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.

Also the Adaptation::AccessCheck modified to schedule an AsyncJobCall when access check finishes.

ServerStateData and ClientHttpRequest classes modified to work with the new Adaptation::AccessCheck.


This is a Measurement Factory project
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.
Also 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-12 13:04:20 +0000
@@ -194,63 +194,49 @@
     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()
 #endif
-
-    if (!doneWithServer()) {
-        debugs(11,5, HERE << "transaction not done: still talking to server");
-        return;
-    }
-
-    debugs(11,3, HERE << "transaction done");
-
-    deleteThis("ServerStateData::quitIfAllDone");
+        ;
 }
 
 // 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 +735,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 +795,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<Adaptation::Initiate> 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<Adaptation::Initiator> theInitiator; ///< the job which ordered this access check
     ACLFilledChecklist *acl_checklist;
 
     typedef int Candidate;
     typedef Vector<Candidate> 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::Initiate>
 Adaptation::Initiator::initiateAdaptation(Initiate *x)
 {
     CbcPointer<Initiate> i(x);
     x->initiator(this);
     Start(x);
     return i;
 }
 
 void
 Adaptation::Initiator::clearAdaptation(CbcPointer<Initiate> &x)
 {
     x.clear();
 }
 
 void
 Adaptation::Initiator::announceInitiatorAbort(CbcPointer<Initiate> &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<Initiate> initiateAdaptation(Initiate *x);
 
     /// clears the pointer (does not call announceInitiatorAbort)
     void clearAdaptation(CbcPointer<Initiate> &x);
 
     /// inform the transaction about abnormal termination and clear the pointer
     void announceInitiatorAbort(CbcPointer<Initiate> &x);
 
     /// Must(initiated(initiate)) instead of Must(initiate.set()), for clarity
     bool initiated(const CbcPointer<AsyncJob> &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<Adaptation::Initiate> 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<FtpStateData, CommCloseCbParams> 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-12 10:55:49 +0000
@@ -149,41 +149,41 @@
 
 const Comm::ConnectionPointer &
 HttpStateData::dataConnection() const
 {
     return serverConnection;
 }
 
 /*
 static void
 httpStateFree(int fd, void *data)
 {
     HttpStateData *httpState = static_cast<HttpStateData *>(data);
     debugs(11, 5, "httpStateFree: FD " << fd << ", httpState=" << data);
     delete httpState;
 }*/
 
 void
 HttpStateData::httpStateConnClosed(const CommCloseCbParams &params)
 {
     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 &params)
 {
     debugs(11, 4, HERE << serverConnection << ": '" << entry->url() << "'" );
 
@@ -2162,45 +2162,49 @@
     buf.Printf("%x\r\n", static_cast<unsigned int>(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 +2326,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 &params);

Reply via email to