]> git.ipfire.org Git - thirdparty/squid.git/blob - src/whois.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / whois.cc
1 /*
2 * Copyright (C) 1996-2017 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, Comm::Flag, int, void *)
52 {
53 xfree(buf);
54 }
55
56 void
57 whoisStart(FwdState * fwd)
58 {
59 WhoisState *p = new WhoisState;
60 p->request = fwd->request;
61 p->entry = fwd->entry;
62 p->fwd = fwd;
63 p->dataWritten = false;
64
65 p->entry->lock("whoisStart");
66 comm_add_close_handler(fwd->serverConnection()->fd, whoisClose, p);
67
68 size_t l = p->request->url.path().length() + 3;
69 char *buf = (char *)xmalloc(l);
70
71 const SBuf str_print = p->request->url.path().substr(1);
72 snprintf(buf, l, SQUIDSBUFPH "\r\n", SQUIDSBUFPRINT(str_print));
73
74 AsyncCall::Pointer writeCall = commCbCall(5,5, "whoisWriteComplete",
75 CommIoCbPtrFun(whoisWriteComplete, p));
76 Comm::Write(fwd->serverConnection(), buf, strlen(buf), writeCall, NULL);
77 AsyncCall::Pointer readCall = commCbCall(5,4, "whoisReadReply",
78 CommIoCbPtrFun(whoisReadReply, p));
79 comm_read(fwd->serverConnection(), p->buf, BUFSIZ, readCall);
80 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "whoisTimeout",
81 CommTimeoutCbPtrFun(whoisTimeout, p));
82 commSetConnTimeout(fwd->serverConnection(), Config.Timeout.read, timeoutCall);
83 }
84
85 /* PRIVATE */
86
87 static void
88 whoisTimeout(const CommTimeoutCbParams &io)
89 {
90 WhoisState *p = static_cast<WhoisState *>(io.data);
91 debugs(75, 3, HERE << io.conn << ", URL " << p->entry->url());
92 io.conn->close();
93 }
94
95 static void
96 whoisReadReply(const Comm::ConnectionPointer &conn, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
97 {
98 WhoisState *p = (WhoisState *)data;
99 p->readReply(conn, buf, len, flag, xerrno);
100 }
101
102 void
103 WhoisState::setReplyToOK(StoreEntry *sentry)
104 {
105 HttpReply *reply = new HttpReply;
106 sentry->buffer();
107 reply->setHeaders(Http::scOkay, "Gatewaying", "text/plain", -1, -1, -2);
108 reply->sources |= HttpMsg::srcWhois;
109 sentry->replaceHttpReply(reply);
110 }
111
112 void
113 WhoisState::readReply(const Comm::ConnectionPointer &conn, char *aBuffer, size_t aBufferLength, Comm::Flag flag, int xerrno)
114 {
115 /* Bail out early on Comm::ERR_CLOSING - close handlers will tidy up for us */
116 if (flag == Comm::ERR_CLOSING)
117 return;
118
119 aBuffer[aBufferLength] = '\0';
120 debugs(75, 3, HERE << conn << " read " << aBufferLength << " bytes");
121 debugs(75, 5, "{" << aBuffer << "}");
122
123 if (flag != Comm::OK) {
124 debugs(50, 2, conn << ": read failure: " << xstrerr(xerrno));
125
126 if (ignoreErrno(xerrno)) {
127 AsyncCall::Pointer call = commCbCall(5,4, "whoisReadReply",
128 CommIoCbPtrFun(whoisReadReply, this));
129 comm_read(conn, aBuffer, BUFSIZ, call);
130 } else {
131 ErrorState *err = new ErrorState(ERR_READ_ERROR, Http::scInternalServerError, fwd->request);
132 err->xerrno = xerrno;
133 fwd->fail(err);
134 conn->close();
135 }
136 return;
137 }
138
139 if (aBufferLength > 0) {
140 if (!dataWritten)
141 setReplyToOK(entry);
142
143 statCounter.server.all.kbytes_in += aBufferLength;
144 statCounter.server.http.kbytes_in += aBufferLength;
145
146 /* No range support, we always grab it all */
147 dataWritten = true;
148 entry->append(aBuffer, aBufferLength);
149 entry->flush();
150
151 AsyncCall::Pointer call = commCbCall(5,4, "whoisReadReply",
152 CommIoCbPtrFun(whoisReadReply, this));
153 comm_read(conn, aBuffer, BUFSIZ, call);
154 return;
155 }
156
157 /* no bytes read. stop reading */
158 entry->timestampsSet();
159 entry->flush();
160
161 entry->makePublic();
162
163 fwd->complete();
164 debugs(75, 3, "whoisReadReply: Done: " << entry->url());
165 conn->close();
166 }
167
168 static void
169 whoisClose(const CommCloseCbParams &params)
170 {
171 WhoisState *p = (WhoisState *)params.data;
172 debugs(75, 3, "whoisClose: FD " << params.fd);
173 p->entry->unlock("whoisClose");
174 delete p;
175 }
176