]> git.ipfire.org Git - thirdparty/squid.git/blob - src/whois.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / whois.cc
1 /*
2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 /* DEBUG: section 75 WHOIS protocol */
10
11 #include "squid.h"
12 #include "comm.h"
13 #include "comm/Read.h"
14 #include "comm/Write.h"
15 #include "errorpage.h"
16 #include "FwdState.h"
17 #include "HttpReply.h"
18 #include "HttpRequest.h"
19 #include "SquidConfig.h"
20 #include "StatCounters.h"
21 #include "Store.h"
22 #include "tools.h"
23
24 #include <cerrno>
25
26 #define WHOIS_PORT 43
27
28 class WhoisState
29 {
30 CBDATA_CLASS(WhoisState);
31
32 public:
33 void readReply(const Comm::ConnectionPointer &, char *aBuffer, size_t aBufferLength, Comm::Flag flag, int xerrno);
34 void setReplyToOK(StoreEntry *sentry);
35 StoreEntry *entry;
36 HttpRequest::Pointer request;
37 FwdState::Pointer fwd;
38 char buf[BUFSIZ+1]; /* readReply adds terminating NULL */
39 bool dataWritten;
40 };
41
42 CBDATA_CLASS_INIT(WhoisState);
43
44 static CLCB whoisClose;
45 static CTCB whoisTimeout;
46 static IOCB whoisReadReply;
47
48 /* PUBLIC */
49
50 static void
51 whoisWriteComplete(const Comm::ConnectionPointer &, char *buf, size_t size, Comm::Flag flag, int xerrno, void *data)
52 {
53 xfree(buf);
54 }
55
56 void
57 whoisStart(FwdState * fwd)
58 {
59 char *buf;
60 size_t l;
61 WhoisState *p = new WhoisState;
62 p->request = fwd->request;
63 p->entry = fwd->entry;
64 p->fwd = fwd;
65 p->dataWritten = false;
66
67 p->entry->lock("whoisStart");
68 comm_add_close_handler(fwd->serverConnection()->fd, whoisClose, p);
69
70 l = p->request->urlpath.size() + 3;
71
72 buf = (char *)xmalloc(l);
73
74 String str_print=p->request->urlpath.substr(1,p->request->urlpath.size());
75 snprintf(buf, l, SQUIDSTRINGPH"\r\n", SQUIDSTRINGPRINT(str_print));
76
77 AsyncCall::Pointer writeCall = commCbCall(5,5, "whoisWriteComplete",
78 CommIoCbPtrFun(whoisWriteComplete, p));
79 Comm::Write(fwd->serverConnection(), buf, strlen(buf), writeCall, NULL);
80 AsyncCall::Pointer readCall = commCbCall(5,4, "whoisReadReply",
81 CommIoCbPtrFun(whoisReadReply, p));
82 comm_read(fwd->serverConnection(), p->buf, BUFSIZ, readCall);
83 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "whoisTimeout",
84 CommTimeoutCbPtrFun(whoisTimeout, p));
85 commSetConnTimeout(fwd->serverConnection(), Config.Timeout.read, timeoutCall);
86 }
87
88 /* PRIVATE */
89
90 static void
91 whoisTimeout(const CommTimeoutCbParams &io)
92 {
93 WhoisState *p = static_cast<WhoisState *>(io.data);
94 debugs(75, 3, HERE << io.conn << ", URL " << p->entry->url());
95 io.conn->close();
96 }
97
98 static void
99 whoisReadReply(const Comm::ConnectionPointer &conn, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
100 {
101 WhoisState *p = (WhoisState *)data;
102 p->readReply(conn, buf, len, flag, xerrno);
103 }
104
105 void
106 WhoisState::setReplyToOK(StoreEntry *sentry)
107 {
108 HttpReply *reply = new HttpReply;
109 sentry->buffer();
110 reply->setHeaders(Http::scOkay, "Gatewaying", "text/plain", -1, -1, -2);
111 sentry->replaceHttpReply(reply);
112 }
113
114 void
115 WhoisState::readReply(const Comm::ConnectionPointer &conn, char *aBuffer, size_t aBufferLength, Comm::Flag flag, int xerrno)
116 {
117 /* Bail out early on Comm::ERR_CLOSING - close handlers will tidy up for us */
118 if (flag == Comm::ERR_CLOSING)
119 return;
120
121 aBuffer[aBufferLength] = '\0';
122 debugs(75, 3, HERE << conn << " read " << aBufferLength << " bytes");
123 debugs(75, 5, "{" << aBuffer << "}");
124
125 if (flag != Comm::OK) {
126 debugs(50, 2, HERE << conn << ": read failure: " << xstrerror() << ".");
127
128 if (ignoreErrno(errno)) {
129 AsyncCall::Pointer call = commCbCall(5,4, "whoisReadReply",
130 CommIoCbPtrFun(whoisReadReply, this));
131 comm_read(conn, aBuffer, BUFSIZ, call);
132 } else {
133 ErrorState *err = new ErrorState(ERR_READ_ERROR, Http::scInternalServerError, fwd->request);
134 err->xerrno = xerrno;
135 fwd->fail(err);
136 conn->close();
137 }
138 return;
139 }
140
141 if (aBufferLength > 0) {
142 if (!dataWritten)
143 setReplyToOK(entry);
144
145 kb_incr(&(statCounter.server.all.kbytes_in), aBufferLength);
146 kb_incr(&(statCounter.server.http.kbytes_in), aBufferLength);
147
148 /* No range support, we always grab it all */
149 dataWritten = true;
150 entry->append(aBuffer, aBufferLength);
151 entry->flush();
152
153 AsyncCall::Pointer call = commCbCall(5,4, "whoisReadReply",
154 CommIoCbPtrFun(whoisReadReply, this));
155 comm_read(conn, aBuffer, BUFSIZ, call);
156 return;
157 }
158
159 /* no bytes read. stop reading */
160 entry->timestampsSet();
161 entry->flush();
162
163 entry->makePublic();
164
165 fwd->complete();
166 debugs(75, 3, "whoisReadReply: Done: " << entry->url());
167 conn->close();
168 }
169
170 static void
171 whoisClose(const CommCloseCbParams &params)
172 {
173 WhoisState *p = (WhoisState *)params.data;
174 debugs(75, 3, "whoisClose: FD " << params.fd);
175 p->entry->unlock("whoisClose");
176 delete p;
177 }
178