--------------------- PatchSet 1519 Date: 2005/08/17 22:01:26 Author: dwsquid Branch: squid3-icap Tag: (none) Log: Rough outline of ICAP and related code changes. This compiles and "runs" but does not talk to ICAP server and does not return a response to the client. Members: src/ICAPAnchor.cc:1.1.2.1->1.1.2.2 src/ICAPAnchor.h:1.1.2.1->1.1.2.2 src/ICAPClient.cc:1.1.2.1->1.1.2.2 src/Makefile.am:1.60.4.1->1.60.4.2 src/MsgPipe.cc:1.1.2.1->1.1.2.2 src/MsgPipeData.h:1.1.2.2->1.1.2.3 src/StoreIOBuffer.h:1.4->1.4.12.1 src/client_side_reply.cc:1.61.2.1->1.61.2.2 src/enums.h:1.24->1.24.4.1 src/http.cc:1.49->1.49.2.1 src/http.h:1.11->1.11.4.1 Index: squid3/src/ICAPAnchor.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/Attic/ICAPAnchor.cc,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -u -r1.1.2.1 -r1.1.2.2 --- squid3/src/ICAPAnchor.cc 17 Aug 2005 20:02:33 -0000 1.1.2.1 +++ squid3/src/ICAPAnchor.cc 17 Aug 2005 22:01:26 -0000 1.1.2.2 @@ -1,37 +1,41 @@ #include "squid.h" +#include "http.h" #include "MsgPipe.h" +#include "MsgPipeData.h" #include "HttpRequest.h" #include "HttpReply.h" #include "ICAPAnchor.h" #include "ICAPModule.h" ICAPAnchor::ICAPAnchor(): virgin(NULL), adapted(NULL) { - and initialize HttpStateData pointer } ICAPAnchor::~ICAPAnchor() { stop(notifyNone); + cbdataReferenceDone(httpState); } -void ICAPAnchor::startRespMod(HttpRequest *request, HttpReply *reply, MemObject *buf) { - remember some pointer to HttpStateData to call it later? +void ICAPAnchor::startRespMod(HttpStateData *anHttpState, HttpRequest *request, HttpReply *reply) { + httpState = cbdataReference(anHttpState); virgin = new MsgPipe; // this is the place to create a refcount ptr virgin->source = this; - virgin->cause = request; - virgin->header = reply; - virgin->body is buf->mem_hdr; + virgin->data = new MsgPipeData; + virgin->data->cause = request; + virgin->data->header = reply; + virgin->data->body = new mem_hdr; adapted = new MsgPipe; adapted->sink = this; - adapted->cause = request; // should not hurt + adapted->data = new MsgPipeData; + adapted->data->cause = request; // should not hurt - ICAPInitXaction(virgin, adapted); + //ICAPInitXaction(virgin, adapted); virgin->sendSourceStart(); // we may have virgin data to provide adapted->sendSinkNeed(); // we want adapted response, eventially } -void ICAPAnchor::sendMoreData() { +void ICAPAnchor::sendMoreData(StoreIOBuffer buf) { virgin->sendSourceProgress(); } @@ -42,34 +46,41 @@ // ICAP client needs more virgin response data void ICAPAnchor::noteSinkNeed(MsgPipe *p) { - 1) tell HttpStateData to resume reading (in case it has stopped due to full buffers, etc.) - 2) check that HttpStateData is reading (or we will get stuck w/o progress) + debug(0,0)("ICAPAnchor::noteSinkNeed called\n"); + //1) tell HttpStateData to resume reading (in case it has stopped due to full buffers, etc.) + //2) check that HttpStateData is reading (or we will get stuck w/o progress) } // ICAP client aborting void ICAPAnchor::noteSinkAbort(MsgPipe *p) { + debug(0,0)("ICAPAnchor::noteSinkNeed called\n"); stop(notifyOwner); } // ICAP client starts sending adapted response +// ICAP client has received new HTTP headers (if any) at this point void ICAPAnchor::noteSourceStart(MsgPipe *p) { - tell HttpStateData to prepare the response store + debug(0,0)("ICAPAnchor::noteSourceStart called\n"); + //tell HttpStateData to prepare the response store noteSourceProgress(p); } // ICAP client sends more data void ICAPAnchor::noteSourceProgress(MsgPipe *p) { - tell HttpStateData to store a fresh portion of the adapted response + debug(0,0)("ICAPAnchor::noteSourceProgress called\n"); + //tell HttpStateData to store a fresh portion of the adapted response } // ICAP client is done sending adapted response void ICAPAnchor::noteSourceFinish(MsgPipe *p) { - tell HttpStateData that we expect no more response data + debug(0,0)("ICAPAnchor::noteSourceFinish called\n"); + //tell HttpStateData that we expect no more response data stop(notifyNone); } // ICAP client is aborting void ICAPAnchor::noteSourceAbort(MsgPipe *p) { + debug(0,0)("ICAPAnchor::noteSourceAbort called\n"); stop(notifyOwner); } @@ -88,10 +99,10 @@ adapted = NULL; } - if (pointer to HttpStateData) { + if (httpState) { if (notifyOwner) - tell HttpStateData that we are aborting prematurely - pointer to HttpStateData = NULL; // will not call it any more + //tell HttpStateData that we are aborting prematurely + cbdataReferenceDone(httpState); // sets to NULL, will not call it any more } } Index: squid3/src/ICAPAnchor.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/Attic/ICAPAnchor.h,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -u -r1.1.2.1 -r1.1.2.2 --- squid3/src/ICAPAnchor.h 17 Aug 2005 20:02:33 -0000 1.1.2.1 +++ squid3/src/ICAPAnchor.h 17 Aug 2005 22:01:26 -0000 1.1.2.2 @@ -1,6 +1,6 @@ /* - * $Id: ICAPAnchor.h,v 1.1.2.1 2005/08/17 20:02:33 rousskov Exp $ + * $Id: ICAPAnchor.h,v 1.1.2.2 2005/08/17 22:01:26 dwsquid Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -54,8 +54,8 @@ virtual ~ICAPAnchor(); // synchronous calls called by HttpStateData - void startRespMod(HttpRequest *request, HttpReply *reply); - void sendMoreData(); + void startRespMod(HttpStateData *anHttpState, HttpRequest *request, HttpReply *reply); + void sendMoreData(StoreIOBuffer buf); void ownerAbort(); // pipe source methods; called by ICAP while receiving the virgin message @@ -69,7 +69,7 @@ virtual void noteSourceAbort(MsgPipe *p); public: - pointer to HttpStateData + HttpStateData *httpState; MsgPipe *virgin; MsgPipe *adapted; Index: squid3/src/ICAPClient.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/Attic/ICAPClient.cc,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -u -r1.1.2.1 -r1.1.2.2 --- squid3/src/ICAPClient.cc 16 Aug 2005 17:18:20 -0000 1.1.2.1 +++ squid3/src/ICAPClient.cc 17 Aug 2005 22:01:26 -0000 1.1.2.2 @@ -5,28 +5,60 @@ #include "ICAPClient.h" #include "clientStream.h" #include "client_side_reply.h" +#include "HttpHeader.h" +#include "HttpReply.h" +struct _junk { + clientStreamNode *node; + clientHttpRequest *http; + HttpReply *rep; + StoreIOBuffer *receivedData; +}; + +static EVH someEvent; + + +/* + * This callback is called for each incoming data chunk. + * Note receivedData only gives us the message body, not + * the headers + */ void -icapclientStreamRead(clientStreamNode *thisNode, clientHttpRequest *http) +icapclientProcessStream(clientStreamNode *thisNode, clientHttpRequest *http, HttpReply *rep, StoreIOBuffer receivedData) { - debug(0,0)("This is icapclientStreamRead\n"); + assert (thisNode != NULL); + assert (cbdataReferenceValid (thisNode)); - /* pass data through untouched */ - clientStreamNode *next = thisNode->next(); - clientStreamRead (thisNode, http, next->readBuffer); - return; -} - -void -icapclientProcessStream(clientStreamNode *thisNode, clientHttpRequest *http, HttpReply *rep, StoreIOBuffer recievedData) -{ debug(0,0)("This is icapclientProcessStream\n"); debug(0,0)("\tthisNode=%p\n", thisNode); debug(0,0)("\thttp=%p\n", http); debug(0,0)("\trep=%p\n", rep); + //debug(0,0)("\trep->content_length=%d\n", rep->content_length); + char *foo; + foo = new char[receivedData.length+1]; + xstrncpy(foo, receivedData.data, receivedData.length+1); + *(foo+receivedData.length) = '\0'; + debug(0,0)("{%s}\n", foo); + + struct _junk *j = (struct _junk *) xcalloc(1, sizeof(*j)); + j->node = thisNode; + j->http = http; + j->rep = rep; + j->receivedData = &receivedData; + + eventAdd("someEvent", someEvent, j, 5.0, 0, 0); + +} + +void +icapclientStreamRead(clientStreamNode *thisNode, clientHttpRequest *http) +{ + debug(0,0)("This is icapclientStreamRead\n"); /* pass data through untouched */ - clientStreamCallback (thisNode, http, rep, recievedData); + clientStreamNode *next = thisNode->next(); + clientStreamRead (thisNode, http, next->readBuffer); + return; } void @@ -45,3 +77,24 @@ return STREAM_NONE; } + +static void +someEvent(void *foo) +{ + debug(0,0)("this is someEvent\n"); + struct _junk *j = (struct _junk *) foo; + + + if (NULL != j->rep) { + httpHeaderPutExt(&j->rep->header, "X-foo", "bar-bar"); + } + + if (NULL == j->node->data.getRaw()) { + /* first call; setup our state */ + } + + /* pass data through untouched */ + clientStreamCallback (j->node, j->http, j->rep, *j->receivedData); + free(j); + +} Index: squid3/src/Makefile.am =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/Makefile.am,v retrieving revision 1.60.4.1 retrieving revision 1.60.4.2 diff -u -r1.60.4.1 -r1.60.4.2 --- squid3/src/Makefile.am 16 Aug 2005 17:18:54 -0000 1.60.4.1 +++ squid3/src/Makefile.am 17 Aug 2005 22:01:26 -0000 1.60.4.2 @@ -1,7 +1,7 @@ # # Makefile for the Squid Object Cache server # -# $Id: Makefile.am,v 1.60.4.1 2005/08/16 17:18:54 dwsquid Exp $ +# $Id: Makefile.am,v 1.60.4.2 2005/08/17 22:01:26 dwsquid Exp $ # # Uncomment and customize the following to suit your needs: # @@ -93,7 +93,9 @@ endif ICAP_CLIENT_ALL_SOURCE = \ - ICAPClient.cc + ICAPAnchor.cc \ + ICAPClient.cc \ + MsgPipe.cc if USE_ICAP_CLIENT ICAP_CLIENT_SOURCE = $(ICAP_CLIENT_ALL_SOURCE) else Index: squid3/src/MsgPipe.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/Attic/MsgPipe.cc,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -u -r1.1.2.1 -r1.1.2.2 --- squid3/src/MsgPipe.cc 17 Aug 2005 19:52:46 -0000 1.1.2.1 +++ squid3/src/MsgPipe.cc 17 Aug 2005 22:01:26 -0000 1.1.2.2 @@ -6,12 +6,34 @@ MsgPipe::MsgPipe(): data(NULL), source(NULL), sink(NULL) { } -#if 0 -void MsgPipe::sendSourceStart(); -void MsgPipe::sendSourceProgress(); -void MsgPipe::sendSourceFinish(); -void MsgPipe::sendSourceAbort(); - -void MsgPipe::sendSinkNeed(); -void MsgPipe::sendSinkAbort(); -#endif +void MsgPipe::sendSourceStart() +{ + debug(0,0)("MsgPipe::sendSourceStart() called\n"); +} + +void MsgPipe::sendSourceProgress() +{ + debug(0,0)("MsgPipe::sendSourceProgress() called\n"); +} + +void MsgPipe::sendSourceFinish() +{ + debug(0,0)("MsgPipe::sendSourceFinish() called\n"); +} + +void MsgPipe::sendSourceAbort() +{ + debug(0,0)("MsgPipe::sendSourceAbort() called\n"); +} + + +void MsgPipe::sendSinkNeed() +{ + debug(0,0)("MsgPipe::sendSinkNeed() called\n"); +} + +void MsgPipe::sendSinkAbort() +{ + debug(0,0)("MsgPipe::sendSinkAbort() called\n"); +} + Index: squid3/src/MsgPipeData.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/Attic/MsgPipeData.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/MsgPipeData.h 17 Aug 2005 21:57:55 -0000 1.1.2.2 +++ squid3/src/MsgPipeData.h 17 Aug 2005 22:01:26 -0000 1.1.2.3 @@ -1,6 +1,6 @@ /* - * $Id: MsgPipeData.h,v 1.1.2.2 2005/08/17 21:57:55 rousskov Exp $ + * $Id: MsgPipeData.h,v 1.1.2.3 2005/08/17 22:01:26 dwsquid Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -35,7 +35,8 @@ #define SQUID_MSGPIPEDATA_H #include "HttpReply.h" -#include "mem_hdr.h" + +class mem_hdr; // MsgPipeData contains information about the HTTP message being sent // from the pipe source to the sink. Since the entire message body may be @@ -47,7 +48,7 @@ class MsgPipeData { public: - MsgPipeData(); + MsgPipeData(): header(0), body(0), cause(0) {}; ~MsgPipeData(); public: Index: squid3/src/StoreIOBuffer.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/StoreIOBuffer.h,v retrieving revision 1.4 retrieving revision 1.4.12.1 diff -u -r1.4 -r1.4.12.1 --- squid3/src/StoreIOBuffer.h 11 Aug 2003 02:13:02 -0000 1.4 +++ squid3/src/StoreIOBuffer.h 17 Aug 2005 22:01:26 -0000 1.4.12.1 @@ -1,6 +1,6 @@ /* - * $Id: StoreIOBuffer.h,v 1.4 2003/08/11 02:13:02 squidadm Exp $ + * $Id: StoreIOBuffer.h,v 1.4.12.1 2005/08/17 22:01:26 dwsquid Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -55,6 +55,12 @@ return Range(offset, offset + length); } + void dump() const + { + fwrite(data, length, 1, stderr); + fwrite("\n", 1, 1, stderr); + } + struct { Index: squid3/src/client_side_reply.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/client_side_reply.cc,v retrieving revision 1.61.2.1 retrieving revision 1.61.2.2 diff -u -r1.61.2.1 -r1.61.2.2 --- squid3/src/client_side_reply.cc 16 Aug 2005 17:19:12 -0000 1.61.2.1 +++ squid3/src/client_side_reply.cc 17 Aug 2005 22:01:26 -0000 1.61.2.2 @@ -1,6 +1,6 @@ /* - * $Id: client_side_reply.cc,v 1.61.2.1 2005/08/16 17:19:12 dwsquid Exp $ + * $Id: client_side_reply.cc,v 1.61.2.2 2005/08/17 22:01:26 dwsquid Exp $ * * DEBUG: section 88 Client-side Reply Routines * AUTHOR: Robert Collins (Originally Duane Wessels in client_side.c) @@ -45,7 +45,7 @@ #if ESI #include "ESI.h" #endif -#if ICAP_CLIENT +#if ICAP_CLIENT_RESPMOD_POSTCACHE #include "ICAPClient.h" #endif #include "MemObject.h" @@ -1942,7 +1942,7 @@ } #endif -#if ICAP_CLIENT +#if ICAP_CLIENT_RESPMOD_POSTCACHE debug(88, 0) ("Enabling ICAP processing for %s\n", http->uri); clientStreamInsertHead(&http->client_stream, icapclientStreamRead, Index: squid3/src/enums.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/enums.h,v retrieving revision 1.24 retrieving revision 1.24.4.1 diff -u -r1.24 -r1.24.4.1 --- squid3/src/enums.h 19 Mar 2005 08:30:33 -0000 1.24 +++ squid3/src/enums.h 17 Aug 2005 22:01:26 -0000 1.24.4.1 @@ -1,6 +1,6 @@ /* - * $Id: enums.h,v 1.24 2005/03/19 08:30:33 squidadm Exp $ + * $Id: enums.h,v 1.24.4.1 2005/08/17 22:01:26 dwsquid Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -96,6 +96,7 @@ TCP_RESET, ERR_ESI, /* Failure to perform ESI processing */ ERR_INVALID_RESP, + ERR_ICAP_FAILURE, ERR_MAX } err_type; Index: squid3/src/http.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/http.cc,v retrieving revision 1.49 retrieving revision 1.49.2.1 diff -u -r1.49 -r1.49.2.1 --- squid3/src/http.cc 10 Jun 2005 02:13:46 -0000 1.49 +++ squid3/src/http.cc 17 Aug 2005 22:01:26 -0000 1.49.2.1 @@ -1,6 +1,6 @@ /* - * $Id: http.cc,v 1.49 2005/06/10 02:13:46 squidadm Exp $ + * $Id: http.cc,v 1.49.2.1 2005/08/17 22:01:26 dwsquid Exp $ * * DEBUG: section 11 Hypertext Transfer Protocol (HTTP) * AUTHOR: Harvest Derived @@ -51,8 +51,12 @@ #if DELAY_POOLS #include "DelayPools.h" #endif +#if ICAP_CLIENT +#include "ICAPAnchor.h" +#endif CBDATA_TYPE(HttpStateData); +CBDATA_TYPE(ICAPAnchor); static const char *const crlf = "\r\n"; @@ -101,6 +105,9 @@ requestUnlink(httpState->orig_request); httpState->request = NULL; httpState->orig_request = NULL; +#if ICAP_CLIENT + cbdataReferenceDone(httpState->icap); +#endif cbdataFree(httpState); } @@ -733,6 +740,9 @@ } processSurrogateControl (reply); +#if ICAP_CLIENT + icap->startRespMod(this, request, reply); +#endif /* TODO: we need our own reply * in the httpState, as we probably don't want to replace * the storeEntry with interim headers */ @@ -862,7 +872,7 @@ * connection. */ if (!flags.request_sent) { - debug(11, 1) ("httpReadReply: Request not yet fully sent \"%s %s\"\n", + debug(11, 1) ("statusIfComplete: Request not yet fully sent \"%s %s\"\n", RequestMethodStr[orig_request->method], storeUrl(entry)); return COMPLETE_NONPERSISTENT_MSG; @@ -918,11 +928,9 @@ return result; } -/* This will be called when data is ready to be read from fd. Read until - * error or connection closed. */ -/* XXX this function is too long! */ +/* This will be called when data is ready to be read from fd. */ static void -httpReadReply(int fd, char *buf, size_t len, comm_err_t flag, int xerrno,void *data) +httpReadReply(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data) { HttpStateData *httpState = static_cast(data); assert (fd == httpState->fd); @@ -931,6 +939,7 @@ PROF_stop(HttpStateData_readReply); } +/* XXX this function is too long! */ void HttpStateData::readReply (int fd, char *readBuf, size_t len, comm_err_t flag, int xerrno,void *data) { @@ -1126,7 +1135,13 @@ tempBuffer.length = len - end; tempBuffer.offset = currentOffset; currentOffset += tempBuffer.length; +#if ICAP_CLIENT + debug(0,0)("processReplyData: tempBuffer@%d:\n", __LINE__); + tempBuffer.dump(); + icap->sendMoreData (tempBuffer); +#else entry->write (tempBuffer); +#endif } flags.headers_pushed = 1; @@ -1135,12 +1150,18 @@ tempBuffer.length = len; tempBuffer.offset = currentOffset; currentOffset += len; +#if ICAP_CLIENT + debug(0,0)("processReplyData: tempBuffer@%d:\n", __LINE__); + tempBuffer.dump(); + icap->sendMoreData (tempBuffer); +#else entry->write(tempBuffer); +#endif } if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { /* - * the above storeAppend() call could ABORT this entry, + * the above entry->write() call could ABORT this entry, * in that case, the server FD should already be closed. * there's nothing for us to do. */ @@ -1240,18 +1261,29 @@ errorAppendEntry(entry, err); comm_close(fd); return; - } else { - /* - * Set the read timeout here because it hasn't been set yet. - * We only set the read timeout after the request has been - * fully written to the server-side. If we start the timeout - * after connection establishment, then we are likely to hit - * the timeout for POST/PUT requests that have very large - * request bodies. - */ - commSetTimeout(fd, Config.Timeout.read, httpTimeout, httpState); } +#if ICAP_CLIENT + if (httpState->doIcap() < 0) { + err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR); + err->xerrno = errno; + err->request = requestLink(httpState->orig_request); + errorAppendEntry(entry, err); + comm_close(fd); + return; + } +#endif + + /* + * Set the read timeout here because it hasn't been set yet. + * We only set the read timeout after the request has been + * fully written to the server-side. If we start the timeout + * after connection establishment, then we are likely to hit + * the timeout for POST/PUT requests that have very large + * request bodies. + */ + commSetTimeout(fd, Config.Timeout.read, httpTimeout, httpState); + httpState->flags.request_sent = 1; } @@ -1911,3 +1943,20 @@ version->major = major; version->minor = minor; } + +#if ICAP_CLIENT +/* + * Initiate an ICAP transaction. Return 0 if all is well, or -1 upon error. + * Caller will handle error condition by generating a Squid error message + * or take other action. + */ +int +HttpStateData::doIcap() +{ +debug(0,0)("HttpStateData::doIcap() called\n"); + CBDATA_INIT_TYPE(ICAPAnchor); + icap = cbdataAlloc(ICAPAnchor); + (void)cbdataReference(icap); + return 0; +} +#endif Index: squid3/src/http.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/http.h,v retrieving revision 1.11 retrieving revision 1.11.4.1 diff -u -r1.11 -r1.11.4.1 --- squid3/src/http.h 7 Mar 2005 03:13:57 -0000 1.11 +++ squid3/src/http.h 17 Aug 2005 22:01:27 -0000 1.11.4.1 @@ -1,6 +1,6 @@ /* - * $Id: http.h,v 1.11 2005/03/07 03:13:57 squidadm Exp $ + * $Id: http.h,v 1.11.4.1 2005/08/17 22:01:27 dwsquid Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -37,6 +37,8 @@ #include "StoreIOBuffer.h" #include "comm.h" +class ICAPAnchor; + class HttpStateData { @@ -67,6 +69,9 @@ bool ignoreCacheControl; bool surrogateNoStore; void processSurrogateControl(HttpReply *); +#if ICAP_CLIENT + ICAPAnchor *icap; +#endif private: enum ConnectionStatus { @@ -77,6 +82,7 @@ ConnectionStatus statusIfComplete() const; ConnectionStatus persistentConnStatus() const; void failReply (HttpReply *reply, http_status const &status); + int doIcap(); }; #endif /* SQUID_HTTP_H */