/* * Copyright (C) 1996-2017 The Squid Software Foundation and contributors * * Squid software is distributed under GPLv2+ license and includes * contributions from numerous individuals and organizations. * Please see the COPYING and CONTRIBUTORS files for details. */ /* DEBUG: section 75 WHOIS protocol */ #include "squid.h" #include "comm.h" #include "comm/Read.h" #include "comm/Write.h" #include "errorpage.h" #include "FwdState.h" #include "HttpReply.h" #include "HttpRequest.h" #include "SquidConfig.h" #include "StatCounters.h" #include "Store.h" #include "tools.h" #include #define WHOIS_PORT 43 class WhoisState { public: void readReply(const Comm::ConnectionPointer &, char *aBuffer, size_t aBufferLength, Comm::Flag flag, int xerrno); void setReplyToOK(StoreEntry *sentry); StoreEntry *entry; HttpRequest::Pointer request; FwdState::Pointer fwd; char buf[BUFSIZ+1]; /* readReply adds terminating NULL */ bool dataWritten; private: CBDATA_CLASS2(WhoisState); }; CBDATA_CLASS_INIT(WhoisState); static CLCB whoisClose; static CTCB whoisTimeout; static IOCB whoisReadReply; /* PUBLIC */ static void whoisWriteComplete(const Comm::ConnectionPointer &, char *buf, size_t size, Comm::Flag flag, int xerrno, void *data) { xfree(buf); } void whoisStart(FwdState * fwd) { char *buf; size_t l; WhoisState *p = new WhoisState; p->request = fwd->request; p->entry = fwd->entry; p->fwd = fwd; p->dataWritten = false; p->entry->lock("whoisStart"); comm_add_close_handler(fwd->serverConnection()->fd, whoisClose, p); l = p->request->urlpath.size() + 3; buf = (char *)xmalloc(l); String str_print=p->request->urlpath.substr(1,p->request->urlpath.size()); snprintf(buf, l, SQUIDSTRINGPH"\r\n", SQUIDSTRINGPRINT(str_print)); AsyncCall::Pointer writeCall = commCbCall(5,5, "whoisWriteComplete", CommIoCbPtrFun(whoisWriteComplete, p)); Comm::Write(fwd->serverConnection(), buf, strlen(buf), writeCall, NULL); AsyncCall::Pointer readCall = commCbCall(5,4, "whoisReadReply", CommIoCbPtrFun(whoisReadReply, p)); comm_read(fwd->serverConnection(), p->buf, BUFSIZ, readCall); AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "whoisTimeout", CommTimeoutCbPtrFun(whoisTimeout, p)); commSetConnTimeout(fwd->serverConnection(), Config.Timeout.read, timeoutCall); } /* PRIVATE */ static void whoisTimeout(const CommTimeoutCbParams &io) { WhoisState *p = static_cast(io.data); debugs(75, 3, HERE << io.conn << ", URL " << p->entry->url()); io.conn->close(); } static void whoisReadReply(const Comm::ConnectionPointer &conn, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data) { WhoisState *p = (WhoisState *)data; p->readReply(conn, buf, len, flag, xerrno); } void WhoisState::setReplyToOK(StoreEntry *sentry) { HttpReply *reply = new HttpReply; sentry->buffer(); reply->setHeaders(Http::scOkay, "Gatewaying", "text/plain", -1, -1, -2); sentry->replaceHttpReply(reply); } void WhoisState::readReply(const Comm::ConnectionPointer &conn, char *aBuffer, size_t aBufferLength, Comm::Flag flag, int xerrno) { /* Bail out early on Comm::ERR_CLOSING - close handlers will tidy up for us */ if (flag == Comm::ERR_CLOSING) return; aBuffer[aBufferLength] = '\0'; debugs(75, 3, HERE << conn << " read " << aBufferLength << " bytes"); debugs(75, 5, "{" << aBuffer << "}"); if (flag != Comm::OK) { debugs(50, 2, HERE << conn << ": read failure: " << xstrerror() << "."); if (ignoreErrno(errno)) { AsyncCall::Pointer call = commCbCall(5,4, "whoisReadReply", CommIoCbPtrFun(whoisReadReply, this)); comm_read(conn, aBuffer, BUFSIZ, call); } else { ErrorState *err = new ErrorState(ERR_READ_ERROR, Http::scInternalServerError, fwd->request); err->xerrno = xerrno; fwd->fail(err); conn->close(); } return; } if (aBufferLength > 0) { if (!dataWritten) setReplyToOK(entry); kb_incr(&(statCounter.server.all.kbytes_in), aBufferLength); kb_incr(&(statCounter.server.http.kbytes_in), aBufferLength); /* No range support, we always grab it all */ dataWritten = true; entry->append(aBuffer, aBufferLength); entry->flush(); AsyncCall::Pointer call = commCbCall(5,4, "whoisReadReply", CommIoCbPtrFun(whoisReadReply, this)); comm_read(conn, aBuffer, BUFSIZ, call); return; } /* no bytes read. stop reading */ entry->timestampsSet(); entry->flush(); entry->makePublic(); fwd->complete(); debugs(75, 3, "whoisReadReply: Done: " << entry->url()); conn->close(); } static void whoisClose(const CommCloseCbParams ¶ms) { WhoisState *p = (WhoisState *)params.data; debugs(75, 3, "whoisClose: FD " << params.fd); p->entry->unlock("whoisClose"); delete p; }