Delete server-side deleteThis() This patch finishes the conversion of ServerStateData into AsyncJob by properly implementing the doneAll() method and by removing calls to deleteThis() or replacing with mustStop() calls as appropriate. The Adaptation::AccessCheck modified to schedule an AsyncJobCall when access check finishes. The ServerStateData and ClientHttpRequest classes modified to work with the new Adaptation::AccessCheck. This is a Measurement Factory project === modified file 'src/ClientRequestContext.h' --- src/ClientRequestContext.h 2011-08-14 23:34:26 +0000 +++ src/ClientRequestContext.h 2011-10-11 20:06:39 +0000 @@ -21,41 +21,40 @@ void *operator new(size_t); void operator delete(void *); ClientRequestContext(ClientHttpRequest *); ~ClientRequestContext(); bool httpStateIsValid(); void hostHeaderVerify(); void hostHeaderIpVerify(const ipcache_addrs* ia, const DnsLookupDetails &dns); void hostHeaderVerifyFailed(const char *A, const char *B); void clientAccessCheck(); void clientAccessCheck2(); void clientAccessCheckDone(const allow_t &answer); void clientRedirectStart(); void clientRedirectDone(char *result); void checkNoCache(); void checkNoCacheDone(const allow_t &answer); #if USE_ADAPTATION void adaptationAccessCheck(); - void adaptationAclCheckDone(Adaptation::ServiceGroupPointer g); #endif #if USE_SSL /** * Initiates and start the acl checklist to check if the a CONNECT * request must be bumped. \retval true if the acl check scheduled, false if no ssl-bump required */ bool sslBumpAccessCheck(); /// The callback function for ssl-bump access check list void sslBumpAccessCheckDone(bool doSslBump); #endif ClientHttpRequest *http; ACLChecklist *acl_checklist; /* need ptr back so we can unreg if needed */ int redirect_state; bool host_header_verify_done; bool http_access_done; bool adapted_http_access_done; #if USE_ADAPTATION === modified file 'src/Server.cc' --- src/Server.cc 2011-08-10 15:54:51 +0000 +++ src/Server.cc 2011-10-13 19:25:44 +0000 @@ -194,63 +194,51 @@ if (responseBodyBuffer != NULL) return; serverComplete2(); } void ServerStateData::serverComplete2() { debugs(11,5,HERE << "serverComplete2 " << this); #if USE_ADAPTATION if (virginBodyDestination != NULL) stopProducingFor(virginBodyDestination, true); if (!doneWithAdaptation()) return; #endif completeForwarding(); - quitIfAllDone(); } -// When we are done talking to the primary server, we may be still talking -// to the ICAP service. And vice versa. Here, we quit only if we are done -// talking to both. -void ServerStateData::quitIfAllDone() +bool ServerStateData::doneAll() const { + return doneWithServer() && #if USE_ADAPTATION - if (!doneWithAdaptation()) { - debugs(11,5, HERE << "transaction not done: still talking to ICAP"); - return; - } + doneWithAdaptation() && + Adaptation::Initiator::doneAll() && + BodyProducer::doneAll() && #endif - - if (!doneWithServer()) { - debugs(11,5, HERE << "transaction not done: still talking to server"); - return; - } - - debugs(11,3, HERE << "transaction done"); - - deleteThis("ServerStateData::quitIfAllDone"); + BodyConsumer::doneAll(); } // FTP side overloads this to work around multiple calls to fwd->complete void ServerStateData::completeForwarding() { debugs(11,5, HERE << "completing forwarding for " << fwd); assert(fwd != NULL); fwd->complete(); } // Register to receive request body bool ServerStateData::startRequestBodyFlow() { HttpRequest *r = originalRequest(); assert(r->body_pipe != NULL); requestBodySource = r->body_pipe; if (requestBodySource->setConsumerIfNotLate(this)) { debugs(11,3, HERE << "expecting request body from " << requestBodySource->status()); @@ -749,41 +737,40 @@ stopConsumingFrom(adaptedBodySource); handleAdaptationAborted(); } // common part of noteAdaptationAnswer and handleAdaptedBodyProductionEnded void ServerStateData::handleAdaptationCompleted() { debugs(11,5, HERE << "handleAdaptationCompleted"); cleanAdaptation(); // We stop reading origin response because we have no place to put it and // cannot use it. If some origin servers do not like that or if we want to // reuse more pconns, we can add code to discard unneeded origin responses. if (!doneWithServer()) { debugs(11,3, HERE << "closing origin conn due to ICAP completion"); closeServer(); } completeForwarding(); - quitIfAllDone(); } // common part of noteAdaptation*Aborted and noteBodyConsumerAborted methods void ServerStateData::handleAdaptationAborted(bool bypassable) { debugs(11,5, HERE << "handleAdaptationAborted; bypassable: " << bypassable << ", entry empty: " << entry->isEmpty()); if (abortOnBadEntry("entry went bad while ICAP aborted")) return; // TODO: bypass if possible if (entry->isEmpty()) { debugs(11,9, HERE << "creating ICAP error entry after ICAP failure"); ErrorState *err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, request); err->xerrno = ERR_DETAIL_ICAP_RESPMOD_EARLY; fwd->fail(err); @@ -810,95 +797,88 @@ abortTransaction("late adaptation block"); return; } debugs(11,7, HERE << "creating adaptation block response"); err_type page_id = aclGetDenyInfoPage(&Config.denyInfoList, answer.ruleId.termedBuf(), 1); if (page_id == ERR_NONE) page_id = ERR_ACCESS_DENIED; ErrorState *err = errorCon(page_id, HTTP_FORBIDDEN, request); err->xerrno = ERR_DETAIL_RESPMOD_BLOCK_EARLY; fwd->fail(err); fwd->dontRetry(true); abortTransaction("timely adaptation block"); } void -ServerStateData::adaptationAclCheckDone(Adaptation::ServiceGroupPointer group) +ServerStateData::noteAdaptationAclCheckDone(Adaptation::ServiceGroupPointer group) { adaptationAccessCheckPending = false; if (abortOnBadEntry("entry went bad while waiting for ICAP ACL check")) return; // TODO: Should nonICAP and postICAP path check this on the server-side? // That check now only happens on client-side, in processReplyAccess(). if (virginReply()->expectedBodyTooLarge(*request)) { sendBodyIsTooLargeError(); return; } // TODO: Should we check receivedBodyTooLarge on the server-side as well? if (!group) { debugs(11,3, HERE << "no adapation needed"); setFinalReply(virginReply()); processReplyBody(); return; } startAdaptation(group, originalRequest()); processReplyBody(); } - -void -ServerStateData::adaptationAclCheckDoneWrapper(Adaptation::ServiceGroupPointer group, void *data) -{ - ServerStateData *state = (ServerStateData *)data; - state->adaptationAclCheckDone(group); -} #endif void ServerStateData::sendBodyIsTooLargeError() { ErrorState *err = errorCon(ERR_TOO_BIG, HTTP_FORBIDDEN, request); err->xerrno = errno; fwd->fail(err); fwd->dontRetry(true); abortTransaction("Virgin body too large."); } // TODO: when HttpStateData sends all errors to ICAP, // we should be able to move this at the end of setVirginReply(). void ServerStateData::adaptOrFinalizeReply() { #if USE_ADAPTATION // TODO: merge with client side and return void to hide the on/off logic? // The callback can be called with a NULL service if adaptation is off. adaptationAccessCheckPending = Adaptation::AccessCheck::Start( Adaptation::methodRespmod, Adaptation::pointPreCache, - originalRequest(), virginReply(), adaptationAclCheckDoneWrapper, this); + originalRequest(), virginReply(), this); debugs(11,5, HERE << "adaptationAccessCheckPending=" << adaptationAccessCheckPending); if (adaptationAccessCheckPending) return; #endif setFinalReply(virginReply()); } /// initializes bodyBytesRead stats if needed and applies delta void ServerStateData::adjustBodyBytesRead(const int64_t delta) { int64_t &bodyBytesRead = originalRequest()->hier.bodyBytesRead; // if we got here, do not log a dash even if we got nothing from the server if (bodyBytesRead < 0) bodyBytesRead = 0; bodyBytesRead += delta; // supports negative and zero deltas === modified file 'src/Server.h' --- src/Server.h 2011-05-24 10:44:39 +0000 +++ src/Server.h 2011-10-12 19:14:16 +0000 @@ -70,63 +70,54 @@ /// \return primary or "request data connection" virtual const Comm::ConnectionPointer & dataConnection() const = 0; // BodyConsumer: consume request body or adapted response body. // The implementation just calls the corresponding HTTP or ICAP handle*() // method, depending on the pipe. virtual void noteMoreBodyDataAvailable(BodyPipe::Pointer); virtual void noteBodyProductionEnded(BodyPipe::Pointer); virtual void noteBodyProducerAborted(BodyPipe::Pointer); /// read response data from the network virtual void maybeReadVirginBody() = 0; /// abnormal transaction termination; reason is for debugging only virtual void abortTransaction(const char *reason) = 0; /// a hack to reach HttpStateData::orignal_request virtual HttpRequest *originalRequest(); #if USE_ADAPTATION - void adaptationAclCheckDone(Adaptation::ServiceGroupPointer group); - static void adaptationAclCheckDoneWrapper(Adaptation::ServiceGroupPointer group, void *data); - - // ICAPInitiator: start an ICAP transaction and receive adapted headers. + // Adaptation::Initiator API: start an ICAP transaction and receive adapted headers. virtual void noteAdaptationAnswer(const Adaptation::Answer &answer); + virtual void noteAdaptationAclCheckDone(Adaptation::ServiceGroupPointer group); // BodyProducer: provide virgin response body to ICAP. virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer ); virtual void noteBodyConsumerAborted(BodyPipe::Pointer ); #endif virtual bool getMoreRequestBody(MemBuf &buf); virtual void processReplyBody() = 0; //AsyncJob virtual methods virtual void swanSong(); - virtual bool doneAll() const { - return -#if USE_ADAPTATION - Adaptation::Initiator::doneAll() && - BodyProducer::doneAll() && -#endif - BodyConsumer::doneAll() && false; - } + virtual bool doneAll() const; public: // should be protected void serverComplete(); /**< call when no server communication is expected */ private: void serverComplete2(); /**< Continuation of serverComplete */ bool completed; /**< serverComplete() has been called */ protected: // kids customize these virtual void haveParsedReplyHeaders(); /**< called when got final headers */ virtual void completeForwarding(); /**< default calls fwd->complete() */ // BodyConsumer for HTTP: consume request body. bool startRequestBodyFlow(); void handleMoreRequestBodyAvailable(); void handleRequestBodyProductionEnded(); virtual void handleRequestBodyProducerAborted() = 0; // sending of the request body to the server @@ -181,29 +172,28 @@ public: // should not be StoreEntry *entry; FwdState::Pointer fwd; HttpRequest *request; protected: BodyPipe::Pointer requestBodySource; /**< to consume request body */ AsyncCall::Pointer requestSender; /**< set if we are expecting Comm::Write to call us back */ #if USE_ADAPTATION BodyPipe::Pointer virginBodyDestination; /**< to provide virgin response body */ CbcPointer adaptedHeadSource; /**< to get adapted response headers */ BodyPipe::Pointer adaptedBodySource; /**< to consume adated response body */ bool adaptationAccessCheckPending; bool startedAdaptation; #endif bool receivedWholeRequestBody; ///< handleRequestBodyProductionEnded called private: - void quitIfAllDone(); /**< successful termination */ void sendBodyIsTooLargeError(); void maybePurgeOthers(); HttpReply *theVirginReply; /**< reply received from the origin server */ HttpReply *theFinalReply; /**< adapted reply from ICAP or virgin reply */ }; #endif /* SQUID_SERVER_H */ === modified file 'src/adaptation/AccessCheck.cc' --- src/adaptation/AccessCheck.cc 2011-08-25 10:08:49 +0000 +++ src/adaptation/AccessCheck.cc 2011-10-12 19:06:05 +0000 @@ -1,81 +1,78 @@ #include "squid.h" #include "structs.h" #include "ConfigParser.h" #include "HttpRequest.h" #include "HttpReply.h" #include "acl/FilledChecklist.h" +#include "adaptation/Initiator.h" #include "adaptation/Service.h" #include "adaptation/ServiceGroups.h" #include "adaptation/AccessRule.h" #include "adaptation/Config.h" #include "adaptation/AccessCheck.h" #include "base/TextException.h" /** \cond AUTODOCS-IGNORE */ cbdata_type Adaptation::AccessCheck::CBDATA_AccessCheck = CBDATA_UNKNOWN; /** \endcond */ bool Adaptation::AccessCheck::Start(Method method, VectPoint vp, - HttpRequest *req, HttpReply *rep, AccessCheckCallback *cb, void *cbdata) + HttpRequest *req, HttpReply *rep, Adaptation::Initiator *initiator) { if (Config::Enabled) { // the new check will call the callback and delete self, eventually AsyncJob::Start(new AccessCheck( // we do not store so not a CbcPointer - ServiceFilter(method, vp, req, rep), cb, cbdata)); + ServiceFilter(method, vp, req, rep), initiator)); return true; } debugs(83, 3, HERE << "adaptation off, skipping"); return false; } Adaptation::AccessCheck::AccessCheck(const ServiceFilter &aFilter, - AccessCheckCallback *aCallback, - void *aCallbackData): + Adaptation::Initiator *initiator): AsyncJob("AccessCheck"), filter(aFilter), - callback(aCallback), - callback_data(cbdataReference(aCallbackData)), + theInitiator(initiator), acl_checklist(NULL) { #if ICAP_CLIENT Adaptation::Icap::History::Pointer h = filter.request->icapHistory(); if (h != NULL) h->start("ACL"); #endif debugs(93, 5, HERE << "AccessCheck constructed for " << methodStr(filter.method) << " " << vectPointStr(filter.point)); } Adaptation::AccessCheck::~AccessCheck() { #if ICAP_CLIENT Adaptation::Icap::History::Pointer h = filter.request->icapHistory(); if (h != NULL) h->stop("ACL"); #endif - if (callback_data) - cbdataReferenceDone(callback_data); } void Adaptation::AccessCheck::start() { AsyncJob::start(); if (!usedDynamicRules()) check(); } /// returns true if previous services configured dynamic chaining "rules" bool Adaptation::AccessCheck::usedDynamicRules() { Adaptation::History::Pointer ah = filter.request->adaptHistory(); if (!ah) return false; // dynamic rules not enabled or not triggered DynamicGroupCfg services; @@ -168,45 +165,42 @@ if (answer == ACCESS_ALLOWED) { // the rule matched ServiceGroupPointer g = topGroup(); if (g != NULL) { // the corresponding group found callBack(g); Must(done()); return; } } // no match or the group disappeared during reconfiguration candidates.shift(); checkCandidates(); } /// call back with a possibly nil group; the job ends here because all failures /// at this point are fatal to the access check process void Adaptation::AccessCheck::callBack(const ServiceGroupPointer &g) { debugs(93,3, HERE << g); - - void *validated_cbdata; - if (cbdataReferenceValidDone(callback_data, &validated_cbdata)) { - callback(g, validated_cbdata); - } + CallJobHere1(93, 5, theInitiator, Adaptation::Initiator, + noteAdaptationAclCheckDone, g); mustStop("done"); // called back or will never be able to call back } Adaptation::ServiceGroupPointer Adaptation::AccessCheck::topGroup() const { ServiceGroupPointer g; if (candidates.size()) { if (AccessRule *r = FindRule(topCandidate())) { g = FindGroup(r->groupId); debugs(93,5, HERE << "top group for " << r->id << " is " << g); } else { debugs(93,5, HERE << "no rule for " << topCandidate()); } } else { debugs(93,5, HERE << "no candidates"); // should not happen } return g; } === modified file 'src/adaptation/AccessCheck.h' --- src/adaptation/AccessCheck.h 2011-08-10 15:54:51 +0000 +++ src/adaptation/AccessCheck.h 2011-10-12 19:06:52 +0000 @@ -1,57 +1,57 @@ #ifndef SQUID_ADAPTATION__ACCESS_CHECK_H #define SQUID_ADAPTATION__ACCESS_CHECK_H #include "acl/Acl.h" #include "base/AsyncJob.h" #include "adaptation/Elements.h" #include "adaptation/forward.h" +#include "adaptation/Initiator.h" #include "adaptation/ServiceFilter.h" class HttpRequest; class HttpReply; class ACLFilledChecklist; namespace Adaptation { class AccessRule; // checks adaptation_access rules to find a matching adaptation service class AccessCheck: public virtual AsyncJob { public: typedef void AccessCheckCallback(ServiceGroupPointer group, void *data); // use this to start async ACL checks; returns true if started static bool Start(Method method, VectPoint vp, HttpRequest *req, - HttpReply *rep, AccessCheckCallback *cb, void *cbdata); + HttpReply *rep, Adaptation::Initiator *initiator); protected: // use Start to start adaptation checks - AccessCheck(const ServiceFilter &aFilter, AccessCheckCallback *, void *); + AccessCheck(const ServiceFilter &aFilter, Adaptation::Initiator *); ~AccessCheck(); private: const ServiceFilter filter; - AccessCheckCallback *callback; - void *callback_data; + CbcPointer theInitiator; ///< the job which ordered this access check ACLFilledChecklist *acl_checklist; typedef int Candidate; typedef Vector Candidates; Candidates candidates; Candidate topCandidate() const { return *candidates.begin(); } ServiceGroupPointer topGroup() const; // may return nil void callBack(const ServiceGroupPointer &g); bool isCandidate(AccessRule &r); public: void checkCandidates(); static void AccessCheckCallbackWrapper(allow_t, void*); void noteAnswer(allow_t answer); protected: // AsyncJob API virtual void start(); virtual bool doneAll() const { return false; } /// not done until mustStop === modified file 'src/adaptation/Initiator.cc' --- src/adaptation/Initiator.cc 2011-03-11 23:02:23 +0000 +++ src/adaptation/Initiator.cc 2011-10-12 19:10:52 +0000 @@ -1,29 +1,35 @@ /* * DEBUG: section 93 ICAP (RFC 3507) Client */ #include "squid.h" #include "adaptation/Initiate.h" #include "adaptation/Initiator.h" #include "base/AsyncJobCalls.h" +void +Adaptation::Initiator::noteAdaptationAclCheckDone(Adaptation::ServiceGroupPointer group) +{ + Must(false); +} + CbcPointer Adaptation::Initiator::initiateAdaptation(Initiate *x) { CbcPointer i(x); x->initiator(this); Start(x); return i; } void Adaptation::Initiator::clearAdaptation(CbcPointer &x) { x.clear(); } void Adaptation::Initiator::announceInitiatorAbort(CbcPointer &x) { CallJobHere(93, 5, x, Initiate, noteInitiatorAborted); clearAdaptation(x); === modified file 'src/adaptation/Initiator.h' --- src/adaptation/Initiator.h 2011-03-11 23:02:23 +0000 +++ src/adaptation/Initiator.h 2011-10-12 19:09:43 +0000 @@ -6,40 +6,43 @@ #include "base/CbcPointer.h" /* * The ICAP Initiator is an ICAP vectoring point that initates ICAP * transactions. This interface exists to allow ICAP transactions to * signal their initiators that they have the answer from the ICAP server * or that the ICAP query has aborted and there will be no answer. It * is also handy for implementing common initiator actions such as starting * or aborting an ICAP transaction. */ namespace Adaptation { class Initiator: virtual public AsyncJob { public: Initiator(): AsyncJob("Initiator") {} virtual ~Initiator() {} + /// AccessCheck calls this back with a possibly nil service group + /// to signal whether adaptation is needed and where it should start. + virtual void noteAdaptationAclCheckDone(Adaptation::ServiceGroupPointer group); /// called with the initial adaptation decision (adapt, block, error); /// virgin and/or adapted body transmission may continue after this virtual void noteAdaptationAnswer(const Answer &answer) = 0; protected: ///< starts freshly created initiate and returns a safe pointer to it CbcPointer initiateAdaptation(Initiate *x); /// clears the pointer (does not call announceInitiatorAbort) void clearAdaptation(CbcPointer &x); /// inform the transaction about abnormal termination and clear the pointer void announceInitiatorAbort(CbcPointer &x); /// Must(initiated(initiate)) instead of Must(initiate.set()), for clarity bool initiated(const CbcPointer &job) const { return job.set(); } }; } // namespace Adaptation === modified file 'src/client_side_request.cc' --- src/client_side_request.cc 2011-09-04 18:28:39 +0000 +++ src/client_side_request.cc 2011-10-12 09:46:26 +0000 @@ -797,79 +797,67 @@ http->getConn() != NULL && http->getConn()->auth_user_request != NULL ? http->getConn()->auth_user_request : http->request->auth_user_request); #else NULL); #endif http->getConn()->flags.readMore = true; // resume any pipeline reads. node = (clientStreamNode *)http->client_stream.tail->data; clientStreamRead(node, http, node->readBuffer); return; } /* ACCESS_ALLOWED (or auth in grace period ACCESS_AUTH_EXPIRED_OK) continues here ... */ safe_free(http->uri); http->uri = xstrdup(urlCanonical(http->request)); http->doCallouts(); } #if USE_ADAPTATION -static void -adaptationAclCheckDoneWrapper(Adaptation::ServiceGroupPointer g, void *data) -{ - ClientRequestContext *calloutContext = (ClientRequestContext *)data; - - if (!calloutContext->httpStateIsValid()) - return; - - calloutContext->adaptationAclCheckDone(g); -} - void -ClientRequestContext::adaptationAclCheckDone(Adaptation::ServiceGroupPointer g) +ClientHttpRequest::noteAdaptationAclCheckDone(Adaptation::ServiceGroupPointer g) { debugs(93,3,HERE << this << " adaptationAclCheckDone called"); - assert(http); #if ICAP_CLIENT - Adaptation::Icap::History::Pointer ih = http->request->icapHistory(); + Adaptation::Icap::History::Pointer ih = request->icapHistory(); if (ih != NULL) { - if (http->getConn() != NULL) { - ih->rfc931 = http->getConn()->clientConnection->rfc931; + if (getConn() != NULL) { + ih->rfc931 = getConn()->clientConnection->rfc931; #if USE_SSL - assert(http->getConn()->clientConnection != NULL); - ih->ssluser = sslGetUserEmail(fd_table[http->getConn()->clientConnection->fd].ssl); + assert(getConn()->clientConnection != NULL); + ih->ssluser = sslGetUserEmail(fd_table[getConn()->clientConnection->fd].ssl); #endif } - ih->log_uri = http->log_uri; - ih->req_sz = http->req_sz; + ih->log_uri = log_uri; + ih->req_sz = req_sz; } #endif if (!g) { debugs(85,3, HERE << "no adaptation needed"); - http->doCallouts(); + doCallouts(); return; } - http->startAdaptation(g); + startAdaptation(g); } #endif static void clientRedirectAccessCheckDone(allow_t answer, void *data) { ClientRequestContext *context = (ClientRequestContext *)data; ClientHttpRequest *http = context->http; context->acl_checklist = NULL; if (answer == ACCESS_ALLOWED) redirectStart(http, clientRedirectDoneWrapper, context); else context->clientRedirectDone(NULL); } void ClientRequestContext::clientRedirectStart() { @@ -1478,41 +1466,41 @@ // CVE-2009-0801: verify the Host: header is consistent with other known details. if (!calloutContext->host_header_verify_done) { debugs(83, 3, HERE << "Doing calloutContext->hostHeaderVerify()"); calloutContext->host_header_verify_done = true; calloutContext->hostHeaderVerify(); return; } if (!calloutContext->http_access_done) { debugs(83, 3, HERE << "Doing calloutContext->clientAccessCheck()"); calloutContext->http_access_done = true; calloutContext->clientAccessCheck(); return; } #if USE_ADAPTATION if (!calloutContext->adaptation_acl_check_done) { calloutContext->adaptation_acl_check_done = true; if (Adaptation::AccessCheck::Start( Adaptation::methodReqmod, Adaptation::pointPreCache, - request, NULL, adaptationAclCheckDoneWrapper, calloutContext)) + request, NULL, this)) return; // will call callback } #endif if (!calloutContext->redirect_done) { calloutContext->redirect_done = true; assert(calloutContext->redirect_state == REDIRECT_NONE); if (Config.Program.redirect) { debugs(83, 3, HERE << "Doing calloutContext->clientRedirectStart()"); calloutContext->redirect_state = REDIRECT_PENDING; calloutContext->clientRedirectStart(); return; } } if (!calloutContext->adapted_http_access_done) { debugs(83, 3, HERE << "Doing calloutContext->clientAccessCheck2()"); calloutContext->adapted_http_access_done = true; calloutContext->clientAccessCheck2(); === modified file 'src/client_side_request.h' --- src/client_side_request.h 2011-05-13 08:13:01 +0000 +++ src/client_side_request.h 2011-10-12 19:12:09 +0000 @@ -163,40 +163,41 @@ bool sslBumpNeeded() const; /// set the sslBumpNeeded state void sslBumpNeeded(bool isNeeded); void sslBumpStart(); void sslBumpEstablish(comm_err_t errflag); #endif #if USE_ADAPTATION public: void startAdaptation(const Adaptation::ServiceGroupPointer &g); // private but exposed for ClientRequestContext void handleAdaptationFailure(int errDetail, bool bypassable = false); private: // Adaptation::Initiator API virtual void noteAdaptationAnswer(const Adaptation::Answer &answer); void handleAdaptedHeader(HttpMsg *msg); void handleAdaptationBlock(const Adaptation::Answer &answer); + virtual void noteAdaptationAclCheckDone(Adaptation::ServiceGroupPointer group); // BodyConsumer API, called by BodyPipe virtual void noteMoreBodyDataAvailable(BodyPipe::Pointer); virtual void noteBodyProductionEnded(BodyPipe::Pointer); virtual void noteBodyProducerAborted(BodyPipe::Pointer); void endRequestSatisfaction(); private: CbcPointer virginHeadSource; BodyPipe::Pointer adaptedBodySource; bool request_satisfaction_mode; int64_t request_satisfaction_offset; #endif }; /* client http based routines */ SQUIDCEXTERN char *clientConstructTraceEcho(ClientHttpRequest *); === modified file 'src/ftp.cc' --- src/ftp.cc 2011-09-22 15:23:11 +0000 +++ src/ftp.cc 2011-10-12 10:40:37 +0000 @@ -217,41 +217,41 @@ char *last_command; char *last_reply; int replycode; } ctrl; /// FTP data channel info; the channel may be opened/closed a few times struct DataChannel: public FtpChannel { MemBuf *readBuf; char *host; unsigned short port; bool read_pending; } data; struct _ftp_flags flags; private: CBDATA_CLASS(FtpStateData); public: // these should all be private - void start(); + virtual void start(); void loginParser(const char *, int escaped); int restartable(); void appendSuccessHeader(); void hackShortcut(FTPSM * nextState); void failed(err_type, int xerrno); void failedErrorMessage(err_type, int xerrno); void unhack(); void scheduleReadControlReply(int); void handleControlReply(); void readStor(); void parseListing(); MemBuf *htmlifyListEntry(const char *line); void completedListing(void); void dataComplete(); void dataRead(const CommIoCbParams &io); /// ignore timeout on CTRL channel. set read timeout on DATA channel. void switchTimeoutToDataChannel(); /// create a data channel acceptor and start listening. void listenForDataChannel(const Comm::ConnectionPointer &conn, const char *note); @@ -440,41 +440,41 @@ ftpReadEPSV, /* SENT_EPSV_2 */ ftpReadPasv, /* SENT_PASV */ ftpReadCwd, /* SENT_CWD */ ftpReadList, /* SENT_LIST */ ftpReadList, /* SENT_NLST */ ftpReadRest, /* SENT_REST */ ftpReadRetr, /* SENT_RETR */ ftpReadStor, /* SENT_STOR */ ftpReadQuit, /* SENT_QUIT */ ftpReadTransferDone, /* READING_DATA (RETR,LIST,NLST) */ ftpWriteTransferDone, /* WRITING_DATA (STOR) */ ftpReadMkdir /* SENT_MKDIR */ }; /// handler called by Comm when FTP control channel is closed unexpectedly void FtpStateData::ctrlClosed(const CommCloseCbParams &io) { debugs(9, 4, HERE); ctrl.clear(); - deleteThis("FtpStateData::ctrlClosed"); + mustStop("FtpStateData::ctrlClosed"); } /// handler called by Comm when FTP data channel is closed unexpectedly void FtpStateData::dataClosed(const CommCloseCbParams &io) { debugs(9, 4, HERE); if (data.listenConn != NULL) { data.listenConn->close(); data.listenConn = NULL; // NP clear() does the: data.fd = -1; } data.clear(); failed(ERR_FTP_FAILURE, 0); /* failed closes ctrl.conn and frees ftpState */ /* NP: failure recovery may be possible when its only a data.conn failure. * if the ctrl.conn is still fine, we can send ABOR down it and retry. * Just need to watch out for wider Squid states like shutting down or reconfigure. */ @@ -1500,42 +1500,41 @@ } base_href.append("@"); } base_href.append(request->GetHost()); if (request->port != urlDefaultPort(AnyP::PROTO_FTP)) { base_href.append(":"); base_href.append(xitoa(request->port)); } base_href.append(request->urlpath); base_href.append("/"); } /// \ingroup ServerProtocolFTPAPI void ftpStart(FwdState * fwd) { - FtpStateData *ftpState = new FtpStateData(fwd, fwd->serverConnection()); - ftpState->start(); + AsyncJob::Start(new FtpStateData(fwd, fwd->serverConnection())); } void FtpStateData::start() { if (!checkAuth(&request->header)) { /* create appropriate reply */ HttpReply *reply = ftpAuthRequired(request, ftpRealm()); entry->replaceHttpReply(reply); serverComplete(); return; } checkUrlpath(); buildTitleUrl(); debugs(9, 5, HERE << "FD " << ctrl.conn->fd << " : host=" << request->GetHost() << ", path=" << request->urlpath << ", user=" << user << ", passwd=" << password); state = BEGIN; ctrl.last_command = xstrdup("Connect to server"); @@ -3860,41 +3859,41 @@ return true; } /** * Quickly abort the transaction * \todo destruction should be sufficient as the destructor should cleanup, * including canceling close handlers */ void FtpStateData::abortTransaction(const char *reason) { debugs(9, 3, HERE << "aborting transaction for " << reason << "; FD " << (ctrl.conn!=NULL?ctrl.conn->fd:-1) << ", Data FD " << (data.conn!=NULL?data.conn->fd:-1) << ", this " << this); if (Comm::IsConnOpen(ctrl.conn)) { ctrl.conn->close(); return; } fwd->handleUnregisteredServerEnd(); - deleteThis("FtpStateData::abortTransaction"); + mustStop("FtpStateData::abortTransaction"); } /// creates a data channel Comm close callback AsyncCall::Pointer FtpStateData::dataCloser() { typedef CommCbMemFunT Dialer; return JobCallback(9, 5, Dialer, this, FtpStateData::dataClosed); } /// configures the channel with a descriptor and registers a close handler void FtpChannel::opened(const Comm::ConnectionPointer &newConn, const AsyncCall::Pointer &aCloser) { assert(!Comm::IsConnOpen(conn)); assert(closer == NULL); assert(Comm::IsConnOpen(newConn)); assert(aCloser != NULL); === modified file 'src/http.cc' --- src/http.cc 2011-08-30 15:04:30 +0000 +++ src/http.cc 2011-10-13 14:45:08 +0000 @@ -136,54 +136,45 @@ if (!readBuf->isNull()) readBuf->clean(); delete readBuf; if (httpChunkDecoder) delete httpChunkDecoder; cbdataReferenceDone(_peer); debugs(11,5, HERE << "HttpStateData " << this << " destroyed; " << serverConnection); } const Comm::ConnectionPointer & HttpStateData::dataConnection() const { return serverConnection; } -/* -static void -httpStateFree(int fd, void *data) -{ - HttpStateData *httpState = static_cast(data); - debugs(11, 5, "httpStateFree: FD " << fd << ", httpState=" << data); - delete httpState; -}*/ - void HttpStateData::httpStateConnClosed(const CommCloseCbParams ¶ms) { debugs(11, 5, "httpStateFree: FD " << params.fd << ", httpState=" << params.data); - deleteThis("HttpStateData::httpStateConnClosed"); + mustStop("HttpStateData::httpStateConnClosed"); } int httpCachable(const HttpRequestMethod& method) { /* GET and HEAD are cachable. Others are not. */ // TODO: replase to HttpRequestMethod::isCachable() ? if (method != METHOD_GET && method != METHOD_HEAD) return 0; /* else cachable */ return 1; } void HttpStateData::httpTimeout(const CommTimeoutCbParams ¶ms) { debugs(11, 4, HERE << serverConnection << ": '" << entry->url() << "'" ); @@ -2162,45 +2153,49 @@ buf.Printf("%x\r\n", static_cast(rawDataSize)); buf.append(raw.content(), rawDataSize); buf.Printf("\r\n"); Must(rawDataSize > 0); // we did not accidently created last-chunk above // Do not send last-chunk unless we successfully received everything if (receivedWholeRequestBody) { Must(!flags.sentLastChunk); flags.sentLastChunk = true; buf.append("0\r\n\r\n", 5); } return true; } void httpStart(FwdState *fwd) { debugs(11, 3, "httpStart: \"" << RequestMethodStr(fwd->request->method) << " " << fwd->entry->url() << "\"" ); - HttpStateData *httpState = new HttpStateData(fwd); + AsyncJob::Start(new HttpStateData(fwd)); +} - if (!httpState->sendRequest()) { +void +HttpStateData::start() +{ + if (!sendRequest()) { debugs(11, 3, "httpStart: aborted"); - delete httpState; + mustStop("HttpStateData::start failed"); return; } statCounter.server.all.requests++; statCounter.server.http.requests++; /* * We used to set the read timeout here, but not any more. * Now its set in httpSendComplete() after the full request, * including request body, has been written to the server. */ } /// if broken posts are enabled for the request, try to fix and return true bool HttpStateData::finishingBrokenPost() { #if USE_HTTP_VIOLATIONS if (!Config.accessList.brokenPosts) { debugs(11, 5, HERE << "No brokenPosts list"); @@ -2322,22 +2317,22 @@ kb_incr(&statCounter.server.http.kbytes_out, io.size); ServerStateData::sentRequestBody(io); } // Quickly abort the transaction // TODO: destruction should be sufficient as the destructor should cleanup, // including canceling close handlers void HttpStateData::abortTransaction(const char *reason) { debugs(11,5, HERE << "aborting transaction for " << reason << "; " << serverConnection << ", this " << this); if (Comm::IsConnOpen(serverConnection)) { serverConnection->close(); return; } fwd->handleUnregisteredServerEnd(); - deleteThis("HttpStateData::abortTransaction"); + mustStop("HttpStateData::abortTransaction"); } === modified file 'src/http.h' --- src/http.h 2011-06-30 08:33:36 +0000 +++ src/http.h 2011-10-12 10:52:57 +0000 @@ -85,40 +85,41 @@ /** * The current server connection. * Maybe open, closed, or NULL. * Use doneWithServer() to check if the server is available for use. */ Comm::ConnectionPointer serverConnection; AsyncCall::Pointer closeHandler; enum ConnectionStatus { INCOMPLETE_MSG, COMPLETE_PERSISTENT_MSG, COMPLETE_NONPERSISTENT_MSG }; ConnectionStatus statusIfComplete() const; ConnectionStatus persistentConnStatus() const; void keepaliveAccounting(HttpReply *); void checkDateSkew(HttpReply *); bool continueAfterParsingHeader(); void truncateVirginBody(); + virtual void start(); virtual void haveParsedReplyHeaders(); virtual bool getMoreRequestBody(MemBuf &buf); virtual void closeServer(); // end communication with the server virtual bool doneWithServer() const; // did we end communication? virtual void abortTransaction(const char *reason); // abnormal termination // consuming request body virtual void handleMoreRequestBodyAvailable(); virtual void handleRequestBodyProducerAborted(); void writeReplyBody(); bool decodeAndWriteReplyBody(); bool finishingBrokenPost(); bool finishingChunkedRequest(); void doneSendingRequestBody(); void requestBodyHandler(MemBuf &); virtual void sentRequestBody(const CommIoCbParams &io); void wroteLast(const CommIoCbParams &io); void sendComplete(); void httpStateConnClosed(const CommCloseCbParams ¶ms);