]>
Commit | Line | Data |
---|---|---|
af6691cc | 1 | /* |
b8ae064d | 2 | * Copyright (C) 1996-2023 The Squid Software Foundation and contributors |
e25c139f | 3 | * |
bbc27441 AJ |
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. | |
af6691cc | 7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 75 WHOIS protocol */ |
10 | ||
582c2af2 FC |
11 | #include "squid.h" |
12 | #include "comm.h" | |
7e66d5e2 | 13 | #include "comm/Read.h" |
ec41b64c | 14 | #include "comm/Write.h" |
aa839030 | 15 | #include "errorpage.h" |
eb13c21e | 16 | #include "FwdState.h" |
528b2c61 | 17 | #include "HttpReply.h" |
924f73bc | 18 | #include "HttpRequest.h" |
4d5904f7 | 19 | #include "SquidConfig.h" |
e4f1fdae | 20 | #include "StatCounters.h" |
582c2af2 | 21 | #include "Store.h" |
4e540555 | 22 | #include "tools.h" |
8b082ed9 | 23 | #include "whois.h" |
af6691cc | 24 | |
1a30fdf5 | 25 | #include <cerrno> |
21d845b1 | 26 | |
62e76326 | 27 | class WhoisState |
28 | { | |
5c2f68b7 AJ |
29 | CBDATA_CLASS(WhoisState); |
30 | ||
528b2c61 | 31 | public: |
c8407295 | 32 | void readReply(const Comm::ConnectionPointer &, char *aBuffer, size_t aBufferLength, Comm::Flag flag, int xerrno); |
e053c141 | 33 | void setReplyToOK(StoreEntry *sentry); |
af6691cc | 34 | StoreEntry *entry; |
c31bb519 | 35 | HttpRequest::Pointer request; |
b6b6f466 | 36 | FwdState::Pointer fwd; |
f53969cc | 37 | char buf[BUFSIZ+1]; /* readReply adds terminating NULL */ |
528b2c61 | 38 | bool dataWritten; |
39 | }; | |
af6691cc | 40 | |
c31bb519 AJ |
41 | CBDATA_CLASS_INIT(WhoisState); |
42 | ||
575d05c4 | 43 | static CLCB whoisClose; |
8d77a37c | 44 | static CTCB whoisTimeout; |
c4b7a5a9 | 45 | static IOCB whoisReadReply; |
af6691cc | 46 | |
47 | /* PUBLIC */ | |
48 | ||
e6546865 | 49 | static void |
ced8def3 | 50 | whoisWriteComplete(const Comm::ConnectionPointer &, char *buf, size_t, Comm::Flag, int, void *) |
e6546865 | 51 | { |
62e76326 | 52 | xfree(buf); |
e6546865 | 53 | } |
54 | ||
af6691cc | 55 | void |
db1cd23c | 56 | whoisStart(FwdState * fwd) |
af6691cc | 57 | { |
c31bb519 | 58 | WhoisState *p = new WhoisState; |
db1cd23c | 59 | p->request = fwd->request; |
60 | p->entry = fwd->entry; | |
61 | p->fwd = fwd; | |
5bac8e33 | 62 | p->dataWritten = false; |
34266cde | 63 | |
1bfe9ade | 64 | p->entry->lock("whoisStart"); |
e0d28505 | 65 | comm_add_close_handler(fwd->serverConnection()->fd, whoisClose, p); |
34266cde | 66 | |
51b5dcf5 AJ |
67 | size_t l = p->request->url.path().length() + 3; |
68 | char *buf = (char *)xmalloc(l); | |
34266cde | 69 | |
51b5dcf5 AJ |
70 | const SBuf str_print = p->request->url.path().substr(1); |
71 | snprintf(buf, l, SQUIDSBUFPH "\r\n", SQUIDSBUFPRINT(str_print)); | |
34266cde | 72 | |
abd8f140 | 73 | AsyncCall::Pointer writeCall = commCbCall(5,5, "whoisWriteComplete", |
dc49061a | 74 | CommIoCbPtrFun(whoisWriteComplete, p)); |
aee3523a | 75 | Comm::Write(fwd->serverConnection(), buf, strlen(buf), writeCall, nullptr); |
abd8f140 | 76 | AsyncCall::Pointer readCall = commCbCall(5,4, "whoisReadReply", |
dc49061a | 77 | CommIoCbPtrFun(whoisReadReply, p)); |
abd8f140 | 78 | comm_read(fwd->serverConnection(), p->buf, BUFSIZ, readCall); |
8d77a37c | 79 | AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "whoisTimeout", |
dc49061a | 80 | CommTimeoutCbPtrFun(whoisTimeout, p)); |
8d77a37c | 81 | commSetConnTimeout(fwd->serverConnection(), Config.Timeout.read, timeoutCall); |
af6691cc | 82 | } |
83 | ||
84 | /* PRIVATE */ | |
85 | ||
86 | static void | |
8d77a37c | 87 | whoisTimeout(const CommTimeoutCbParams &io) |
af6691cc | 88 | { |
8d77a37c | 89 | WhoisState *p = static_cast<WhoisState *>(io.data); |
bf95c10a | 90 | debugs(75, 3, io.conn << ", URL " << p->entry->url()); |
8d77a37c | 91 | io.conn->close(); |
af6691cc | 92 | } |
93 | ||
94 | static void | |
c8407295 | 95 | whoisReadReply(const Comm::ConnectionPointer &conn, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data) |
af6691cc | 96 | { |
e6ccf245 | 97 | WhoisState *p = (WhoisState *)data; |
e0d28505 | 98 | p->readReply(conn, buf, len, flag, xerrno); |
528b2c61 | 99 | } |
100 | ||
101 | void | |
e053c141 | 102 | WhoisState::setReplyToOK(StoreEntry *sentry) |
528b2c61 | 103 | { |
06a5ae20 | 104 | HttpReply *reply = new HttpReply; |
e053c141 | 105 | sentry->buffer(); |
955394ce | 106 | reply->setHeaders(Http::scOkay, "Gatewaying", "text/plain", -1, -1, -2); |
63df1d28 | 107 | reply->sources |= Http::Message::srcWhois; |
e053c141 | 108 | sentry->replaceHttpReply(reply); |
528b2c61 | 109 | } |
110 | ||
111 | void | |
c8407295 | 112 | WhoisState::readReply(const Comm::ConnectionPointer &conn, char *aBuffer, size_t aBufferLength, Comm::Flag flag, int xerrno) |
528b2c61 | 113 | { |
c8407295 AJ |
114 | /* Bail out early on Comm::ERR_CLOSING - close handlers will tidy up for us */ |
115 | if (flag == Comm::ERR_CLOSING) | |
c4b7a5a9 | 116 | return; |
c4b7a5a9 | 117 | |
e053c141 | 118 | aBuffer[aBufferLength] = '\0'; |
bf95c10a | 119 | debugs(75, 3, conn << " read " << aBufferLength << " bytes"); |
e053c141 | 120 | debugs(75, 5, "{" << aBuffer << "}"); |
62e76326 | 121 | |
d2b604ec AR |
122 | // TODO: Honor delay pools. |
123 | ||
124 | // XXX: Update statCounter before bailing | |
125 | if (!entry->isAccepting()) { | |
126 | debugs(52, 3, "terminating due to bad " << *entry); | |
127 | // TODO: Do not abuse connection for triggering cleanup. | |
128 | conn->close(); | |
129 | return; | |
130 | } | |
131 | ||
c8407295 | 132 | if (flag != Comm::OK) { |
b69e9ffa | 133 | debugs(50, 2, conn << ": read failure: " << xstrerr(xerrno)); |
62e76326 | 134 | |
b69e9ffa | 135 | if (ignoreErrno(xerrno)) { |
1b76e6c1 AJ |
136 | AsyncCall::Pointer call = commCbCall(5,4, "whoisReadReply", |
137 | CommIoCbPtrFun(whoisReadReply, this)); | |
138 | comm_read(conn, aBuffer, BUFSIZ, call); | |
6cae5db1 | 139 | } else { |
7e6eabbc | 140 | const auto err = new ErrorState(ERR_READ_ERROR, Http::scInternalServerError, fwd->request, fwd->al); |
129fe2a1 | 141 | err->xerrno = xerrno; |
b6b6f466 | 142 | fwd->fail(err); |
80463bb4 | 143 | conn->close(); |
62e76326 | 144 | } |
58c0b17d AJ |
145 | return; |
146 | } | |
62e76326 | 147 | |
58c0b17d AJ |
148 | if (aBufferLength > 0) { |
149 | if (!dataWritten) | |
150 | setReplyToOK(entry); | |
62e76326 | 151 | |
a0864754 AJ |
152 | statCounter.server.all.kbytes_in += aBufferLength; |
153 | statCounter.server.http.kbytes_in += aBufferLength; | |
62e76326 | 154 | |
58c0b17d AJ |
155 | /* No range support, we always grab it all */ |
156 | dataWritten = true; | |
157 | entry->append(aBuffer, aBufferLength); | |
158 | entry->flush(); | |
62e76326 | 159 | |
abd8f140 AJ |
160 | AsyncCall::Pointer call = commCbCall(5,4, "whoisReadReply", |
161 | CommIoCbPtrFun(whoisReadReply, this)); | |
162 | comm_read(conn, aBuffer, BUFSIZ, call); | |
58c0b17d | 163 | return; |
abd8f140 | 164 | } |
62e76326 | 165 | |
58c0b17d AJ |
166 | /* no bytes read. stop reading */ |
167 | entry->timestampsSet(); | |
168 | entry->flush(); | |
169 | ||
4310f8b0 EB |
170 | if (!entry->makePublic()) |
171 | entry->makePrivate(true); | |
58c0b17d | 172 | |
ba3fe8d9 EB |
173 | if (dataWritten) // treat zero-length responses as incomplete |
174 | fwd->markStoredReplyAsWhole("whois received/stored the entire response"); | |
21f90159 EB |
175 | else |
176 | fwd->fail(new ErrorState(ERR_ZERO_SIZE_OBJECT, Http::scBadGateway, fwd->request, fwd->al)); | |
ba3fe8d9 | 177 | |
58c0b17d AJ |
178 | fwd->complete(); |
179 | debugs(75, 3, "whoisReadReply: Done: " << entry->url()); | |
1b76e6c1 | 180 | conn->close(); |
af6691cc | 181 | } |
182 | ||
183 | static void | |
575d05c4 | 184 | whoisClose(const CommCloseCbParams ¶ms) |
af6691cc | 185 | { |
575d05c4 AJ |
186 | WhoisState *p = (WhoisState *)params.data; |
187 | debugs(75, 3, "whoisClose: FD " << params.fd); | |
2b6b1bcb | 188 | // We do not own a Connection. Assume that FwdState is also monitoring. |
1bfe9ade | 189 | p->entry->unlock("whoisClose"); |
c31bb519 | 190 | delete p; |
af6691cc | 191 | } |
f53969cc | 192 |