--------------------- PatchSet 3836 Date: 2006/10/06 16:43:03 Author: rousskov Branch: squid3-icap Tag: (none) Log: - Merged common code from the ICAPClientReqmodPrecache and ICAPClientReqmodPrecache classes into the newly added ICAPClientVector class. The specific vectors do not have a common owner (yet?) because ServerStateData and ClientHttpRequest do not have a common base class. Thus, ICAPClientVector has to rely on its kids to communicate with their owners. However, at least 50% of the logic was common and has been moved. Eventually, we may want to create a simple ICAPOwner API that ServerStateData and ClientHttpRequest can implement and ICAPClientVector can rely on. This will make the code simpler and more efficient. The big merge was motivated by a couple of bugs that were found in one vector class but that did not exist or behaved differently in the other vector, mostly likely due to natural diversion of used-to-be identical code. Debugging messages need more work. ICAPClientVector should probably use the name of the specific class in the debugging output. - Rewrote communication between a server-side ICAPClient*mod* vector and its owner. When a server-side ICAPClient*mod* vector was notifying its owner of more adapted data, the owner could delete the vector (by calling icap->ownerAbort) if the store entry was not willing to accept the data. The same deletion could happen when a vector was notifying the owner of a successful termination. In all those cases, the vector did not expect to be deleted and could continue to do something, causing segmentation faults. Now, when more data is available, the vector calls its owner and checks the return value of the call. If it is false, the vector knows it has been deleted and quits. When vector terminates, it calls its owner and trusts the owner to always delete the vector. The "check return value and quit" design is not perfect, but we are paying the price for isolating the vectors from their owners while using direct calls between them (instead of MsgPipe or a similar less efficient indirect approach we use elsewhere). Members: src/Makefile.am:1.60.4.20->1.60.4.21 src/ICAP/ICAPClientReqmodPrecache.cc:1.1.2.3->1.1.2.4 src/ICAP/ICAPClientReqmodPrecache.h:1.1.2.2->1.1.2.3 src/ICAP/ICAPClientRespmodPrecache.cc:1.1.2.3->1.1.2.4 src/ICAP/ICAPClientRespmodPrecache.h:1.1.2.2->1.1.2.3 src/ICAP/ICAPClientVector.cc:1.1->1.1.2.1 src/ICAP/ICAPClientVector.h:1.1->1.1.2.1 Index: squid3/src/Makefile.am =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/Makefile.am,v retrieving revision 1.60.4.20 retrieving revision 1.60.4.21 diff -u -r1.60.4.20 -r1.60.4.21 --- squid3/src/Makefile.am 29 Sep 2006 23:27:09 -0000 1.60.4.20 +++ squid3/src/Makefile.am 6 Oct 2006 16:43:04 -0000 1.60.4.21 @@ -1,7 +1,7 @@ # # Makefile for the Squid Object Cache server # -# $Id: Makefile.am,v 1.60.4.20 2006/09/29 23:27:09 dwsquid Exp $ +# $Id: Makefile.am,v 1.60.4.21 2006/10/06 16:43:04 rousskov Exp $ # # Uncomment and customize the following to suit your needs: # @@ -670,6 +670,8 @@ ICAP/ChunkedCodingParser.h \ ICAP/ICAPClient.cc \ ICAP/ICAPClient.h \ + ICAP/ICAPClientVector.cc \ + ICAP/ICAPClientVector.h \ ICAP/ICAPClientReqmodPrecache.cc \ ICAP/ICAPClientReqmodPrecache.h \ ICAP/ICAPClientRespmodPrecache.cc \ Index: squid3/src/ICAP/ICAPClientReqmodPrecache.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/ICAP/ICAPClientReqmodPrecache.cc,v retrieving revision 1.1.2.3 retrieving revision 1.1.2.4 diff -u -r1.1.2.3 -r1.1.2.4 --- squid3/src/ICAP/ICAPClientReqmodPrecache.cc 4 Oct 2006 19:34:04 -0000 1.1.2.3 +++ squid3/src/ICAP/ICAPClientReqmodPrecache.cc 6 Oct 2006 16:43:03 -0000 1.1.2.4 @@ -1,10 +1,7 @@ #include "squid.h" #include "client_side_request.h" #include "ClientRequestContext.h" -#include "MsgPipe.h" #include "MsgPipeData.h" -#include "MsgPipeSource.h" -#include "MsgPipeSink.h" #include "HttpRequest.h" #include "ICAPClientReqmodPrecache.h" #include "ICAPServiceRep.h" @@ -12,106 +9,19 @@ CBDATA_CLASS_INIT(ICAPClientReqmodPrecache); -ICAPClientReqmodPrecache::ICAPClientReqmodPrecache(ICAPServiceRep::Pointer aService): service(aService), http(NULL), virgin(NULL), adapted(NULL) +ICAPClientReqmodPrecache::ICAPClientReqmodPrecache(ICAPServiceRep::Pointer aService): + ICAPClientVector(aService, "ICAPClientReqmodPrecache"), http(NULL) { - debug(93,3)("ICAPClientReqmodPrecache constructed, this=%p\n", this); -} - -ICAPClientReqmodPrecache::~ICAPClientReqmodPrecache() -{ - stop(notifyNone); - cbdataReferenceDone(http); - debug(93,3)("ICAPClientReqmodPrecache destructed, this=%p\n", this); - - if (virgin != NULL) - freeVirgin(); - - if (adapted != NULL) { - /* - * adapted->sink is equal to this. Remove the pointer since - * we are deleting this. - */ - - if (adapted->sink) - adapted->sink = NULL; - - freeAdapted(); - } } void ICAPClientReqmodPrecache::startReqMod(ClientHttpRequest *aHttp, HttpRequest *request) { - debug(93,3)("ICAPClientReqmodPrecache::startReqMod() called\n"); http = cbdataReference(aHttp); - - virgin = new MsgPipe("virgin"); // this is the place to create a refcount ptr - virgin->source = this; - virgin->data = new MsgPipeData; - virgin->data->cause = NULL; - virgin->data->setHeader(request); - virgin->data->body = new MemBuf; - virgin->data->body->init(ICAP::MsgPipeBufSizeMin, ICAP::MsgPipeBufSizeMax); - - adapted = new MsgPipe("adapted"); - adapted->sink = this; - - ICAPInitXaction(service, virgin, adapted); - - virgin->sendSourceStart(); // we may have virgin data to provide - adapted->sendSinkNeed(); // we want adapted response, eventially -} - -void ICAPClientReqmodPrecache::sendMoreData(StoreIOBuffer buf) -{ - debug(93,3)("ICAPClientReqmodPrecache::sendMoreData() called\n"); - //buf.dump(); - /* - * The caller is responsible for not giving us more data - * than will fit in body MemBuf. Caller should use - * potentialSpaceSize() to find out how much we can hold. - */ - virgin->data->body->append(buf.data, buf.length); - virgin->sendSourceProgress(); -} - -int -ICAPClientReqmodPrecache::potentialSpaceSize() -{ - if (virgin == NULL) - return 0; - - return (int) virgin->data->body->potentialSpaceSize(); -} - -// ClientHttpRequest says we have the entire HTTP message -void ICAPClientReqmodPrecache::doneSending() -{ - debug(93,3)("ICAPClientReqmodPrecache::doneSending() called\n"); - - virgin->sendSourceFinish(); + startMod(http, NULL, request); } -// ClientHttpRequest tells us to abort -void ICAPClientReqmodPrecache::ownerAbort() -{ - debug(93,3)("ICAPClientReqmodPrecache::ownerAbort() called\n"); - stop(notifyIcap); -} - -// ICAP client needs more virgin response data -void ICAPClientReqmodPrecache::noteSinkNeed(MsgPipe *p) -{ - debug(93,3)("ICAPClientReqmodPrecache::noteSinkNeed() called\n"); - - if (virgin->data->body->potentialSpaceSize()) - http->icapSpaceAvailable(); -} - -// ICAP client aborting -void ICAPClientReqmodPrecache::noteSinkAbort(MsgPipe *p) -{ - debug(93,3)("ICAPClientReqmodPrecache::noteSinkAbort() called\n"); - stop(notifyOwner); +void ICAPClientReqmodPrecache::tellSpaceAvailable() { + http->icapSpaceAvailable(); } // ICAP client starts sending adapted response @@ -165,71 +75,40 @@ } } -// ICAP client is done sending adapted response -void ICAPClientReqmodPrecache::noteSourceFinish(MsgPipe *p) +void ICAPClientReqmodPrecache::tellDoneAdapting() { - debug(93,3)("ICAPClientReqmodPrecache::noteSourceFinish() called\n"); + debug(93,3)("ICAPClientReqmodPrecache::tellDoneAdapting() called\n"); //tell ClientHttpRequest that we expect no more response data - http->doneAdapting(); + http->doneAdapting(); // does not delete us (yet?) stop(notifyNone); } -// ICAP client is aborting -void ICAPClientReqmodPrecache::noteSourceAbort(MsgPipe *p) +void ICAPClientReqmodPrecache::tellAbortAdapting() { - debug(93,3)("ICAPClientReqmodPrecache::noteSourceAbort() called\n"); - stop(notifyOwner); + debug(93,3)("ICAPClientReqmodPrecache::tellAbortAdapting() called\n"); + // tell ClientHttpRequest that we are aborting ICAP processing prematurely + http->abortAdapting(); } // internal cleanup void ICAPClientReqmodPrecache::stop(Notify notify) { - if (virgin != NULL) { - if (notify == notifyIcap) - virgin->sendSourceAbort(); - else - virgin->source = NULL; - - freeVirgin(); - } - -#if DONT_FREE_ADAPTED /* * NOTE: We do not clean up "adapted->sink" here because it may * have an HTTP message body that needs to stay around a little * while longer so that the HTTP server-side can forward it on. */ - if (adapted != NULL) { - if (notify == notifyIcap) - adapted->sendSinkAbort(); - else - adapted->sink = NULL; - - freeAdapted(); - } - -#endif - - if (http) { - if (notify == notifyOwner) - // tell ClientHttpRequest that we are aborting prematurely - http->abortAdapting(); - - cbdataReferenceDone(http); - // http is now NULL, will not call it any more - } -} - -void ICAPClientReqmodPrecache::freeVirgin() -{ - // virgin->data->cause should be NULL; - virgin = NULL; // refcounted -} + // XXX: who will clean up the "adapted->sink" then? Does it happen + // when the owner deletes us? Is that why we are deleted when the + // owner is destroyed and not when ICAP adaptation is done, like + // in http.cc case? + + // XXX: "adapted->sink" does not really have an "HTTP message body", + // In fact, it simply points to "this". Should the above comment + // refer to adapted and adapted->data->body? -void ICAPClientReqmodPrecache::freeAdapted() -{ - adapted = NULL; // refcounted + ICAPClientVector::clean(notify, false); } /* Index: squid3/src/ICAP/ICAPClientReqmodPrecache.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/ICAP/ICAPClientReqmodPrecache.h,v retrieving revision 1.1.2.2 retrieving revision 1.1.2.3 diff -u -r1.1.2.2 -r1.1.2.3 --- squid3/src/ICAP/ICAPClientReqmodPrecache.h 29 Sep 2006 23:27:15 -0000 1.1.2.2 +++ squid3/src/ICAP/ICAPClientReqmodPrecache.h 6 Oct 2006 16:43:03 -0000 1.1.2.3 @@ -1,6 +1,6 @@ /* - * $Id: ICAPClientReqmodPrecache.h,v 1.1.2.2 2006/09/29 23:27:15 dwsquid Exp $ + * $Id: ICAPClientReqmodPrecache.h,v 1.1.2.3 2006/10/06 16:43:03 rousskov Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -31,68 +31,54 @@ * */ -#ifndef SQUID_ICAPCLIENTSIDEHOOK_H -#define SQUID_ICAPCLIENTSIDEHOOK_H +#ifndef SQUID_ICAPCLIENTREQMODPRECACHE_H +#define SQUID_ICAPCLIENTREQMODPRECACHE_H -#include "MsgPipe.h" -#include "MsgPipeSource.h" -#include "MsgPipeSink.h" - -/* The ICAP ClientReqmodPrecache implements message pipe sink and source interfaces. It - * helps client-side to marshall the incoming/virgin HTTP message (being - * recieved from the HTTP client) to Squid's ICAP client module, using the - * MsgPipe interface. The same interface is used to get the adapted HTTP - * message back from the ICAP client. client-side is the "owner" of the - * ICAPClientReqmodPrecache. - */ +#include "ICAPClientVector.h" -class HttpRequest; +/* + * ICAPClientReqmodPrecache implements the ICAP client-side pre-cache + * vectoring point using ICAPClientVector as a parent. + * ClientHttpRequest is the Owner of this vectoring point. + */ class ClientRequestContext; -class ICAPClientReqmodPrecache: public MsgPipeSource, public MsgPipeSink +class ICAPClientReqmodPrecache: public ICAPClientVector { public: ICAPClientReqmodPrecache(ICAPServiceRep::Pointer); - virtual ~ICAPClientReqmodPrecache(); // synchronous calls called by ClientHttpRequest void startReqMod(ClientHttpRequest *, HttpRequest *); - void sendMoreData(StoreIOBuffer buf); - void doneSending(); - void ownerAbort(); - int potentialSpaceSize(); /* how much data can we accept? */ // pipe source methods; called by ICAP while receiving the virgin message - virtual void noteSinkNeed(MsgPipe *p); - virtual void noteSinkAbort(MsgPipe *p); + // pipe sink methods; called by ICAP while sending the adapted message virtual void noteSourceStart(MsgPipe *p); virtual void noteSourceProgress(MsgPipe *p); - virtual void noteSourceFinish(MsgPipe *p); - virtual void noteSourceAbort(MsgPipe *p); + +protected: + // used by ICAPClientVector because it does not know Owner type + virtual void tellSpaceAvailable(); + virtual void tellDoneAdapting(); + virtual void tellAbortAdapting(); + virtual void stop(Notify notify); public: - ICAPServiceRep::Pointer service; ClientHttpRequest *http; - MsgPipe::Pointer virgin; - MsgPipe::Pointer adapted; BodyReader::Pointer body_reader; private: - typedef enum { notifyNone, notifyOwner, notifyIcap } Notify; - void stop(Notify notify); - void freeVirgin(); - void freeAdapted(); - CBDATA_CLASS2(ICAPClientReqmodPrecache); - // Hooks to BodyReader so HttpStateData can get the // adapted request body static BodyReadFunc readBody; static BodyAbortFunc abortBody; static BodyKickFunc kickBody; + + CBDATA_CLASS2(ICAPClientReqmodPrecache); }; #endif /* SQUID_ICAPCLIENTSIDEHOOK_H */ Index: squid3/src/ICAP/ICAPClientRespmodPrecache.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/ICAP/ICAPClientRespmodPrecache.cc,v retrieving revision 1.1.2.3 retrieving revision 1.1.2.4 diff -u -r1.1.2.3 -r1.1.2.4 --- squid3/src/ICAP/ICAPClientRespmodPrecache.cc 4 Oct 2006 18:00:33 -0000 1.1.2.3 +++ squid3/src/ICAP/ICAPClientRespmodPrecache.cc 6 Oct 2006 16:43:03 -0000 1.1.2.4 @@ -1,9 +1,6 @@ #include "squid.h" #include "http.h" -#include "MsgPipe.h" #include "MsgPipeData.h" -#include "MsgPipeSource.h" -#include "MsgPipeSink.h" #include "HttpRequest.h" #include "HttpReply.h" #include "ICAPClientRespmodPrecache.h" @@ -12,122 +9,23 @@ CBDATA_CLASS_INIT(ICAPClientRespmodPrecache); -ICAPClientRespmodPrecache::ICAPClientRespmodPrecache(ICAPServiceRep::Pointer aService): service(aService), serverState(NULL), virgin(NULL), adapted(NULL) +ICAPClientRespmodPrecache::ICAPClientRespmodPrecache(ICAPServiceRep::Pointer aService): + ICAPClientVector(aService, "ICAPClientRespmodPrecache"), serverState(NULL) { - debug(93,5)("ICAPClientRespmodPrecache constructed, this=%p\n", this); + debug(93,3)("ICAPClientRespmodPrecache constructed, this=%p\n", this); } -ICAPClientRespmodPrecache::~ICAPClientRespmodPrecache() +void ICAPClientRespmodPrecache::startRespMod(ServerStateData *aServerState, HttpRequest *request, HttpReply *reply) { - stop(notifyNone); - cbdataReferenceDone(serverState); - debug(93,5)("ICAPClientRespmodPrecache destructed, this=%p\n", this); - - if (virgin != NULL) - freeVirgin(); - - if (adapted != NULL) - freeAdapted(); - - service = NULL; -} - -void ICAPClientRespmodPrecache::startRespMod(ServerStateData *anServerState, HttpRequest *request, HttpReply *reply) -{ - serverState = cbdataReference(anServerState); - - virgin = new MsgPipe("virgin"); // this is the place to create a refcount ptr - virgin->source = this; - virgin->data = new MsgPipeData; - virgin->data->setCause(request); - virgin->data->setHeader(reply); - virgin->data->body = new MemBuf; - virgin->data->body->init(ICAP::MsgPipeBufSizeMin, ICAP::MsgPipeBufSizeMax); - - adapted = new MsgPipe("adapted"); - adapted->sink = this; -#if ICAP_ANCHOR_LOOPBACK - - adapted->data = new MsgPipeData; - adapted->data->setCause(request); // should not hurt -#else - - ICAPInitXaction(service, virgin, adapted); -#endif - - virgin->sendSourceStart(); // we may have virgin data to provide - adapted->sendSinkNeed(); // we want adapted response, eventially -} - -void ICAPClientRespmodPrecache::sendMoreData(StoreIOBuffer buf) -{ - debug(93,5)("ICAPClientRespmodPrecache::sendMoreData() called\n"); - //debugs(93,0,HERE << "appending " << buf.length << " bytes"); - //debugs(93,0,HERE << "body.contentSize = " << virgin->data->body->contentSize()); - //buf.dump(); - /* - * The caller is responsible for not giving us more data - * than will fit in body MemBuf. Caller should use - * potentialSpaceSize() to find out how much we can hold. - */ - virgin->data->body->append(buf.data, buf.length); - virgin->sendSourceProgress(); -} - -int -ICAPClientRespmodPrecache::potentialSpaceSize() -{ - if (virgin == NULL) - return 0; - - return (int) virgin->data->body->potentialSpaceSize(); -} - -// ServerStateData says we have the entire HTTP message -void ICAPClientRespmodPrecache::doneSending() -{ - debug(93,5)("ICAPClientRespmodPrecache::doneSending() called\n"); - -#if ICAP_ANCHOR_LOOPBACK - /* simple assignments are not the right way to do this */ - adapted->data->setHeader(virgin->data->header); - adapted->data->body = virgin->data->body; - noteSourceFinish(adapted); - return; -#else - - virgin->sendSourceFinish(); -#endif -} - -// ServerStateData tells us to abort -void ICAPClientRespmodPrecache::ownerAbort() -{ - debug(93,5)("ICAPClientRespmodPrecache::ownerAbort() called\n"); - stop(notifyIcap); -} - -// ICAP client needs more virgin response data -void ICAPClientRespmodPrecache::noteSinkNeed(MsgPipe *p) -{ - debug(93,5)("ICAPClientRespmodPrecache::noteSinkNeed() called\n"); - - if (virgin->data->body->potentialSpaceSize()) - serverState->icapSpaceAvailable(); -} - -// ICAP client aborting -void ICAPClientRespmodPrecache::noteSinkAbort(MsgPipe *p) -{ - debug(93,5)("ICAPClientRespmodPrecache::noteSinkAbort() called\n"); - stop(notifyOwner); + serverState = cbdataReference(aServerState); + startMod(serverState, request, reply); } // ICAP client starts sending adapted response // ICAP client has received new HTTP headers (if any) at this point void ICAPClientRespmodPrecache::noteSourceStart(MsgPipe *p) { - debugs(93,5, HERE << "ICAPClientRespmodPrecache::noteSourceStart() called"); + debugs(93,3, HERE << "ICAPClientRespmodPrecache::noteSourceStart() called"); HttpReply *reply = dynamic_cast(adapted->data->header); /* @@ -146,7 +44,8 @@ ssize_t dummy; bool expect_body = reply->expectingBody(virgin->data->cause->method, dummy); - serverState->takeAdaptedHeaders(reply); + if (!serverState->takeAdaptedHeaders(reply)) // deletes us + return; if (expect_body) noteSourceProgress(p); @@ -157,13 +56,14 @@ // ICAP client sends more data void ICAPClientRespmodPrecache::noteSourceProgress(MsgPipe *p) { - debug(93,5)("ICAPClientRespmodPrecache::noteSourceProgress() called\n"); + debug(93,3)("ICAPClientRespmodPrecache::noteSourceProgress() called\n"); //tell ServerStateData to store a fresh portion of the adapted response assert(serverState); if (p->data->body->hasContent()) { - serverState->takeAdaptedBody(p->data->body); + if (!serverState->takeAdaptedBody(p->data->body)) + return; // HttpStateData::takeAdaptedBody does not detect when we have enough, // so we always notify source that there more buffer space is available @@ -172,60 +72,23 @@ } } -// ICAP client is done sending adapted response -void ICAPClientRespmodPrecache::noteSourceFinish(MsgPipe *p) -{ - debug(93,5)("ICAPClientRespmodPrecache::noteSourceFinish() called\n"); - //tell ServerStateData that we expect no more response data - serverState->doneAdapting(); - stop(notifyNone); -} - -// ICAP client is aborting -void ICAPClientRespmodPrecache::noteSourceAbort(MsgPipe *p) +void +ICAPClientRespmodPrecache::tellSpaceAvailable() { - debug(93,5)("ICAPClientRespmodPrecache::noteSourceAbort() called\n"); - stop(notifyOwner); + serverState->icapSpaceAvailable(); } -// internal cleanup -void ICAPClientRespmodPrecache::stop(Notify notify) +void +ICAPClientRespmodPrecache::tellDoneAdapting() { - if (virgin != NULL) { - if (notify == notifyIcap) - virgin->sendSourceAbort(); - else - virgin->source = NULL; - - freeVirgin(); - } - - if (adapted != NULL) { - if (notify == notifyIcap) - adapted->sendSinkAbort(); - else - adapted->sink = NULL; - - freeAdapted(); - } - - if (serverState) { - if (notify == notifyOwner) - // tell ServerStateData that we are aborting prematurely - serverState->abortAdapting(); - - cbdataReferenceDone(serverState); - - // serverState is now NULL, will not call it any more - } + serverState->finishAdapting(); // deletes us } -void ICAPClientRespmodPrecache::freeVirgin() +void +ICAPClientRespmodPrecache::tellAbortAdapting() { - virgin = NULL; // refcounted + debug(93,3)("ICAPClientReqmodPrecache::tellAbortAdapting() called\n"); + // tell ClientHttpRequest that we are aborting ICAP processing prematurely + serverState->abortAdapting(); // deletes us } -void ICAPClientRespmodPrecache::freeAdapted() -{ - adapted = NULL; // refcounted -} Index: squid3/src/ICAP/ICAPClientRespmodPrecache.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/ICAP/ICAPClientRespmodPrecache.h,v retrieving revision 1.1.2.2 retrieving revision 1.1.2.3 diff -u -r1.1.2.2 -r1.1.2.3 --- squid3/src/ICAP/ICAPClientRespmodPrecache.h 29 Sep 2006 23:27:15 -0000 1.1.2.2 +++ squid3/src/ICAP/ICAPClientRespmodPrecache.h 6 Oct 2006 16:43:03 -0000 1.1.2.3 @@ -1,6 +1,6 @@ /* - * $Id: ICAPClientRespmodPrecache.h,v 1.1.2.2 2006/09/29 23:27:15 dwsquid Exp $ + * $Id: ICAPClientRespmodPrecache.h,v 1.1.2.3 2006/10/06 16:43:03 rousskov Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -31,62 +31,44 @@ * */ -#ifndef SQUID_ICAPANCHOR_H -#define SQUID_ICAPANCHOR_H +#ifndef SQUID_ICAPCLIENTRESPMODPRECACHE_H +#define SQUID_ICAPCLIENTRESPMODPRECACHE_H -#include "MsgPipe.h" -#include "MsgPipeSource.h" -#include "MsgPipeSink.h" -#include "ICAPServiceRep.h" - -/* The ICAP Anchor implements message pipe sink and source interfaces. It - * helps ServerStateData to marshall the incoming/virgin HTTP message (being - * recieved from the HTTP server) to Squid's ICAP client module, using the - * MsgPipe interface. The same interface is used to get the adapted HTTP - * message back from the ICAP client. ServerStateData is the "owner" of the - * ICAPClientRespmodPrecache. - */ +#include "ICAPClientVector.h" -class HttpRequest; +/* + * ICAPClientRespmodPrecache implements the server-side pre-cache ICAP + * vectoring point using ICAPClientVector as a parent. + * ServerStateData is the Owner of this vectoring point. + */ -class HttpReply; +class ServerStateData; -class ICAPClientRespmodPrecache: public MsgPipeSource, public MsgPipeSink +class ICAPClientRespmodPrecache: public ICAPClientVector { public: ICAPClientRespmodPrecache(ICAPServiceRep::Pointer); - virtual ~ICAPClientRespmodPrecache(); // synchronous calls called by ServerStateData void startRespMod(ServerStateData *anServerState, HttpRequest *request, HttpReply *reply); - void sendMoreData(StoreIOBuffer buf); - void doneSending(); - void ownerAbort(); - int potentialSpaceSize(); /* how much data can we accept? */ // pipe source methods; called by ICAP while receiving the virgin message - virtual void noteSinkNeed(MsgPipe *p); - virtual void noteSinkAbort(MsgPipe *p); // pipe sink methods; called by ICAP while sending the adapted message virtual void noteSourceStart(MsgPipe *p); virtual void noteSourceProgress(MsgPipe *p); - virtual void noteSourceFinish(MsgPipe *p); - virtual void noteSourceAbort(MsgPipe *p); + +protected: + virtual void tellSpaceAvailable(); + virtual void tellDoneAdapting(); // deletes us + virtual void tellAbortAdapting(); // deletes us public: - ICAPServiceRep::Pointer service; ServerStateData *serverState; - MsgPipe::Pointer virgin; - MsgPipe::Pointer adapted; private: - typedef enum { notifyNone, notifyOwner, notifyIcap } Notify; - void stop(Notify notify); - void freeVirgin(); - void freeAdapted(); CBDATA_CLASS2(ICAPClientRespmodPrecache); }; -#endif /* SQUID_ICAPANCHOR_H */ +#endif /* SQUID_ICAPCLIENTRESPMODPRECACHE_H */ --- /dev/null Wed Feb 14 13:37:19 2007 +++ squid3/src/ICAP/ICAPClientVector.cc Wed Feb 14 13:38:11 2007 @@ -0,0 +1,161 @@ +#include "squid.h" +#include "MsgPipe.h" +#include "MsgPipeData.h" +#include "MsgPipeSource.h" +#include "MsgPipeSink.h" +#include "HttpRequest.h" +#include "ICAPClientVector.h" +#include "ICAPClient.h" + +ICAPClientVector::ICAPClientVector(ICAPServiceRep::Pointer aService, const char *aPoint): + theOwner(0), vPoint(aPoint), + service(aService), virgin(NULL), adapted(NULL) +{ + debug(93,3)("%s constructed, this=%p\n", vPoint, this); +} + +ICAPClientVector::~ICAPClientVector() +{ + stop(notifyNone); + debug(93,3)("%s destructed, this=%p\n", vPoint, this); +} + +void ICAPClientVector::startMod(void *anOwner, HttpRequest *cause, HttpMsg *header) +{ + debug(93,5)("%s starting, this=%p\n", vPoint, this); + + theOwner = anOwner; + + virgin = new MsgPipe("virgin"); // this is the place to create a refcount ptr + virgin->source = this; + virgin->data = new MsgPipeData; + virgin->data->setCause(cause); + virgin->data->setHeader(header); + virgin->data->body = new MemBuf; + virgin->data->body->init(ICAP::MsgPipeBufSizeMin, ICAP::MsgPipeBufSizeMax); + + adapted = new MsgPipe("adapted"); + adapted->sink = this; + +#if ICAP_ANCHOR_LOOPBACK + adapted->data = new MsgPipeData; + adapted->data->setCause(request); // should not hurt +#else + ICAPInitXaction(service, virgin, adapted); +#endif + + virgin->sendSourceStart(); // we may have virgin data to provide + adapted->sendSinkNeed(); // we want adapted response, eventially +} + +void ICAPClientVector::sendMoreData(StoreIOBuffer buf) +{ + debug(93,3)("ICAPClientVector::sendMoreData() called\n"); + //debugs(93,0,HERE << "appending " << buf.length << " bytes"); + //debugs(93,0,HERE << "body.contentSize = " << virgin->data->body->contentSize()); + //buf.dump(); + /* + * The caller is responsible for not giving us more data + * than will fit in body MemBuf. Caller should use + * potentialSpaceSize() to find out how much we can hold. + */ + virgin->data->body->append(buf.data, buf.length); + virgin->sendSourceProgress(); +} + +int +ICAPClientVector::potentialSpaceSize() +{ + if (virgin == NULL) + return 0; + + return (int) virgin->data->body->potentialSpaceSize(); +} + +// Owner says we have the entire HTTP message +void ICAPClientVector::doneSending() +{ + debug(93,3)("ICAPClientVector::doneSending() called\n"); + +#if ICAP_ANCHOR_LOOPBACK + /* simple assignments are not the right way to do this */ + adapted->data->setHeader(virgin->data->header); + adapted->data->body = virgin->data->body; + noteSourceFinish(adapted); + return; +#else + virgin->sendSourceFinish(); +#endif +} + +// Owner tells us to abort +void ICAPClientVector::ownerAbort() +{ + debug(93,3)("ICAPClientVector::ownerAbort() called\n"); + stop(notifyIcap); +} + +// ICAP client needs more virgin response data +void ICAPClientVector::noteSinkNeed(MsgPipe *p) +{ + debug(93,3)("ICAPClientVector::noteSinkNeed() called\n"); + + if (virgin->data->body->potentialSpaceSize()) + tellSpaceAvailable(); +} + +// ICAP client aborting +void ICAPClientVector::noteSinkAbort(MsgPipe *p) +{ + debug(93,3)("ICAPClientVector::noteSinkAbort() called\n"); + stop(notifyOwner); // deletes us +} + +// ICAP client is done sending adapted response +void ICAPClientVector::noteSourceFinish(MsgPipe *p) +{ + debug(93,3)("ICAPClientVector::noteSourceFinish() called\n"); + tellDoneAdapting(); // deletes us +} + +// ICAP client is aborting +void ICAPClientVector::noteSourceAbort(MsgPipe *p) +{ + debug(93,3)("ICAPClientVector::noteSourceAbort() called\n"); + stop(notifyOwner); // deletes us +} + +void ICAPClientVector::stop(Notify notify) +{ + clean(notify, true); +} + +void ICAPClientVector::clean(Notify notify, bool cleanAdapted) +{ + if (virgin != NULL) { + if (notify == notifyIcap) + virgin->sendSourceAbort(); + else + virgin->source = NULL; + virgin = NULL; // refcounted + } + + if (cleanAdapted && adapted != NULL) { + if (notify == notifyIcap) + adapted->sendSinkAbort(); + else + adapted->sink = NULL; + adapted = NULL; // refcounted + } + + service = NULL; + + if (theOwner) { + if (notify == notifyOwner) + tellAbortAdapting(); // deletes us + else + cbdataReferenceDone(theOwner); + } + + // not safe to do anything here because we may have been deleted. +} --- /dev/null Wed Feb 14 13:37:19 2007 +++ squid3/src/ICAP/ICAPClientVector.h Wed Feb 14 13:38:11 2007 @@ -0,0 +1,98 @@ + +/* + * $Id: ICAPClientVector.h,v 1.1.2.1 2006/10/06 16:43:03 rousskov Exp $ + * + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#ifndef SQUID_ICAPVECTOR_H +#define SQUID_ICAPVECTOR_H + +#include "MsgPipe.h" +#include "MsgPipeSource.h" +#include "MsgPipeSink.h" +#include "ICAPServiceRep.h" + +/* + * The ICAP Vector helps its Owner to talk to the ICAP transaction, which + * implements asynchronous communication with the ICAP server. The Owner + * is either the HTTP client side (ClientHttpRequest) or the HTTP server + * side (ServerStateData). The Vector marshals the incoming/virgin HTTP + * message to the ICAP transaction, via the MsgPipe interface. The same + * interface is used to get the adapted HTTP message back. + * + * ICAPClientReqmodPrecache and ICAPClientRespmodPrecache classes use + * ICAPVector as a base and cover specifics of their vectoring point. + */ + +class ICAPClientVector: public MsgPipeSource, public MsgPipeSink +{ + +public: + ICAPClientVector(ICAPServiceRep::Pointer, const char *aPoint); + virtual ~ICAPClientVector(); + + // synchronous calls called by Owner + void sendMoreData(StoreIOBuffer buf); + void doneSending(); + void ownerAbort(); + int potentialSpaceSize(); /* how much data can we accept? */ + + // pipe source methods; called by ICAP while receiving the virgin message + virtual void noteSinkNeed(MsgPipe *p); + virtual void noteSinkAbort(MsgPipe *p); + + // pipe sink methods; called by ICAP while sending the adapted message + virtual void noteSourceStart(MsgPipe *p) = 0; + virtual void noteSourceProgress(MsgPipe *p) = 0; + virtual void noteSourceFinish(MsgPipe *p); + virtual void noteSourceAbort(MsgPipe *p); + +protected: + typedef enum { notifyNone, notifyOwner, notifyIcap } Notify; + + // implemented by kids because we do not have a common Owner parent + virtual void tellSpaceAvailable() = 0; + virtual void tellDoneAdapting() = 0; // may delete us + virtual void tellAbortAdapting() = 0; // may delete us + virtual void stop(Notify notify); // may delete us + + void startMod(void *anOwner, HttpRequest *cause, HttpMsg *header); + void clean(Notify notify, bool cleanAdapted = true); + +public: + void *theOwner; + const char *vPoint; // unmanaged vectoring point name for debugging + + ICAPServiceRep::Pointer service; + MsgPipe::Pointer virgin; + MsgPipe::Pointer adapted; +}; + +#endif /* SQUID_ICAPVECTOR_H */