]> git.ipfire.org Git - thirdparty/squid.git/blame - src/whois.cc
Source Format Enforcement (#1234)
[thirdparty/squid.git] / src / whois.cc
CommitLineData
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 27class WhoisState
28{
5c2f68b7
AJ
29 CBDATA_CLASS(WhoisState);
30
528b2c61 31public:
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
41CBDATA_CLASS_INIT(WhoisState);
42
575d05c4 43static CLCB whoisClose;
8d77a37c 44static CTCB whoisTimeout;
c4b7a5a9 45static IOCB whoisReadReply;
af6691cc 46
47/* PUBLIC */
48
e6546865 49static void
ced8def3 50whoisWriteComplete(const Comm::ConnectionPointer &, char *buf, size_t, Comm::Flag, int, void *)
e6546865 51{
62e76326 52 xfree(buf);
e6546865 53}
54
af6691cc 55void
db1cd23c 56whoisStart(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
86static void
8d77a37c 87whoisTimeout(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
94static void
c8407295 95whoisReadReply(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
101void
e053c141 102WhoisState::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
111void
c8407295 112WhoisState::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");
175
58c0b17d
AJ
176 fwd->complete();
177 debugs(75, 3, "whoisReadReply: Done: " << entry->url());
1b76e6c1 178 conn->close();
af6691cc 179}
180
181static void
575d05c4 182whoisClose(const CommCloseCbParams &params)
af6691cc 183{
575d05c4
AJ
184 WhoisState *p = (WhoisState *)params.data;
185 debugs(75, 3, "whoisClose: FD " << params.fd);
2b6b1bcb 186 // We do not own a Connection. Assume that FwdState is also monitoring.
1bfe9ade 187 p->entry->unlock("whoisClose");
c31bb519 188 delete p;
af6691cc 189}
f53969cc 190