From: robertc <> Date: Sat, 15 Mar 2003 11:17:38 +0000 (+0000) Subject: Summary: X-Git-Tag: SQUID_3_0_PRE1~261 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0655fa4d59f4c8c0c212ab7a0530ae6f149fd78d;p=thirdparty%2Fsquid.git Summary: Merge in IMS refactoring. Keywords: Patches applied: * robertc@squid-cache.org--squid/squid--bug-564--3.0--patch-5 And ESI was broken too. * robertc@squid-cache.org--squid/squid--bug-564--3.0--patch-4 Fix introduced memleak. * robertc@squid-cache.org--squid/squid--bug-564--3.0--patch-3 Start tackling the refresh logic. * robertc@squid-cache.org--squid/squid--bug-564--3.0--patch-2 More steps to fixing bug #564 * robertc@squid-cache.org--squid/squid--bug-564--3.0--patch-1 Towards addressing bug 564 * robertc@squid-cache.org--squid/squid--bug-564--3.0--base-0 tag of robertc@squid-cache.org--squid/squid--HEAD--3.0--patch-125 --- diff --git a/include/RefCount.h b/include/RefCount.h index 9aa9efbbe4..d646931731 100644 --- a/include/RefCount.h +++ b/include/RefCount.h @@ -1,6 +1,6 @@ /* - * $Id: RefCount.h,v 1.4 2003/03/10 04:56:20 robertc Exp $ + * $Id: RefCount.h,v 1.5 2003/03/15 04:17:38 robertc Exp $ * * DEBUG: section xx Refcount allocator * AUTHOR: Robert Collins @@ -84,6 +84,11 @@ public: return p.p_ == p_; } + bool operator != (const RefCount &p) const + { + return p.p_ != p_; + } + private: void dereference() { diff --git a/src/ESI.cc b/src/ESI.cc index 0dd49229b4..d02a28aed9 100644 --- a/src/ESI.cc +++ b/src/ESI.cc @@ -1,6 +1,6 @@ /* - * $Id: ESI.cc,v 1.2 2003/03/11 08:24:42 robertc Exp $ + * $Id: ESI.cc,v 1.3 2003/03/15 04:17:38 robertc Exp $ * * DEBUG: section 86 ESI processing * AUTHOR: Robert Collins @@ -55,7 +55,9 @@ * */ -typedef struct _esiStreamContext esiStreamContext; +class ESIStreamContext; + +typedef class ESIStreamContext esiStreamContext; /* TODO: split this out into separate files ? */ /* Parsing: quick and dirty. ESI files are not valid XML, so a generic @@ -211,6 +213,31 @@ private: MemPool * esiComment::pool = NULL; +class esiInclude; +typedef RefCount esiIncludePtr; + +class ESIStreamContext : public RefCountable +{ + +public: + typedef RefCount Pointer; + void *operator new(size_t); + void operator delete(void *); + void deleteSelf() const; + ESIStreamContext(); + ~ESIStreamContext(); + void freeResources(); + int finished; + esiIncludePtr include; + ESISegment::Pointer localbuffer; + ESISegment::Pointer buffer; + +private: + CBDATA_CLASS(ESIStreamContext); +}; + +CBDATA_CLASS_INIT (ESIStreamContext); + #include "ESILiteral.h" MemPool *esiLiteral::pool = NULL; @@ -218,8 +245,10 @@ MemPool *esiLiteral::pool = NULL; /* esiInclude */ -struct esiInclude : public ESIElement +class esiInclude : public ESIElement { + +public: void *operator new (size_t byteCount); void operator delete (void *address); void deleteSelf() const; @@ -230,7 +259,7 @@ struct esiInclude : public ESIElement esiProcessResult_t process (int dovars); Pointer makeCacheable() const; Pointer makeUsable(esiTreeParentPtr, esiVarState &) const; - void subRequestDone (esiStreamContext *, bool); + void subRequestDone (ESIStreamContext::Pointer, bool); struct { @@ -246,18 +275,18 @@ int finished: } flags; - esiStreamContext *src; - esiStreamContext *alt; + ESIStreamContext::Pointer src; + ESIStreamContext::Pointer alt; ESISegment::Pointer srccontent; ESISegment::Pointer altcontent; esiVarState *varState; char *srcurl, *alturl; - void fail(esiStreamContext *); + void fail(ESIStreamContext::Pointer); void finish(); private: static MemPool *Pool; - static void Start (esiStreamContext *, char const *, esiVarState *); + static void Start (ESIStreamContext::Pointer, char const *, esiVarState *); esiTreeParentPtr parent; void start(); bool started; @@ -451,30 +480,14 @@ bool ESIContext::reading() const return reading_; } -typedef RefCount esiIncludePtr; - -struct _esiStreamContext -{ - -public: - void *operator new(size_t); - _esiStreamContext(); - int finished; - esiIncludePtr include; - ESISegment::Pointer localbuffer; - ESISegment::Pointer buffer; -}; - -CBDATA_TYPE (esiStreamContext); -_esiStreamContext::_esiStreamContext() : finished(false), include (NULL), localbuffer (new ESISegment), buffer (NULL) +ESIStreamContext::ESIStreamContext() : finished(false), include (NULL), localbuffer (new ESISegment), buffer (NULL) {} /* Local functions */ /* ESIContext */ static ESIContext *ESIContextNew(HttpReply *, clientStreamNode *, clientHttpRequest *); /* esiStreamContext */ -static FREE esiStreamContextFree; static esiStreamContext *esiStreamContextNew (esiIncludePtr); /* other */ @@ -645,22 +658,20 @@ void esiStreamRead (clientStreamNode *thisNode, clientHttpRequest *http) { clientStreamNode *next; - ESIContext *context; /* Test preconditions */ assert (thisNode != NULL); assert (cbdataReferenceValid (thisNode)); /* we are not in the chain until ESI is detected on a data callback */ - assert (thisNode->data != NULL); assert (thisNode->node.prev != NULL); assert (thisNode->node.next != NULL); - context = (ESIContext *)cbdataReference (thisNode->data); + ESIContext::Pointer context = dynamic_cast(thisNode->data.getRaw()); + assert (context.getRaw() != NULL); if (context->flags.passthrough) { /* passthru mode - read into supplied buffers */ next = thisNode->next(); clientStreamRead (thisNode, http, next->readBuffer); - cbdataReferenceDone (context); return; } @@ -679,7 +690,6 @@ esiStreamRead (clientStreamNode *thisNode, clientHttpRequest *http) case ESIContext::ESI_KICK_SENT: case ESIContext::ESI_KICK_INPROGRESS: - cbdataReferenceDone (context); return; case ESIContext::ESI_KICK_PENDING: @@ -696,7 +706,6 @@ esiStreamRead (clientStreamNode *thisNode, clientHttpRequest *http) * flow */ debug (86,5) ("esiStreamRead: Waiting for async resume of esi processing\n"); - cbdataReferenceDone (context); return; } @@ -704,7 +713,6 @@ esiStreamRead (clientStreamNode *thisNode, clientHttpRequest *http) debug (86,5)("all processing complete, but outbound data still buffered\n"); assert (!context->flags.clientwantsdata); /* client MUST be processing the last reply */ - cbdataReferenceDone (context); return; } @@ -715,14 +723,11 @@ esiStreamRead (clientStreamNode *thisNode, clientHttpRequest *http) /* We've finished processing, and there is no more data buffered */ debug (86,5)("Telling recipient EOF on READ\n"); clientStreamCallback (thisNode, http, NULL, tempBuffer); - cbdataReferenceDone (context); return; } - if (context->reading()) { - cbdataReferenceDone (context); + if (context->reading()) return; - } /* no data that is ready to send, and still reading? well, lets get some */ /* secure a buffer */ @@ -741,8 +746,6 @@ esiStreamRead (clientStreamNode *thisNode, clientHttpRequest *http) context->startRead(); clientStreamRead (thisNode, http, tempBuffer); } - - cbdataReferenceDone (context); } clientStream_status_t @@ -752,27 +755,22 @@ esiStreamStatus (clientStreamNode *thisNode, clientHttpRequest *http) assert (thisNode != NULL); assert (cbdataReferenceValid (thisNode)); /* we are not in the chain until ESI is detected on a data callback */ - assert (thisNode->data != NULL); assert (thisNode->node.prev != NULL); assert (thisNode->node.next != NULL); - ESIContext *context = (ESIContext *)cbdataReference (thisNode->data); + ESIContext::Pointer context = dynamic_cast(thisNode->data.getRaw()); + assert (context.getRaw() != NULL); - if (context->flags.passthrough) { - cbdataReferenceDone (context); + if (context->flags.passthrough) return clientStreamStatus (thisNode, http); - } if (context->flags.oktosend && context->flags.finished && !(context->outbound.getRaw() && context->outbound_offset < context->outbound->len)) { - cbdataReferenceDone (context); debug (86,5) ("Telling recipient EOF on STATUS\n"); return STREAM_UNPLANNED_COMPLETE; /* we don't know lengths in advance */ } /* ?? RC: we can't be aborted / fail ? */ - cbdataReferenceDone (context); - return STREAM_NONE; } @@ -930,11 +928,11 @@ void esiStreamDetach (clientStreamNode *thisNode, clientHttpRequest *http) { /* if we have pending callbacks, tell them we're done. */ - ESIContext *context; /* test preconditions */ assert (thisNode != NULL); assert (cbdataReferenceValid (thisNode)); - context = ( ESIContext *)cbdataReference(thisNode->data); + ESIContext::Pointer context = dynamic_cast(thisNode->data.getRaw()); + assert (context.getRaw() != NULL); /* detach from the stream */ clientStreamDetach (thisNode,http); /* if we have pending callbacks (from subincludes), tell them we're done. */ @@ -945,7 +943,6 @@ esiStreamDetach (clientStreamNode *thisNode, clientHttpRequest *http) context->parserState.stack[0] = NULL; /* allow refcount logic to trigger */ context->cbdataLocker = NULL; - cbdataReferenceDone (context); } /* Process incoming data for ESI tags */ @@ -964,7 +961,6 @@ esiStreamDetach (clientStreamNode *thisNode, clientHttpRequest *http) void esiProcessStream (clientStreamNode *thisNode, clientHttpRequest *http, HttpReply *rep, StoreIOBuffer recievedData) { - ESIContext *context; /* test preconditions */ assert (thisNode != NULL); /* ESI TODO: handle thisNode rather than asserting - it should only ever @@ -976,14 +972,16 @@ esiProcessStream (clientStreamNode *thisNode, clientHttpRequest *http, HttpReply * if data is NULL thisNode is the first entrance. If rep is also NULL, * something is wrong. * */ - assert (thisNode->data != NULL || rep); + assert (thisNode->data.getRaw() != NULL || rep); assert (thisNode->node.next != NULL); - if (!thisNode->data) + if (!thisNode->data.getRaw()) /* setup ESI context from reply headers */ thisNode->data = ESIContextNew(rep, thisNode, http); - context = (ESIContext *)cbdataReference(thisNode->data); + ESIContext::Pointer context = dynamic_cast(thisNode->data.getRaw()); + + assert (context.getRaw() != NULL); context->finishRead(); @@ -992,12 +990,11 @@ esiProcessStream (clientStreamNode *thisNode, clientHttpRequest *http, HttpReply * has been detected to prevent ESI processing the error body */ if (context->flags.passthrough) { - cbdataReferenceDone(context); clientStreamCallback (thisNode, http, rep, recievedData); return; } - debug (86, 3)("esiProcessStream: Processing thisNode %p context %p offset %d length %u\n",thisNode, context, (int) recievedData.offset, (unsigned int)recievedData.length); + debug (86, 3)("esiProcessStream: Processing thisNode %p context %p offset %d length %u\n",thisNode, context.getRaw(), (int) recievedData.offset, (unsigned int)recievedData.length); /* once we finish the template, we *cannot* return here */ assert (!context->flags.finishedtemplate); @@ -1061,7 +1058,7 @@ esiProcessStream (clientStreamNode *thisNode, clientHttpRequest *http, HttpReply if (rep == NULL && recievedData.data == NULL && recievedData.length == 0 && !context->flags.finishedtemplate) { /* TODO: get stream status to test the entry for aborts */ /* else flush the esi processor */ - debug (86,5)("esiProcess: %p Finished reading upstream data\n", context); + debug (86,5)("esiProcess: %p Finished reading upstream data\n", context.getRaw()); /* This is correct */ context->flags.finishedtemplate = 1; } @@ -1072,13 +1069,11 @@ esiProcessStream (clientStreamNode *thisNode, clientHttpRequest *http, HttpReply /* thisNode can not happen - processing can't fail until we have data, * and when we come here we have sent data to the client */ - cbdataReferenceDone (context); return; case ESIContext::ESI_KICK_SENT: case ESIContext::ESI_KICK_INPROGRESS: - cbdataReferenceDone (context); return; case ESIContext::ESI_KICK_PENDING: @@ -1097,12 +1092,10 @@ esiProcessStream (clientStreamNode *thisNode, clientHttpRequest *http, HttpReply tempBuffer.data = &context->incoming->buf[context->incoming->len]; context->startRead(); clientStreamRead (thisNode, http, tempBuffer); - cbdataReferenceDone (context); return; } debug (86,3)("esiProcessStream: no data to send, no data to read, awaiting a callback\n"); - cbdataReferenceDone(context); } ESIContext::~ESIContext() @@ -1727,7 +1720,6 @@ esiBufferDetach (clientStreamNode *node, clientHttpRequest *http) void esiBufferRecipient (clientStreamNode *node, clientHttpRequest *http, HttpReply *rep, StoreIOBuffer recievedData) { - esiStreamContext *esiStream; /* Test preconditions */ assert (node != NULL); /* ESI TODO: handle thisNode rather than asserting @@ -1737,11 +1729,11 @@ esiBufferRecipient (clientStreamNode *node, clientHttpRequest *http, HttpReply * * itself shouldn't happen, so it stays as an * assert for now. */ assert (cbdataReferenceValid (node)); - assert (node->data != NULL); assert (node->node.next == NULL); assert (http->conn == NULL); - esiStream = (esiStreamContext *)cbdataReference (node->data); + esiStreamContext::Pointer esiStream = dynamic_cast(node->data.getRaw()); + assert (esiStream.getRaw() != NULL); /* If segments become more flexible, ignore thisNode */ assert (recievedData.length <= sizeof(esiStream->localbuffer->buf)); assert (!esiStream->finished); @@ -1760,7 +1752,6 @@ esiBufferRecipient (clientStreamNode *node, clientHttpRequest *http, HttpReply * rep = NULL; esiStream->include->fail (esiStream); esiStream->finished = 1; - cbdataReferenceDone (esiStream); httpRequestFree (http); return; } @@ -1802,7 +1793,6 @@ esiBufferRecipient (clientStreamNode *node, clientHttpRequest *http, HttpReply * debug (86,5)("Finished reading upstream data in subrequest\n"); esiStream->include->subRequestDone (esiStream, true); esiStream->finished = 1; - cbdataReferenceDone (esiStream); httpRequestFree (http); return; } @@ -1812,11 +1802,10 @@ esiBufferRecipient (clientStreamNode *node, clientHttpRequest *http, HttpReply * * we call */ if (clientHttpRequestStatus(-1, http)) { /* TODO: Does thisNode if block leak htto ? */ - esiStreamContext *temp = esiStream; - esiStream->include->fail (esiStream); + /* XXX when reviewing ESI this is the first place to look */ + node->data = NULL; esiStream->finished = 1; - cbdataReferenceDone (esiStream); - cbdataFree (temp); /* free the request */ + esiStream->include->fail (esiStream); return; }; @@ -1828,7 +1817,6 @@ esiBufferRecipient (clientStreamNode *node, clientHttpRequest *http, HttpReply * debug (86,3)("ESI subrequest finished OK\n"); esiStream->include->subRequestDone (esiStream, true); esiStream->finished = 1; - cbdataReferenceDone (esiStream); httpRequestFree (http); return; @@ -1836,7 +1824,6 @@ esiBufferRecipient (clientStreamNode *node, clientHttpRequest *http, HttpReply * debug (86,1)("ESI subrequest failed transfer\n"); esiStream->include->fail (esiStream); esiStream->finished = 1; - cbdataReferenceDone (esiStream); httpRequestFree (http); return; @@ -1869,32 +1856,56 @@ esiBufferRecipient (clientStreamNode *node, clientHttpRequest *http, HttpReply * fatal ("Hit unreachable code in esiBufferRecipient\n"); } - cbdataReferenceDone (esiStream); } /* esiStream functions */ +ESIStreamContext::~ESIStreamContext() +{ + assert (this); + freeResources(); +} + void -esiStreamContextFree (void *data) +ESIStreamContext::freeResources() { - esiStreamContext *esiStream = (esiStreamContext *)data; - assert (esiStream); - esiStream->buffer = NULL; - esiStream->localbuffer = NULL; - esiStream->include = NULL; - debug (86,5)("Freeing stream context\n"); + debug (86,5)("Freeing stream context resources.\n"); + buffer = NULL; + localbuffer = NULL; + include = NULL; } void * -_esiStreamContext::operator new (size_t count) +ESIStreamContext::operator new(size_t byteCount) { - CBDATA_INIT_TYPE_FREECB(esiStreamContext, esiStreamContextFree); - return cbdataAlloc(esiStreamContext); + assert (byteCount == sizeof (ESIStreamContext)); + CBDATA_INIT_TYPE(ESIStreamContext); + ESIStreamContext *result = cbdataAlloc(ESIStreamContext); + /* Mark result as being owned - we want the refcounter to do the + * delete call + */ + cbdataReference(result); + return result; +} + +void +ESIStreamContext::operator delete (void *address) +{ + ESIStreamContext *t = static_cast(address); + cbdataFree(t); + /* And allow the memory to be freed */ + cbdataReferenceDone (address); +} + +void +ESIStreamContext::deleteSelf() const +{ + delete this; } esiStreamContext * esiStreamContextNew (esiIncludePtr include) { - esiStreamContext *rv = new _esiStreamContext; + esiStreamContext *rv = new ESIStreamContext; rv->include = include; return rv; } @@ -2158,11 +2169,11 @@ esiInclude::esiInclude(esiInclude const &old) : parent (NULL), started (false), } void -esiInclude::Start (esiStreamContext *stream, char const *url, esiVarState *vars) +esiInclude::Start (ESIStreamContext::Pointer stream, char const *url, esiVarState *vars) { HttpHeader tempheaders; - if (!stream) + if (!stream.getRaw()) return; httpHeaderInit (&tempheaders, hoRequest); @@ -2175,7 +2186,7 @@ esiInclude::Start (esiStreamContext *stream, char const *url, esiVarState *vars) debug (86,5)("esiIncludeStart: Starting subrequest with url '%s'\n", tempUrl); - if (clientBeginRequest(METHOD_GET, tempUrl, esiBufferRecipient, esiBufferDetach, stream, &tempheaders, stream->localbuffer->buf, HTTP_REQBUF_SZ)) { + if (clientBeginRequest(METHOD_GET, tempUrl, esiBufferRecipient, esiBufferDetach, stream.getRaw(), &tempheaders, stream->localbuffer->buf, HTTP_REQBUF_SZ)) { debug (86,0) ("starting new ESI subrequest failed\n"); } @@ -2192,9 +2203,9 @@ esiInclude::esiInclude (esiTreeParentPtr aParent, int attrcount, char const **at /* Start a request for thisNode url */ debug (86,5)("esiIncludeNew: Requesting source '%s'\n",attr[i+1]); /* TODO: don't assert on thisNode, ignore the duplicate */ - assert (src == NULL); + assert (src.getRaw() == NULL); src = esiStreamContextNew (this); - assert (src != NULL); + assert (src.getRaw() != NULL); srcurl = xstrdup ( attr[i+1]); } else if (!strcmp(attr[i],"alt")) { /* Start a secondary request for thisNode url */ @@ -2202,9 +2213,9 @@ esiInclude::esiInclude (esiTreeParentPtr aParent, int attrcount, char const **at * for the src to fail */ debug (86,5)("esiIncludeNew: Requesting alternate '%s'\n",attr[i+1]); - assert (alt == NULL); /* TODO: FIXME */ + assert (alt.getRaw() == NULL); /* TODO: FIXME */ alt = esiStreamContextNew (this); - assert (alt != NULL); + assert (alt.getRaw() != NULL); alturl = xstrdup (attr[i+1]); } else if (!strcmp(attr[i],"onerror")) { if (!strcmp(attr[i+1], "continue")) { @@ -2233,12 +2244,11 @@ esiInclude::start() started = true; - if (src) { + if (src.getRaw()) { Start (src, srcurl, varState); Start (alt, alturl, varState); } else { - if (alt) - cbdataFree (alt); + alt = NULL; debug (86,1)("esiIncludeNew: esi:include with no src attributes\n"); @@ -2303,7 +2313,7 @@ esiInclude::process (int dovars) } void -esiInclude::fail (esiStreamContext *stream) +esiInclude::fail (ESIStreamContext::Pointer stream) { subRequestDone (stream, false); } @@ -2315,7 +2325,7 @@ esiInclude::dataNeeded() const } void -esiInclude::subRequestDone (esiStreamContext *stream, bool success) +esiInclude::subRequestDone (ESIStreamContext::Pointer stream, bool success) { assert (this); @@ -2336,7 +2346,7 @@ esiInclude::subRequestDone (esiStreamContext *stream, bool success) /* Fail if there is no alt being retrieved */ debug (86,3)("esiIncludeSubRequestDone: Src FAILED\n"); - if (!(alt || altcontent.getRaw())) { + if (!(alt.getRaw() || altcontent.getRaw())) { debug (86,3)("esiIncludeSubRequestDone: Include FAILED - No ALT\n"); flags.failed = 1; } else if (altcontent.getRaw()) { @@ -2357,13 +2367,13 @@ esiInclude::subRequestDone (esiStreamContext *stream, bool success) ESISegment::ListTransfer (stream->localbuffer, altcontent); /* we're done! */ - if (!(src || srccontent.getRaw())) { + if (!(src.getRaw() || srccontent.getRaw())) { /* src already failed, kick ESI processor */ debug (86,3)("esiIncludeSubRequestDone: Include PASSED - SRC already failed.\n"); flags.finished = 1; } } else { - if (!(src || srccontent.getRaw())) { + if (!(src.getRaw() || srccontent.getRaw())) { debug (86,3)("esiIncludeSubRequestDone: ALT FAILED, Include FAILED - SRC already failed\n"); /* src already failed */ flags.failed = 1; @@ -2377,7 +2387,7 @@ esiInclude::subRequestDone (esiStreamContext *stream, bool success) if (flags.finished || flags.failed) { /* Kick ESI Processor */ - debug (86,5)("esiInclude %p SubRequest %p completed, kicking processor , status %s\n", this, stream, flags.finished ? "OK" : "FAILED"); + debug (86,5)("esiInclude %p SubRequest %p completed, kicking processor , status %s\n", this, stream.getRaw(), flags.finished ? "OK" : "FAILED"); assert (parent.getRaw()); if (!flags.failed) { diff --git a/src/ESIContext.h b/src/ESIContext.h index 902159f5e8..5965c05ed3 100644 --- a/src/ESIContext.h +++ b/src/ESIContext.h @@ -1,5 +1,5 @@ /* - * $Id: ESIContext.h,v 1.1 2003/03/10 04:56:35 robertc Exp $ + * $Id: ESIContext.h,v 1.2 2003/03/15 04:17:38 robertc Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -35,11 +35,10 @@ #define SQUID_ESICONTEXT_H #include "ESIElement.h" +#include "clientStream.h" class esiVarState; -class clientStreamNode; - class ClientHttpRequest; #include "ESIParser.h" @@ -50,6 +49,7 @@ class ESIContext : public esiTreeParent, public ESIParserClient { public: + typedef RefCount Pointer; void *operator new (size_t byteCount); void operator delete (void *address); void deleteSelf() const; diff --git a/src/HttpReply.cc b/src/HttpReply.cc index e646fe6db5..b15f368083 100644 --- a/src/HttpReply.cc +++ b/src/HttpReply.cc @@ -1,6 +1,6 @@ /* - * $Id: HttpReply.cc,v 1.58 2003/03/10 04:56:36 robertc Exp $ + * $Id: HttpReply.cc,v 1.59 2003/03/15 04:17:38 robertc Exp $ * * DEBUG: section 58 HTTP Reply (Response) * AUTHOR: Alex Rousskov @@ -646,3 +646,15 @@ HttpReply::operator delete (void *address) { memPoolFree (Pool, address); } + +bool +HttpReply::isBodyTooLarge(ssize_t clen) const +{ + if (0 == maxBodySize) + return 0; /* disabled */ + + if (clen < 0) + return 0; /* unknown */ + + return (unsigned int)clen > maxBodySize; +} diff --git a/src/Makefile.am b/src/Makefile.am index e360daa005..9b00009335 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ # # Makefile for the Squid Object Cache server # -# $Id: Makefile.am,v 1.67 2003/03/13 07:39:53 hno Exp $ +# $Id: Makefile.am,v 1.68 2003/03/15 04:17:39 robertc Exp $ # # Uncomment and customize the following to suit your needs: # @@ -9,755 +9,786 @@ if USE_DNSSERVER DNSSOURCE = dns.cc -DNSSERVER = dnsserver -else -DNSSOURCE = dns_internal.cc -DNSSERVER = -endif - -if USE_SNMP -SNMPSOURCE = snmp_core.cc snmp_agent.cc -else -SNMPSOURCE = -endif - -if USE_DELAY_POOLS -DELAY_POOL_SOURCE = \ - CommonPool.h \ - CompositePoolNode.h \ - delay_pools.cc \ - DelayId.cc \ - DelayId.h \ - DelayIdComposite.h \ - DelayBucket.cc \ - DelayBucket.h \ - DelayConfig.cc \ - DelayConfig.h \ - DelayPool.cc \ - DelayPool.h \ - DelayPools.h \ - DelaySpec.cc \ - DelaySpec.h \ - DelayUser.cc \ - DelayUser.h \ - DelayVector.cc \ - DelayVector.h \ - NullDelayId.cc \ - NullDelayId.h -else -DELAY_POOL_SOURCE = -endif - -ESI_ALL_SOURCE = \ - ElementList.h \ - ESI.cc \ - ESI.h \ - ESIAttempt.h \ - ESIContext.cc \ - ESIContext.h \ - ESICustomParser.cc \ - ESICustomParser.h \ - ESIElement.h \ - ESIExcept.h \ - ESIExpatParser.cc \ - ESIExpatParser.h \ - ESIExpression.cc \ - ESILiteral.h \ - ESIParser.cc \ - ESIParser.h \ - ESISegment.cc \ - ESISegment.h \ - ESISequence.cc \ - ESISequence.h -if USE_ESI - ESI_SOURCE = $(ESI_ALL_SOURCE) -else - ESI_SOURCE = -endif - -if ENABLE_XPROF_STATS -XPROF_STATS_SOURCE = ProfStats.cc -else -XPROF_STATS_SOURCE = -endif - -if ENABLE_HTCP -HTCPSOURCE = htcp.cc -endif - -if MAKE_LEAKFINDER -LEAKFINDERSOURCE = leakfinder.cc -else -LEAKFINDERSOURCE = -endif - -if ENABLE_UNLINKD -UNLINKDSOURCE = unlinkd.cc -UNLINKD = unlinkd -else -UNLINKDSOURCE = -UNLINKD = -endif - -if ENABLE_PINGER -PINGER = pinger -else -PINGER = -endif - -if ENABLE_SSL -SSLSOURCE = \ - ACLCertificateData.cc \ - ACLCertificateData.h \ - ACLCertificate.cc \ - ACLCertificate.h \ - ssl_support.cc -else -SSLSOURCE = -endif - -if ENABLE_WIN32SPECIFIC -WIN32SOURCE = win32.cc -else -WIN32SOURCE = -endif - -if ENABLE_IDENT -IDENTSOURCE = ACLIdent.cc ACLIdent.h ident.cc -else -IDENTSOURCE = -endif - -if ENABLE_ARP_ACL -ARP_ACL_SOURCE = ACLARP.cc ACLARP.h -else -ARP_ACL_SOURCE = -endif - -AM_CFLAGS = @SQUID_CFLAGS@ -AM_CXXFLAGS = @SQUID_CXXFLAGS@ - -SUBDIRS = fs repl auth - -INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include -I$(top_srcdir)/lib/libTrie/include - -EXTRA_PROGRAMS = \ - unlinkd \ - pinger \ - dnsserver \ - recv-announce \ - ufsdump - -noinst_PROGRAMS = \ - cf_gen - -sbin_PROGRAMS = \ - squid - -bin_PROGRAMS = \ - squidclient - - -libexec_PROGRAMS = \ - $(PINGER) \ - $(DNSSERVER) \ - $(UNLINKD) \ - cachemgr$(CGIEXT) - -cf_gen_SOURCES = cf_gen.cc defines.h -nodist_cf_gen_HEADER = cf_gen_defines.h -cf_gen.$(OBJEXT): cf_gen_defines.h -squidclient_SOURCES = client.cc -cachemgr__CGIEXT__SOURCES = cachemgr.cc - -EXTRA_squid_SOURCES = \ - $(ARP_ACL_SOURCE) \ - $(DELAY_POOL_SOURCE) \ - dns.cc \ - dnsserver.cc \ - dns_internal.cc \ - htcp.cc \ - $(ESI_ALL_SOURCE) \ - ProfStats.cc \ - leakfinder.cc \ - snmp_core.cc \ - snmp_agent.cc \ - unlinkd.cc \ - ssl_support.cc \ - ssl_support.h \ - win32.cc - -squid_ACLSOURCES = \ - $(ARP_ACL_SOURCE) \ - ACLASN.cc \ - ACLASN.h \ - ACLDestinationASN.h \ - ACLSourceASN.h \ - ACLBrowser.cc \ - ACLBrowser.h \ - ACLData.h \ - ACLDestinationDomain.cc \ - ACLDestinationDomain.h \ - ACLDestinationIP.cc \ - ACLDestinationIP.h \ - ACLDomainData.h \ - ACLDomainData.cc \ - ACLIntRange.cc \ - ACLIntRange.h \ - ACLIP.cc \ - ACLIP.h \ - ACLMaxConnection.cc \ - ACLMaxConnection.h \ - ACLMaxUserIP.cc \ - ACLMaxUserIP.h \ - ACLMethod.cc \ - ACLMethod.h \ - ACLMethodData.cc \ - ACLMethodData.h \ - ACLMyIP.cc \ - ACLMyIP.h \ - ACLMyPort.cc \ - ACLMyPort.h \ - ACLProtocol.cc \ - ACLProtocol.h \ - ACLProtocolData.cc \ - ACLProtocolData.h \ - ACLProxyAuth.cc \ - ACLProxyAuth.h \ - ACLReferer.cc \ - ACLReferer.h \ - ACLRegexData.cc \ - ACLRegexData.h \ - ACLReplyHeaderStrategy.h \ - ACLReplyMIMEType.cc \ - ACLReplyMIMEType.h \ - ACLRequestHeaderStrategy.h \ - ACLRequestMIMEType.cc \ - ACLRequestMIMEType.h \ - ACLSourceDomain.cc \ - ACLSourceDomain.h \ - ACLSourceIP.cc \ - ACLSourceIP.h \ - ACLStrategised.cc \ - ACLStrategised.h \ - ACLStrategy.h \ - ACLStringData.cc \ - ACLStringData.h \ - ACLTime.cc \ - ACLTime.h \ - ACLTimeData.cc \ - ACLTimeData.h \ - ACLUrl.cc \ - ACLUrl.h \ - ACLUrlPath.cc \ - ACLUrlPath.h \ - ACLUrlPort.cc \ - ACLUrlPort.h \ - ACLUserData.cc \ - ACLUserData.h - -squid_SOURCES = \ - access_log.cc \ - acl.cc \ - ACL.h \ - ACLChecklist.cc \ - ACLChecklist.h \ - $(squid_ACLSOURCES) \ - asn.cc \ - authenticate.cc \ - authenticate.h \ - cache_cf.cc \ - CacheDigest.cc \ - cache_manager.cc \ - carp.cc \ - cbdata.cc \ - client_db.cc \ - client_side.cc \ - client_side.h \ - client_side_reply.cc \ - client_side_request.cc \ - client_side_request.h \ - clientStream.cc \ - clientStream.h \ - comm.cc \ - comm.h \ - comm_select.cc \ - comm_poll.cc \ - comm_kqueue.cc \ - comm_epoll.cc \ - CommRead.h \ - ConfigParser.h \ - ConnectionDetail.h \ - debug.cc \ - Debug.h \ - defines.h \ - $(DELAY_POOL_SOURCE) \ - disk.cc \ - $(DNSSOURCE) \ - enums.h \ - errorpage.cc \ - $(ESI_SOURCE) \ - ETag.cc \ - event.cc \ - external_acl.cc \ - ExternalACL.h \ - fd.cc \ - fde.cc \ - fde.h \ - filemap.cc \ - forward.cc \ - fqdncache.cc \ - ftp.cc \ - Generic.h \ - globals.h \ - gopher.cc \ - helper.cc \ - $(HTCPSOURCE) \ - http.cc \ - http.h \ - HttpStatusLine.cc \ - HttpHdrCc.cc \ - HttpHdrRange.cc \ - HttpHdrSc.cc \ - HttpHdrScTarget.cc \ - HttpHdrContRange.cc \ - HttpHdrContRange.h \ - HttpHeader.cc \ - HttpHeader.h \ - HttpHeaderRange.h \ - HttpHeaderTools.cc \ - HttpBody.cc \ - HttpMsg.cc \ - HttpReply.cc \ - HttpReply.h \ - HttpRequest.cc \ - HttpRequest.h \ - icmp.cc \ - ICP.h \ - icp_v2.cc \ - icp_v3.cc \ - $(IDENTSOURCE) \ - int.cc \ - internal.cc \ - ipc.cc \ - ipcache.cc \ - IPInterception.cc \ - IPInterception.h \ - $(LEAKFINDERSOURCE) \ - logfile.cc \ - main.cc \ - mem.cc \ - mem_node.cc \ - mem_node.h \ - Mem.h \ - MemBuf.cc \ - MemObject.cc \ - MemObject.h \ - mime.cc \ - multicast.cc \ - neighbors.cc \ - net_db.cc \ - Packer.cc \ - $(XPROF_STATS_SOURCE) \ - pconn.cc \ - peer_digest.cc \ - peer_select.cc \ - protos.h \ - redirect.cc \ - referer.cc \ - refresh.cc \ - send-announce.cc \ - $(SNMPSOURCE) \ - squid.h \ - tunnel.cc \ - $(SSLSOURCE) \ - stat.cc \ - StatHist.cc \ - String.cc \ - stmem.cc \ - stmem.h \ - store.cc \ - Store.h \ - store_io.cc \ - StoreIOBuffer.h \ - StoreIOState.cc \ - StoreIOState.h \ - store_client.cc \ - StoreClient.h \ - store_digest.cc \ - store_dir.cc \ - store_key_md5.cc \ - store_log.cc \ - store_rebuild.cc \ - store_swapin.cc \ - store_swapmeta.cc \ - store_swapout.cc \ - StoreMeta.cc \ - StoreMeta.h \ - StoreMetaMD5.cc \ - StoreMetaMD5.h \ - StoreMetaSTD.cc \ - StoreMetaSTD.h \ - StoreMetaUnpacker.cc \ - StoreMetaUnpacker.h \ - StoreMetaURL.cc \ - StoreMetaURL.h \ - StoreMetaVary.cc \ - StoreMetaVary.h \ - structs.h \ - SwapDir.cc \ - SwapDir.h \ - tools.cc \ - typedefs.h \ - ufscommon.cc \ - ufscommon.h \ - $(UNLINKDSOURCE) \ - url.cc \ - urn.cc \ - useragent.cc \ - wais.cc \ - wccp.cc \ - whois.cc \ - $(WIN32SOURCE) - -noinst_HEADERS = MemBuf.cci \ - MemBuf.h \ - Store.cci \ - String.cci \ - SquidString.h \ - ufscommon.cci - -nodist_squid_SOURCES = \ - repl_modules.cc \ - auth_modules.cc \ - store_modules.cc \ - cf_parser.h \ - globals.cc \ - string_arrays.c - -squid_LDADD = \ - -L../lib \ - @XTRA_OBJS@ \ - @REPL_OBJS@ \ - @STORE_OBJS@ \ - @AUTH_OBJS@ \ - @CRYPTLIB@ \ - @REGEXLIB@ \ - @SNMPLIB@ \ - @LIB_MALLOC@ \ - @SSLLIB@ \ - -lmiscutil \ - @XTRA_LIBS@ \ - @EPOLL_LIBS@ -squid_DEPENDENCIES = $(top_builddir)/lib/libmiscutil.a @STORE_OBJS@ - -unlinkd_SOURCES = unlinkd.cc -unlinkd_CXXFLAGS = -DUNLINK_DAEMON - -pinger_SOURCES = \ - pinger.cc \ - debug.cc - -dnsserver_SOURCES = dnsserver.cc -recv_announce_SOURCES = recv-announce.cc - -ufsdump_SOURCES = debug.cc \ - int.cc \ - ufsdump.cc \ - store.cc \ - StoreMeta.cc \ - StoreMeta.h \ - StoreMetaMD5.cc \ - StoreMetaMD5.h \ - StoreMetaSTD.cc \ - StoreMetaSTD.h \ - StoreMetaUnpacker.cc \ - StoreMetaUnpacker.h \ - StoreMetaURL.cc \ - StoreMetaURL.h \ - StoreMetaVary.cc \ - StoreMetaVary.h \ - access_log.cc \ - acl.cc \ - ACLChecklist.cc \ - $(squid_ACLSOURCES) \ - ACLChecklist.cc \ - asn.cc \ - authenticate.cc \ - cache_cf.cc \ - CacheDigest.cc \ - cache_manager.cc \ - carp.cc \ - cbdata.cc \ - client_db.cc \ - client_side.cc \ - client_side_reply.cc \ - client_side_request.cc \ - client_side_request.h \ - clientStream.cc \ - clientStream.h \ - comm.cc \ - comm.h \ - comm_select.cc \ - comm_poll.cc \ - comm_kqueue.cc \ - comm_epoll.cc \ - defines.h \ - $(DELAY_POOL_SOURCE) \ - disk.cc \ - $(DNSSOURCE) \ - enums.h \ - errorpage.cc \ - $(ESI_SOURCE) \ - ETag.cc \ - event.cc \ - external_acl.cc \ - fd.cc \ - fde.cc \ - fde.h \ - filemap.cc \ - forward.cc \ - fqdncache.cc \ - ftp.cc \ - gopher.cc \ - helper.cc \ - $(HTCPSOURCE) \ - http.cc \ - HttpStatusLine.cc \ - HttpHdrCc.cc \ - HttpHdrRange.cc \ - HttpHdrSc.cc \ - HttpHdrScTarget.cc \ - HttpHdrContRange.cc \ - HttpHeader.cc \ - HttpHeaderTools.cc \ - HttpBody.cc \ - HttpMsg.cc \ - HttpReply.cc \ - HttpRequest.cc \ - HttpRequest.h \ - icmp.cc \ - icp_v2.cc \ - icp_v3.cc \ - $(IDENTSOURCE) \ - internal.cc \ - ipc.cc \ - ipcache.cc \ - IPInterception.cc \ - IPInterception.h \ - $(LEAKFINDERSOURCE) \ - logfile.cc \ - mem.cc \ - mem_node.cc \ - mem_node.h \ - Mem.h \ - MemBuf.cc \ - MemObject.cc \ - MemObject.h \ - mime.cc \ - multicast.cc \ - neighbors.cc \ - net_db.cc \ - Packer.cc \ - $(XPROF_STATS_SOURCE) \ - pconn.cc \ - peer_digest.cc \ - peer_select.cc \ - protos.h \ - redirect.cc \ - referer.cc \ - refresh.cc \ - send-announce.cc \ - $(SNMPSOURCE) \ - squid.h \ - $(SSLSOURCE) \ - tunnel.cc \ - stat.cc \ - StatHist.cc \ - String.cc \ - stmem.cc \ - store_io.cc \ - StoreIOBuffer.h \ - StoreIOState.cc \ - store_client.cc \ - StoreClient.h \ - store_digest.cc \ - store_dir.cc \ - store_key_md5.cc \ - store_log.cc \ - store_rebuild.cc \ - store_swapin.cc \ - store_swapmeta.cc \ - store_swapout.cc \ - structs.h \ - SwapDir.cc \ - tools.cc \ - typedefs.h \ - ufscommon.cc \ - ufscommon.h \ - $(UNLINKDSOURCE) \ - url.cc \ - urn.cc \ - useragent.cc \ - wais.cc \ - wccp.cc \ - whois.cc \ - $(WIN32SOURCE) -ufsdump_LDADD = \ - -L../lib \ - @XTRA_OBJS@ \ - @REPL_OBJS@ \ - @STORE_OBJS@ \ - @AUTH_OBJS@ \ - @CRYPTLIB@ \ - @REGEXLIB@ \ - @SNMPLIB@ \ - @LIB_MALLOC@ \ - @SSLLIB@ \ - -lmiscutil \ - @XTRA_LIBS@ \ - @EPOLL_LIBS@ -ufsdump_DEPENDENCIES = $(top_builddir)/lib/libmiscutil.a -nodist_ufsdump_SOURCES = \ - repl_modules.cc \ - auth_modules.cc \ - store_modules.cc \ - cf_parser.h \ - globals.cc \ - string_arrays.c - -nodist_pinger_SOURCES = \ - globals.cc - -BUILT_SOURCES = \ - cf_gen_defines.h \ - cf_parser.h \ - globals.cc \ - string_arrays.c \ - repl_modules.cc \ - auth_modules.cc \ - store_modules.cc - -sysconf_DATA = \ - squid.conf.default \ - mime.conf.default - -data_DATA = \ - mib.txt - -LDADD = -L../lib -lmiscutil @XTRA_LIBS@ @EPOLL_LIBS@ - -EXTRA_DIST = \ - cf_gen_defines \ - cf.data.pre \ - mk-globals-c.pl \ - mk-string-arrays.pl \ - auth_modules.sh \ - store_modules.sh \ - repl_modules.sh \ - mib.txt \ - mime.conf.default - -DEFAULT_PREFIX = $(prefix) -DEFAULT_CONFIG_FILE = $(sysconfdir)/squid.conf -DEFAULT_MIME_TABLE = $(sysconfdir)/mime.conf -DEFAULT_DNSSERVER = $(libexecdir)/dnsserver$(EXEEXT) -DEFAULT_LOG_PREFIX = $(localstatedir)/logs -DEFAULT_CACHE_LOG = $(DEFAULT_LOG_PREFIX)/cache.log -DEFAULT_ACCESS_LOG = $(DEFAULT_LOG_PREFIX)/access.log -DEFAULT_STORE_LOG = $(DEFAULT_LOG_PREFIX)/store.log -DEFAULT_PID_FILE = $(DEFAULT_LOG_PREFIX)/squid.pid -DEFAULT_SWAP_DIR = $(localstatedir)/cache -DEFAULT_PINGER = $(libexecdir)/pinger$(EXEEXT) -DEFAULT_UNLINKD = $(libexecdir)/unlinkd$(EXEEXT) -DEFAULT_DISKD = $(libexecdir)/diskd$(EXEEXT) -DEFAULT_ICON_DIR = $(datadir)/icons -DEFAULT_ERROR_DIR = $(datadir)/errors/@ERR_DEFAULT_LANGUAGE@ -DEFAULT_MIB_PATH = $(datadir)/mib.txt -DEFAULT_HOSTS = @OPT_DEFAULT_HOSTS@ - -DEFS = @DEFS@ -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\" - -$(OBJS): $(top_srcdir)/include/version.h ../include/autoconf.h - -snmp_core.o snmp_agent.o: ../snmplib/libsnmp.a $(top_srcdir)/include/cache_snmp.h - -globals.cc: globals.h mk-globals-c.pl - $(PERL) $(srcdir)/mk-globals-c.pl < $(srcdir)/globals.h > $@ - -string_arrays.c: enums.h mk-string-arrays.pl - $(PERL) $(srcdir)/mk-string-arrays.pl < $(srcdir)/enums.h > $@ - -cache_diff: cache_diff.o debug.o globals.o store_key_md5.o - $(CC) -o $@ $(LDFLAGS) $@.o debug.o globals.o store_key_md5.o $(STD_APP_LIBS) - -test_cache_digest: test_cache_digest.o CacheDigest.o debug.o globals.o store_key_md5.o - $(CC) -o $@ $(LDFLAGS) $@.o CacheDigest.o debug.o globals.o store_key_md5.o $(STD_APP_LIBS) + DNSSERVER = dnsserver + else + DNSSOURCE = dns_internal.cc + DNSSERVER = + endif + + if USE_SNMP + SNMPSOURCE = snmp_core.cc snmp_agent.cc + else + SNMPSOURCE = + endif + + if USE_DELAY_POOLS + DELAY_POOL_SOURCE = \ + CommonPool.h \ + CompositePoolNode.h \ + delay_pools.cc \ + DelayId.cc \ + DelayId.h \ + DelayIdComposite.h \ + DelayBucket.cc \ + DelayBucket.h \ + DelayConfig.cc \ + DelayConfig.h \ + DelayPool.cc \ + DelayPool.h \ + DelayPools.h \ + DelaySpec.cc \ + DelaySpec.h \ + DelayUser.cc \ + DelayUser.h \ + DelayVector.cc \ + DelayVector.h \ + NullDelayId.cc \ + NullDelayId.h + else + DELAY_POOL_SOURCE = + endif + + ESI_ALL_SOURCE = \ + ElementList.h \ + ESI.cc \ + ESI.h \ + ESIAttempt.h \ + ESIContext.cc \ + ESIContext.h \ + ESICustomParser.cc \ + ESICustomParser.h \ + ESIElement.h \ + ESIExcept.h \ + ESIExpatParser.cc \ + ESIExpatParser.h \ + ESIExpression.cc \ + ESILiteral.h \ + ESIParser.cc \ + ESIParser.h \ + ESISegment.cc \ + ESISegment.h \ + ESISequence.cc \ + ESISequence.h + if USE_ESI + ESI_SOURCE = $(ESI_ALL_SOURCE) + else + ESI_SOURCE = + endif + + if ENABLE_XPROF_STATS + XPROF_STATS_SOURCE = ProfStats.cc + else + XPROF_STATS_SOURCE = + endif + + if ENABLE_HTCP + HTCPSOURCE = htcp.cc + endif + + if MAKE_LEAKFINDER + LEAKFINDERSOURCE = leakfinder.cc + else + LEAKFINDERSOURCE = + endif + + if ENABLE_UNLINKD + UNLINKDSOURCE = unlinkd.cc + UNLINKD = unlinkd + else + UNLINKDSOURCE = + UNLINKD = + endif + + if ENABLE_PINGER + PINGER = pinger + else + PINGER = + endif + + if ENABLE_SSL + SSLSOURCE = \ + ACLCertificateData.cc \ + ACLCertificateData.h \ + ACLCertificate.cc \ + ACLCertificate.h \ + ssl_support.cc + else + SSLSOURCE = + endif + + if ENABLE_WIN32SPECIFIC + WIN32SOURCE = win32.cc + else + WIN32SOURCE = + endif + + if ENABLE_IDENT + IDENTSOURCE = ACLIdent.cc ACLIdent.h ident.cc + else + IDENTSOURCE = + endif + + if ENABLE_ARP_ACL + ARP_ACL_SOURCE = ACLARP.cc ACLARP.h + else + ARP_ACL_SOURCE = + endif + + AM_CFLAGS = @SQUID_CFLAGS@ + AM_CXXFLAGS = @SQUID_CXXFLAGS@ + + SUBDIRS = fs repl auth + + INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include -I$(top_srcdir)/lib/libTrie/include + + EXTRA_PROGRAMS = \ + unlinkd \ + pinger \ + dnsserver \ + recv-announce \ + ufsdump + + noinst_PROGRAMS = \ + cf_gen + + sbin_PROGRAMS = \ + squid + + bin_PROGRAMS = \ + squidclient + + + libexec_PROGRAMS = \ + $(PINGER) \ + $(DNSSERVER) \ + $(UNLINKD) \ + cachemgr$(CGIEXT) + + cf_gen_SOURCES = cf_gen.cc defines.h + nodist_cf_gen_HEADER = cf_gen_defines.h + cf_gen.$(OBJEXT): cf_gen_defines.h + squidclient_SOURCES = client.cc + cachemgr__CGIEXT__SOURCES = cachemgr.cc + + EXTRA_squid_SOURCES = \ + $(ARP_ACL_SOURCE) \ + $(DELAY_POOL_SOURCE) \ + dns.cc \ + dnsserver.cc \ + dns_internal.cc \ + htcp.cc \ + $(ESI_ALL_SOURCE) \ + ProfStats.cc \ + leakfinder.cc \ + snmp_core.cc \ + snmp_agent.cc \ + unlinkd.cc \ + ssl_support.cc \ + ssl_support.h \ + win32.cc + + squid_ACLSOURCES = \ + $(ARP_ACL_SOURCE) \ + ACLASN.cc \ + ACLASN.h \ + ACLDestinationASN.h \ + ACLSourceASN.h \ + ACLBrowser.cc \ + ACLBrowser.h \ + ACLData.h \ + ACLDestinationDomain.cc \ + ACLDestinationDomain.h \ + ACLDestinationIP.cc \ + ACLDestinationIP.h \ + ACLDomainData.h \ + ACLDomainData.cc \ + ACLIntRange.cc \ + ACLIntRange.h \ + ACLIP.cc \ + ACLIP.h \ + ACLMaxConnection.cc \ + ACLMaxConnection.h \ + ACLMaxUserIP.cc \ + ACLMaxUserIP.h \ + ACLMethod.cc \ + ACLMethod.h \ + ACLMethodData.cc \ + ACLMethodData.h \ + ACLMyIP.cc \ + ACLMyIP.h \ + ACLMyPort.cc \ + ACLMyPort.h \ + ACLProtocol.cc \ + ACLProtocol.h \ + ACLProtocolData.cc \ + ACLProtocolData.h \ + ACLProxyAuth.cc \ + ACLProxyAuth.h \ + ACLReferer.cc \ + ACLReferer.h \ + ACLRegexData.cc \ + ACLRegexData.h \ + ACLReplyHeaderStrategy.h \ + ACLReplyMIMEType.cc \ + ACLReplyMIMEType.h \ + ACLRequestHeaderStrategy.h \ + ACLRequestMIMEType.cc \ + ACLRequestMIMEType.h \ + ACLSourceDomain.cc \ + ACLSourceDomain.h \ + ACLSourceIP.cc \ + ACLSourceIP.h \ + ACLStrategised.cc \ + ACLStrategised.h \ + ACLStrategy.h \ + ACLStringData.cc \ + ACLStringData.h \ + ACLTime.cc \ + ACLTime.h \ + ACLTimeData.cc \ + ACLTimeData.h \ + ACLUrl.cc \ + ACLUrl.h \ + ACLUrlPath.cc \ + ACLUrlPath.h \ + ACLUrlPort.cc \ + ACLUrlPort.h \ + ACLUserData.cc \ + ACLUserData.h + + squid_SOURCES = \ + access_log.cc \ + acl.cc \ + ACL.h \ + ACLChecklist.cc \ + ACLChecklist.h \ + $(squid_ACLSOURCES) \ + asn.cc \ + authenticate.cc \ + authenticate.h \ + cache_cf.cc \ + CacheDigest.cc \ + cache_manager.cc \ + carp.cc \ + cbdata.cc \ + client_db.cc \ + client_side.cc \ + client_side.h \ + client_side_reply.cc \ + client_side_request.cc \ + client_side_request.h \ + clientStream.cc \ + clientStream.h \ + comm.cc \ + comm.h \ + comm_select.cc \ + comm_poll.cc \ + comm_kqueue.cc \ + comm_epoll.cc \ + CommRead.h \ + ConfigParser.h \ + ConnectionDetail.h \ + debug.cc \ + Debug.h \ + defines.h \ + $(DELAY_POOL_SOURCE) \ + disk.cc \ + $(DNSSOURCE) \ + enums.h \ + errorpage.cc \ + $(ESI_SOURCE) \ + ETag.cc \ + event.cc \ + external_acl.cc \ + ExternalACL.h \ + fd.cc \ + fde.cc \ + fde.h \ + filemap.cc \ + forward.cc \ + fqdncache.cc \ + ftp.cc \ + Generic.h \ + globals.h \ + gopher.cc \ + helper.cc \ + $(HTCPSOURCE) \ + http.cc \ + http.h \ + HttpStatusLine.cc \ + HttpHdrCc.cc \ + HttpHdrRange.cc \ + HttpHdrSc.cc \ + HttpHdrScTarget.cc \ + HttpHdrContRange.cc \ + HttpHdrContRange.h \ + HttpHeader.cc \ + HttpHeader.h \ + HttpHeaderRange.h \ + HttpHeaderTools.cc \ + HttpBody.cc \ + HttpMsg.cc \ + HttpReply.cc \ + HttpReply.h \ + HttpRequest.cc \ + HttpRequest.h \ + icmp.cc \ + ICP.h \ + icp_v2.cc \ + icp_v3.cc \ + $(IDENTSOURCE) \ + int.cc \ + internal.cc \ + ipc.cc \ + ipcache.cc \ + IPInterception.cc \ + IPInterception.h \ + $(LEAKFINDERSOURCE) \ + logfile.cc \ + main.cc \ + mem.cc \ + mem_node.cc \ + mem_node.h \ + Mem.h \ + MemBuf.cc \ + MemObject.cc \ + MemObject.h \ + mime.cc \ + multicast.cc \ + neighbors.cc \ + net_db.cc \ + Packer.cc \ + $(XPROF_STATS_SOURCE) \ + pconn.cc \ + peer_digest.cc \ + peer_select.cc \ + protos.h \ + redirect.cc \ + referer.cc \ + refresh.cc \ + send-announce.cc \ + $(SNMPSOURCE) \ + squid.h \ + tunnel.cc \ + $(SSLSOURCE) \ + stat.cc \ + StatHist.cc \ + String.cc \ + stmem.cc \ + stmem.h \ + store.cc \ + Store.h \ + store_io.cc \ + StoreIOBuffer.h \ + StoreIOState.cc \ + StoreIOState.h \ + store_client.cc \ + StoreClient.h \ + store_digest.cc \ + store_dir.cc \ + store_key_md5.cc \ + store_log.cc \ + store_rebuild.cc \ + store_swapin.cc \ + store_swapmeta.cc \ + store_swapout.cc \ + StoreMeta.cc \ + StoreMeta.h \ + StoreMetaMD5.cc \ + StoreMetaMD5.h \ + StoreMetaSTD.cc \ + StoreMetaSTD.h \ + StoreMetaUnpacker.cc \ + StoreMetaUnpacker.h \ + StoreMetaURL.cc \ + StoreMetaURL.h \ + StoreMetaVary.cc \ + StoreMetaVary.h \ + structs.h \ + SwapDir.cc \ + SwapDir.h \ + tools.cc \ + typedefs.h \ + ufscommon.cc \ + ufscommon.h \ + $(UNLINKDSOURCE) \ + url.cc \ + urn.cc \ + useragent.cc \ + wais.cc \ + wccp.cc \ + whois.cc \ + $(WIN32SOURCE) + + noinst_HEADERS = MemBuf.cci \ + MemBuf.h \ + Store.cci \ + String.cci \ + SquidString.h \ + ufscommon.cci + + nodist_squid_SOURCES = \ + repl_modules.cc \ + auth_modules.cc \ + store_modules.cc \ + cf_parser.h \ + globals.cc \ + string_arrays.c + + squid_LDADD = \ + -L../lib \ + @XTRA_OBJS@ \ + @REPL_OBJS@ \ + @STORE_OBJS@ \ + @AUTH_OBJS@ \ + @CRYPTLIB@ \ + @REGEXLIB@ \ + @SNMPLIB@ \ + @LIB_MALLOC@ \ + @SSLLIB@ \ + -lmiscutil \ + @XTRA_LIBS@ \ + @EPOLL_LIBS@ + squid_DEPENDENCIES = $(top_builddir)/lib/libmiscutil.a @STORE_OBJS@ + + unlinkd_SOURCES = unlinkd.cc + unlinkd_CXXFLAGS = -DUNLINK_DAEMON + + pinger_SOURCES = \ + pinger.cc \ + debug.cc + + dnsserver_SOURCES = dnsserver.cc + recv_announce_SOURCES = recv-announce.cc + + ufsdump_SOURCES = debug.cc \ + int.cc \ + ufsdump.cc \ + store.cc \ + StoreMeta.cc \ + StoreMeta.h \ + StoreMetaMD5.cc \ + StoreMetaMD5.h \ + StoreMetaSTD.cc \ + StoreMetaSTD.h \ + StoreMetaUnpacker.cc \ + StoreMetaUnpacker.h \ + StoreMetaURL.cc \ + StoreMetaURL.h \ + StoreMetaVary.cc \ + StoreMetaVary.h \ + access_log.cc \ + acl.cc \ + ACLChecklist.cc \ + $(squid_ACLSOURCES) \ + asn.cc \ + authenticate.cc \ + cache_cf.cc \ + CacheDigest.cc \ + cache_manager.cc \ + carp.cc \ + cbdata.cc \ + client_db.cc \ + client_side.cc \ + client_side_reply.cc \ + client_side_request.cc \ + client_side_request.h \ + clientStream.cc \ + clientStream.h \ + comm.cc \ + comm.h \ + comm_select.cc \ + comm_poll.cc \ + comm_kqueue.cc \ + comm_epoll.cc \ + defines.h \ + $(DELAY_POOL_SOURCE) \ + disk.cc \ + $(DNSSOURCE) \ + enums.h \ + errorpage.cc \ + $(ESI_SOURCE) \ + ETag.cc \ + event.cc \ + external_acl.cc \ + fd.cc \ + fde.cc \ + fde.h \ + filemap.cc \ + forward.cc \ + fqdncache.cc \ + ftp.cc \ + gopher.cc \ + helper.cc \ + $(HTCPSOURCE) \ + http.cc \ + HttpStatusLine.cc \ + HttpHdrCc.cc \ + HttpHdrRange.cc \ + HttpHdrSc.cc \ + HttpHdrScTarget.cc \ + HttpHdrContRange.cc \ + HttpHeader.cc \ + HttpHeaderTools.cc \ + HttpBody.cc \ + HttpMsg.cc \ + HttpReply.cc \ + HttpRequest.cc \ + HttpRequest.h \ + icmp.cc \ + icp_v2.cc \ + icp_v3.cc \ + $(IDENTSOURCE) \ + internal.cc \ + ipc.cc \ + ipcache.cc \ + IPInterception.cc \ + IPInterception.h \ + $(LEAKFINDERSOURCE) \ + logfile.cc \ + mem.cc \ + mem_node.cc \ + mem_node.h \ + Mem.h \ + MemBuf.cc \ + MemObject.cc \ + MemObject.h \ + mime.cc \ + multicast.cc \ + neighbors.cc \ + net_db.cc \ + Packer.cc \ + $(XPROF_STATS_SOURCE) \ + pconn.cc \ + peer_digest.cc \ + peer_select.cc \ + protos.h \ + redirect.cc \ + referer.cc \ + refresh.cc \ + send-announce.cc \ + $(SNMPSOURCE) \ + squid.h \ + $(SSLSOURCE) \ + tunnel.cc \ + stat.cc \ + StatHist.cc \ + String.cc \ + stmem.cc \ + store_io.cc \ + StoreIOBuffer.h \ + StoreIOState.cc \ + store_client.cc \ + StoreClient.h \ + store_digest.cc \ + store_dir.cc \ + store_key_md5.cc \ + store_log.cc \ + store_rebuild.cc \ + store_swapin.cc \ + store_swapmeta.cc \ + store_swapout.cc \ + structs.h \ + SwapDir.cc \ + tools.cc \ + typedefs.h \ + ufscommon.cc \ + ufscommon.h \ + $(UNLINKDSOURCE) \ + url.cc \ + urn.cc \ + useragent.cc \ + wais.cc \ + wccp.cc \ + whois.cc \ + $(WIN32SOURCE) + ufsdump_LDADD = \ + -L../lib \ + @XTRA_OBJS@ \ + @REPL_OBJS@ \ + @STORE_OBJS@ \ + @AUTH_OBJS@ \ + @CRYPTLIB@ \ + @REGEXLIB@ \ + @SNMPLIB@ \ + @LIB_MALLOC@ \ + @SSLLIB@ \ + -lmiscutil \ + @XTRA_LIBS@ \ + @EPOLL_LIBS@ + ufsdump_DEPENDENCIES = $(top_builddir)/lib/libmiscutil.a + nodist_ufsdump_SOURCES = \ + repl_modules.cc \ + auth_modules.cc \ + store_modules.cc \ + cf_parser.h \ + globals.cc \ + string_arrays.c + + nodist_pinger_SOURCES = \ + globals.cc + + BUILT_SOURCES = \ + cf_gen_defines.h \ + cf_parser.h \ + globals.cc \ + string_arrays.c \ + repl_modules.cc \ + auth_modules.cc \ + store_modules.cc + + sysconf_DATA = \ + squid.conf.default \ + mime.conf.default + + data_DATA = \ + mib.txt + + LDADD = -L../lib -lmiscutil @XTRA_LIBS@ @EPOLL_LIBS@ + + EXTRA_DIST = \ + cf_gen_defines \ + cf.data.pre \ + mk-globals-c.pl \ + mk-string-arrays.pl \ + auth_modules.sh \ + store_modules.sh \ + repl_modules.sh \ + mib.txt \ + mime.conf.default + + DEFAULT_PREFIX = $(prefix) + DEFAULT_CONFIG_FILE = $(sysconfdir)/squid.conf + DEFAULT_MIME_TABLE = $(sysconfdir)/mime.conf + DEFAULT_DNSSERVER = $(libexecdir)/dnsserver$(EXEEXT) + DEFAULT_LOG_PREFIX = $(localstatedir)/logs + DEFAULT_CACHE_LOG = $(DEFAULT_LOG_PREFIX)/cache.log + DEFAULT_ACCESS_LOG = $(DEFAULT_LOG_PREFIX)/access.log + DEFAULT_STORE_LOG = $(DEFAULT_LOG_PREFIX)/store.log + DEFAULT_PID_FILE = $(DEFAULT_LOG_PREFIX)/squid.pid + DEFAULT_SWAP_DIR = $(localstatedir)/cache + DEFAULT_PINGER = $(libexecdir)/pinger$(EXEEXT) + DEFAULT_UNLINKD = $(libexecdir)/unlinkd$(EXEEXT) + DEFAULT_DISKD = $(libexecdir)/diskd$(EXEEXT) + DEFAULT_ICON_DIR = $(datadir)/icons + DEFAULT_ERROR_DIR = $(datadir)/errors/@ERR_DEFAULT_LANGUAGE@ + DEFAULT_MIB_PATH = $(datadir)/mib.txt + DEFAULT_HOSTS = @OPT_DEFAULT_HOSTS@ + + DEFS = @DEFS@ -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\" + + $(OBJS): $(top_srcdir)/include/version.h ../include/autoconf.h + + snmp_core.o snmp_agent.o: ../snmplib/libsnmp.a $(top_srcdir)/include/cache_snmp.h + + globals.cc: globals.h mk-globals-c.pl + $(PERL) $(srcdir)/mk-globals-c.pl < $(srcdir)/globals.h > $@ + + string_arrays.c: enums.h mk-string-arrays.pl + $(PERL) $(srcdir)/mk-string-arrays.pl < $(srcdir)/enums.h > $@ + + cache_diff: cache_diff.o debug.o globals.o store_key_md5.o + $(CC) -o $@ $(LDFLAGS) $@.o debug.o globals.o store_key_md5.o $(STD_APP_LIBS) + + test_cache_digest: test_cache_digest.o CacheDigest.o debug.o globals.o store_key_md5.o + $(CC) -o $@ $(LDFLAGS) $@.o CacheDigest.o debug.o globals.o store_key_md5.o $(STD_APP_LIBS) ## If autodependency works well this is not needed anymore -cache_cf.o: cf_parser.h + cache_cf.o: cf_parser.h -squid.conf.default: cf_parser.h - $(SHELL) -c "test -f squid.conf.default || ./cf_gen cf.data" + squid.conf.default: cf_parser.h + $(SHELL) -c "test -f squid.conf.default || ./cf_gen cf.data" -cf_parser.h: cf.data cf_gen$(EXEEXT) - ./cf_gen cf.data + cf_parser.h: cf.data cf_gen$(EXEEXT) + ./cf_gen cf.data -cf_gen_defines.h: $(srcdir)/cf_gen_defines $(srcdir)/cf.data.pre - awk -f $(srcdir)/cf_gen_defines <$(srcdir)/cf.data.pre >cf_gen_defines.h + cf_gen_defines.h: $(srcdir)/cf_gen_defines $(srcdir)/cf.data.pre + awk -f $(srcdir)/cf_gen_defines <$(srcdir)/cf.data.pre >cf_gen_defines.h ## FIXME: generate a sed command file from configure. Then this doesn't -## depend on the Makefile. -cf.data: cf.data.pre Makefile - sed "\ - s%@DEFAULT_MIME_TABLE@%$(DEFAULT_MIME_TABLE)%g;\ - s%@DEFAULT_DNSSERVER@%$(DEFAULT_DNSSERVER)%g;\ - s%@DEFAULT_UNLINKD@%$(DEFAULT_UNLINKD)%g;\ - s%@DEFAULT_PINGER@%$(DEFAULT_PINGER)%g;\ - s%@DEFAULT_DISKD@%$(DEFAULT_DISKD)%g;\ - s%@DEFAULT_CACHE_LOG@%$(DEFAULT_CACHE_LOG)%g;\ - s%@DEFAULT_ACCESS_LOG@%$(DEFAULT_ACCESS_LOG)%g;\ - s%@DEFAULT_STORE_LOG@%$(DEFAULT_STORE_LOG)%g;\ - s%@DEFAULT_PID_FILE@%$(DEFAULT_PID_FILE)%g;\ - s%@DEFAULT_SWAP_DIR@%$(DEFAULT_SWAP_DIR)%g;\ - s%@DEFAULT_ICON_DIR@%$(DEFAULT_ICON_DIR)%g;\ - s%@DEFAULT_MIB_PATH@%$(DEFAULT_MIB_PATH)%g;\ - s%@DEFAULT_ERROR_DIR@%$(DEFAULT_ERROR_DIR)%g;\ - s%@DEFAULT_PREFIX@%$(DEFAULT_PREFIX)%g;\ - s%@DEFAULT_HOSTS@%$(DEFAULT_HOSTS)%g;\ - s%@[V]ERSION@%$(VERSION)%g;"\ - < $(srcdir)/cf.data.pre >$@ - -store_modules.cc: store_modules.sh Makefile - $(SHELL) $(srcdir)/store_modules.sh $(STORE_MODULES) >store_modules.cc - -repl_modules.cc: repl_modules.sh Makefile - $(SHELL) $(srcdir)/repl_modules.sh $(REPL_POLICIES) > repl_modules.cc - -auth_modules.cc: auth_modules.sh Makefile - @$(SHELL) $(srcdir)/auth_modules.sh $(AUTH_MODULES) >auth_modules.cc - -install-data-local: install-sysconfDATA install-dataDATA - @if test -f $(DESTDIR)$(DEFAULT_MIME_TABLE) ; then \ - echo "$@ will not overwrite existing $(DESTDIR)$(DEFAULT_MIME_TABLE)" ; \ - else \ - echo "$(INSTALL_DATA) $(srcdir)/mime.conf.default $(DESTDIR)$(DEFAULT_MIME_TABLE)" ;\ - $(INSTALL_DATA) $(srcdir)/mime.conf.default $(DESTDIR)$(DEFAULT_MIME_TABLE); \ - fi - @if test -f $(DESTDIR)$(DEFAULT_CONFIG_FILE) ; then \ - echo "$@ will not overwrite existing $(DESTDIR)$(DEFAULT_CONFIG_FILE)" ; \ - else \ - echo "$(INSTALL_DATA) squid.conf.default $(DESTDIR)$(DEFAULT_CONFIG_FILE)"; \ - $(INSTALL_DATA) squid.conf.default $(DESTDIR)$(DEFAULT_CONFIG_FILE); \ - fi - $(mkinstalldirs) $(DESTDIR)$(DEFAULT_LOG_PREFIX) +## depend on the Makefile. + cf.data: cf.data.pre Makefile + sed "\ + s%@DEFAULT_MIME_TABLE@%$(DEFAULT_MIME_TABLE)%g; + + \ + s%@DEFAULT_DNSSERVER@%$(DEFAULT_DNSSERVER)%g; + + \ + s%@DEFAULT_UNLINKD@%$(DEFAULT_UNLINKD)%g; + + \ + s%@DEFAULT_PINGER@%$(DEFAULT_PINGER)%g; + + \ + s%@DEFAULT_DISKD@%$(DEFAULT_DISKD)%g; + + \ + s%@DEFAULT_CACHE_LOG@%$(DEFAULT_CACHE_LOG)%g; + + \ + s%@DEFAULT_ACCESS_LOG@%$(DEFAULT_ACCESS_LOG)%g; + + \ + s%@DEFAULT_STORE_LOG@%$(DEFAULT_STORE_LOG)%g; + + \ + s%@DEFAULT_PID_FILE@%$(DEFAULT_PID_FILE)%g; + + \ + s%@DEFAULT_SWAP_DIR@%$(DEFAULT_SWAP_DIR)%g; + + \ + s%@DEFAULT_ICON_DIR@%$(DEFAULT_ICON_DIR)%g; + + \ + s%@DEFAULT_MIB_PATH@%$(DEFAULT_MIB_PATH)%g; + + \ + s%@DEFAULT_ERROR_DIR@%$(DEFAULT_ERROR_DIR)%g; + + \ + s%@DEFAULT_PREFIX@%$(DEFAULT_PREFIX)%g; + + \ + s%@DEFAULT_HOSTS@%$(DEFAULT_HOSTS)%g; + + \ + s%@[V]ERSION@%$(VERSION)%g;"\ + + < $(srcdir)/cf.data.pre >$@ + + store_modules.cc: store_modules.sh Makefile + $(SHELL) $(srcdir)/store_modules.sh $(STORE_MODULES) >store_modules.cc + + repl_modules.cc: repl_modules.sh Makefile + $(SHELL) $(srcdir)/repl_modules.sh $(REPL_POLICIES) > repl_modules.cc + + auth_modules.cc: auth_modules.sh Makefile + @$(SHELL) $(srcdir)/auth_modules.sh $(AUTH_MODULES) >auth_modules.cc + + install-data-local: install-sysconfDATA install-dataDATA + @if test -f $(DESTDIR)$(DEFAULT_MIME_TABLE) ; then \ +echo " +$@ will not overwrite existing $(DESTDIR)$(DEFAULT_MIME_TABLE)" ; \ +else \ + echo "$(INSTALL_DATA) $(srcdir)/mime.conf.default $(DESTDIR)$(DEFAULT_MIME_TABLE)" ;\ +$(INSTALL_DATA) $(srcdir)/mime.conf.default $(DESTDIR)$(DEFAULT_MIME_TABLE); \ +fi +@if test -f $(DESTDIR)$(DEFAULT_CONFIG_FILE) ; then \ +echo "$@ will not overwrite existing $(DESTDIR)$(DEFAULT_CONFIG_FILE)" ; \ +else \ + echo "$(INSTALL_DATA) squid.conf.default $(DESTDIR)$(DEFAULT_CONFIG_FILE)"; \ +$(INSTALL_DATA) squid.conf.default $(DESTDIR)$(DEFAULT_CONFIG_FILE); \ +fi +$(mkinstalldirs) $(DESTDIR)$(DEFAULT_LOG_PREFIX) uninstall-local: - @if test -f $(DESTDIR)$(DEFAULT_MIME_TABLE) ; then \ - echo "rm -f $(DESTDIR)$(DEFAULT_MIME_TABLE)"; \ - $(RM) -f $(DESTDIR)$(DEFAULT_MIME_TABLE); \ - fi +@if test -f $(DESTDIR)$(DEFAULT_MIME_TABLE) ; then \ +echo "rm -f $(DESTDIR)$(DEFAULT_MIME_TABLE)"; \ +$(RM) -f $(DESTDIR)$(DEFAULT_MIME_TABLE); \ +fi # Don't automatically uninstall config files # @if test -f $(DESTDIR)$(DEFAULT_CONFIG_FILE) ; then \ @@ -766,7 +797,7 @@ uninstall-local: # fi DISTCLEANFILES = cf_gen_defines.h cf.data cf_parser.h squid.conf.default \ - globals.cc string_arrays.c repl_modules.cc auth_modules.cc store_modules.cc + globals.cc string_arrays.c repl_modules.cc auth_modules.cc store_modules.cc ##install-pinger: ## @f=$(PINGER_EXE); \ diff --git a/src/Store.h b/src/Store.h index b763072d96..7699254e36 100644 --- a/src/Store.h +++ b/src/Store.h @@ -1,6 +1,6 @@ /* - * $Id: Store.h,v 1.9 2003/03/10 04:56:36 robertc Exp $ + * $Id: Store.h,v 1.10 2003/03/15 04:17:39 robertc Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -72,6 +72,7 @@ public: void delayAwareRead(int fd, char *buf, int len, IOCB *handler, void *data); void setNoDelay (bool const); + bool modifiedSince(request_t * request) const; MemObject *mem_obj; RemovalPolicyNode repl; diff --git a/src/clientStream.cc b/src/clientStream.cc index 7b16df5a60..a6eb930d49 100644 --- a/src/clientStream.cc +++ b/src/clientStream.cc @@ -1,6 +1,6 @@ /* - * $Id: clientStream.cc,v 1.6 2003/03/10 04:56:37 robertc Exp $ + * $Id: clientStream.cc,v 1.7 2003/03/15 04:17:39 robertc Exp $ * * DEBUG: section 87 Client-side Stream routines. * AUTHOR: Robert Collins @@ -96,9 +96,9 @@ CBDATA_TYPE(clientStreamNode); * * (i.e. * mycontext = thisObject->data; - * cbdataReferenceDone (mycontext); + * thisObject->data = NULL; * clientStreamFreeLinst (thisObject->head); - * cbdataFree (mycontext); + * mycontext = NULL; * return; */ @@ -107,7 +107,7 @@ static FREE clientStreamFree; clientStreamNode * clientStreamNew(CSR * readfunc, CSCB * callback, CSD * detach, CSS * status, - void *data) + ClientStreamData data) { clientStreamNode *temp; CBDATA_INIT_TYPE_FREECB(clientStreamNode, clientStreamFree); @@ -129,7 +129,7 @@ clientStreamNew(CSR * readfunc, CSCB * callback, CSD * detach, CSS * status, */ void clientStreamInit(dlink_list * list, CSR * func, CSD * rdetach, CSS * readstatus, - void *readdata, CSCB * callback, CSD * cdetach, void *callbackdata, + ClientStreamData readdata, CSCB * callback, CSD * cdetach, ClientStreamData callbackdata, StoreIOBuffer tailBuffer) { clientStreamNode *temp = clientStreamNew(func, NULL, rdetach, readstatus, @@ -149,18 +149,17 @@ clientStreamInit(dlink_list * list, CSR * func, CSD * rdetach, CSS * readstatus, */ void clientStreamInsertHead(dlink_list * list, CSR * func, CSCB * callback, - CSD * detach, CSS * status, void *data) + CSD * detach, CSS * status, ClientStreamData data) { - clientStreamNode *temp; /* test preconditions */ assert(list != NULL); assert(list->head); - temp = clientStreamNew(func, callback, detach, status, data); + clientStreamNode *temp = clientStreamNew(func, callback, detach, status, data); temp->head = list; debug(87, 3) ("clientStreamInsertHead: Inserted node %p with data %p after head\n", - temp, data); + temp, data.getRaw()); if (list->head->next) temp->readBuffer = ((clientStreamNode *)list->head->next->data)->readBuffer; @@ -183,7 +182,7 @@ clientStreamCallback(clientStreamNode * thisObject, clientHttpRequest * http, debug(87, 3) ("clientStreamCallback: Calling %p with cbdata %p from node %p\n", - next->callback, next->data, thisObject); + next->callback, next->data.getRaw(), thisObject); next->callback(next, http, rep, replyBuffer); } @@ -200,7 +199,7 @@ clientStreamRead(clientStreamNode * thisObject, clientHttpRequest * http, prev = thisObject->prev(); debug(87, 3) ("clientStreamRead: Calling %p with cbdata %p from node %p\n", - prev->readfunc, prev->data, thisObject); + prev->readfunc, prev->data.getRaw(), thisObject); thisObject->readBuffer = readBuffer; prev->readfunc(prev, http); } @@ -211,15 +210,23 @@ clientStreamRead(clientStreamNode * thisObject, clientHttpRequest * http, void clientStreamDetach(clientStreamNode * thisObject, clientHttpRequest * http) { - clientStreamNode *prev = thisObject->prev(); clientStreamNode *temp = thisObject; assert(thisObject->node.next == NULL); debug(87, 3) ("clientStreamDetach: Detaching node %p\n", thisObject); /* And clean up thisObject node */ /* ESI TODO: push refcount class through to head */ + clientStreamNode *prev = NULL; + + if (thisObject->prev()) + prev = cbdataReference(thisObject->prev()); + + thisObject->removeFromStream(); + cbdataReferenceDone(temp); + cbdataFree(thisObject); + /* and tell the prev that the detach has occured */ /* * We do it in thisObject order so that the detaching node is always @@ -228,8 +235,12 @@ clientStreamDetach(clientStreamNode * thisObject, clientHttpRequest * http) if (prev) { debug(87, 3) ("clientStreamDetach: Calling %p with cbdata %p\n", - prev->detach, prev->data); - prev->detach(prev, http); + prev->detach, prev->data.getRaw()); + + if (cbdataReferenceValid(prev)) + prev->detach(prev, http); + + cbdataReferenceDone(prev); } } @@ -265,6 +276,15 @@ clientStreamStatus(clientStreamNode * thisObject, clientHttpRequest * http) } /* Local function bodies */ +void +clientStreamNode::removeFromStream() +{ + if (head) + dlinkDelete(&node, head); + + head = NULL; +} + void clientStreamFree(void *foo) { @@ -272,14 +292,8 @@ clientStreamFree(void *foo) debug(87, 3) ("Freeing clientStreamNode %p\n", thisObject); - if (thisObject->data) { - cbdataFree(thisObject->data); - } - - if (thisObject->node.next || thisObject->node.prev) { - dlinkDelete(&thisObject->node, thisObject->head); - } - + thisObject->removeFromStream(); + thisObject->data = NULL; } clientStreamNode * diff --git a/src/clientStream.h b/src/clientStream.h index b3c2b9265f..c6d965e4e9 100644 --- a/src/clientStream.h +++ b/src/clientStream.h @@ -1,6 +1,6 @@ /* - * $Id: clientStream.h,v 1.5 2003/03/10 04:56:37 robertc Exp $ + * $Id: clientStream.h,v 1.6 2003/03/15 04:17:39 robertc Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -35,6 +35,9 @@ #define SQUID_CLIENTSTREAM_H #include "StoreIOBuffer.h" +#include "RefCount.h" + +typedef RefCount ClientStreamData; class clientStreamNode; @@ -54,20 +57,21 @@ class clientStreamNode public: clientStreamNode *prev() const; clientStreamNode *next() const; + void removeFromStream(); dlink_node node; dlink_list *head; /* sucks I know, but hey, the interface is limited */ CSR *readfunc; CSCB *callback; CSD *detach; /* tell this node the next one downstream wants no more data */ CSS *status; - void *data; /* Context for the node */ + ClientStreamData data; /* Context for the node */ StoreIOBuffer readBuffer; /* what, where and how much this node wants */ }; /* clientStream.c */ -SQUIDCEXTERN void clientStreamInit(dlink_list *, CSR *, CSD *, CSS *, void *, CSCB *, CSD *, void *, StoreIOBuffer tailBuffer); -SQUIDCEXTERN void clientStreamInsertHead(dlink_list *, CSR *, CSCB *, CSD *, CSS *, void *); -SQUIDCEXTERN clientStreamNode *clientStreamNew(CSR *, CSCB *, CSD *, CSS *, void *); +SQUIDCEXTERN void clientStreamInit(dlink_list *, CSR *, CSD *, CSS *, ClientStreamData, CSCB *, CSD *, ClientStreamData, StoreIOBuffer tailBuffer); +SQUIDCEXTERN void clientStreamInsertHead(dlink_list *, CSR *, CSCB *, CSD *, CSS *, ClientStreamData); +SQUIDCEXTERN clientStreamNode *clientStreamNew(CSR *, CSCB *, CSD *, CSS *, ClientStreamData); SQUIDCEXTERN void clientStreamCallback(clientStreamNode *, ClientHttpRequest *, HttpReply *, StoreIOBuffer replyBuffer); SQUIDCEXTERN void clientStreamRead(clientStreamNode *, ClientHttpRequest *, StoreIOBuffer readBuffer); SQUIDCEXTERN void clientStreamDetach(clientStreamNode *, ClientHttpRequest *); diff --git a/src/client_side.cc b/src/client_side.cc index bb9a58d582..7694e1dfbc 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -1,6 +1,6 @@ /* - * $Id: client_side.cc,v 1.633 2003/03/13 07:51:38 hno Exp $ + * $Id: client_side.cc,v 1.634 2003/03/15 04:17:39 robertc Exp $ * * DEBUG: section 33 Client-side Routines * AUTHOR: Duane Wessels @@ -69,6 +69,7 @@ #include "client_side_request.h" #include "ACLChecklist.h" #include "ConnectionDetail.h" +#include "client_side_reply.h" #if LINGERING_CLOSE #define comm_close comm_lingering_close @@ -93,73 +94,32 @@ /* our socket-related context */ -class ClientSocketContext -{ - -public: - clientHttpRequest *http; /* we own this */ - char reqbuf[HTTP_REQBUF_SZ]; - ClientSocketContext *next; - struct - { +CBDATA_CLASS_INIT(ClientSocketContext); -int deferred: - 1; /* This is a pipelined request waiting for the current object to complete */ - -int parsed_ok: - 1; /* Was this parsed correctly? */ - } - - flags; - bool mayUseConnection() const {return mayUseConnection_;} - - void mayUseConnection(bool aBool) - { - mayUseConnection_ = aBool; - debug (33,3)("ClientSocketContext::mayUseConnection: This %p marked %d\n", - this, aBool); - } +void * +ClientSocketContext::operator new (size_t byteCount) +{ + /* derived classes with different sizes must implement their own new */ + assert (byteCount == sizeof (ClientSocketContext)); + CBDATA_INIT_TYPE(ClientSocketContext); + return cbdataAlloc(ClientSocketContext); +} - struct - { - clientStreamNode *node; - HttpReply *rep; - StoreIOBuffer queuedBuffer; - } - - deferredparams; - off_t writtenToSocket; - void pullData(); - off_t getNextRangeOffset() const; - bool canPackMoreRanges() const; - clientStream_status_t socketState(); - void sendBody(HttpReply * rep, StoreIOBuffer bodyData); - void sendStartOfMessage(HttpReply * rep, StoreIOBuffer bodyData); - size_t lengthToSend(size_t maximum); - void noteSentBodyBytes(size_t); - void buildRangeHeader(HttpReply * rep); - int fd() const; - clientStreamNode * getTail() const; - clientStreamNode * getClientReplyContext() const; - void removeFromConnectionList(ConnStateData * conn); - void deferRecipientForLater(clientStreamNode * node, HttpReply * rep, StoreIOBuffer recievedData); - bool multipartRangeRequest() const; - void packRange(const char **buf, - size_t size, - MemBuf * mb); - -private: - void prepareReply(HttpReply * rep); - bool mayUseConnection_; /* This request may use the connection. Don't read anymore requests for now */ -}; - -CBDATA_TYPE(ClientSocketContext); +void +ClientSocketContext::operator delete (void *address) +{ + cbdataFree (address); +} +void +ClientSocketContext::deleteSelf() const +{ + delete this; +} /* Local functions */ /* ClientSocketContext */ -static FREE ClientSocketContextFree; static ClientSocketContext *ClientSocketContextNew(clientHttpRequest *); /* other */ static CWCB clientWriteComplete; @@ -189,10 +149,8 @@ static void clientUpdateHierCounters(HierarchyLogEntry *); static bool clientPingHasFinished(ping_data const *aPing); static void clientPrepareLogWithRequestDetails(request_t *, AccessLogEntry *); static int connIsUsable(ConnStateData * conn); -static ClientSocketContext *connGetCurrentContext(ConnStateData const * conn); static int responseFinishedOrFailed(HttpReply * rep, StoreIOBuffer const &recievedData); -static int contextStartOfOutput(ClientSocketContext * context); -static void ClientSocketContextPushDeferredIfNeeded(ClientSocketContext * deferredRequest, ConnStateData * conn); +static void ClientSocketContextPushDeferredIfNeeded(ClientSocketContext::Pointer deferredRequest, ConnStateData * conn); static void clientUpdateSocketStats(log_type logType, size_t size); static ClientSocketContext *clientParseRequestMethod(char *inbuf, method_t * method_p, ConnStateData * conn); @@ -203,8 +161,6 @@ static void trimTrailingSpaces(char *aString, size_t len); #endif static ClientSocketContext *parseURIandHTTPVersion(char **url_p, http_version_t * http_ver_p, ConnStateData * conn, char *http_version_str); static void setLogUri(clientHttpRequest * http, char const *uri); -static void connAddContextToQueue(ConnStateData * conn, ClientSocketContext * context); -static int connGetConcurrentRequestCount(ConnStateData * conn); static int connReadWasError(ConnStateData * conn, comm_err_t, int size, int xerrno); static int connFinishedWithConn(ConnStateData * conn, int size); static void connNoteUseOfBuffer(ConnStateData * conn, size_t byteCount); @@ -224,7 +180,10 @@ ClientSocketContext::fd() const clientStreamNode * ClientSocketContext::getTail() const { - return (clientStreamNode *)http->client_stream.tail->data; + if (http->client_stream.tail) + return (clientStreamNode *)http->client_stream.tail->data; + + return NULL; } clientStreamNode * @@ -260,39 +219,85 @@ ConnStateData::readSomeData() void ClientSocketContext::removeFromConnectionList(ConnStateData * conn) { - ClientSocketContext **tempContextPointer; + ClientSocketContext::Pointer *tempContextPointer; assert(conn); - assert(connGetCurrentContext(conn) != NULL); + assert(conn->getCurrentContext().getRaw() != NULL); /* Unlink us from the connection request list */ - tempContextPointer = (ClientSocketContext **) & conn->currentobject; + tempContextPointer = & conn->currentobject; - while (*tempContextPointer) { + while (tempContextPointer->getRaw()) { if (*tempContextPointer == this) break; tempContextPointer = &(*tempContextPointer)->next; } - assert(*tempContextPointer != NULL); + assert(tempContextPointer->getRaw() != NULL); *tempContextPointer = next; next = NULL; } -void -ClientSocketContextFree(void *data) +ClientSocketContext::~ClientSocketContext() { - ClientSocketContext *context = (ClientSocketContext *)data; - ConnStateData *conn = context->http->conn; - clientStreamNode *node = context->getTail(); - /* We are *always* the tail - prevent recursive free */ - assert(context == node->data); - node->data = NULL; - httpRequestFree(context->http); + clientStreamNode *node = getTail(); + + if (node) { + ClientSocketContext *streamContext = dynamic_cast (node->data.getRaw()); + + if (streamContext) { + /* We are *always* the tail - prevent recursive free */ + assert(this == streamContext); + node->data = NULL; + } + } + + if (connRegistered_) + deRegisterWithConn(); + + httpRequestFree(http); + /* clean up connection links to us */ - assert(context != context->next); + assert(this != next.getRaw()); +} - if (conn) - context->removeFromConnectionList(conn); +void +ClientSocketContext::registerWithConn() +{ + assert (!connRegistered_); + assert (http); + assert (http->conn); + connRegistered_ = true; + http->conn->addContextToQueue(this); +} + +void +ClientSocketContext::deRegisterWithConn() +{ + assert (connRegistered_); + removeFromConnectionList(http->conn); + connRegistered_ = false; +} + +void +ClientSocketContext::connIsFinished() +{ + assert (http); + assert (http->conn); + deRegisterWithConn(); + /* we can't handle any more stream data - detach */ + clientStreamDetach(getTail(), http); +} + +ClientSocketContext::ClientSocketContext() : http(NULL), next(NULL), + writtenToSocket(0), + mayUseConnection_ (false), + connRegistered_ (false) +{ + memset (reqbuf, '\0', sizeof (reqbuf)); + flags.deferred = 0; + flags.parsed_ok = 0; + deferredparams.node = NULL; + deferredparams.rep = NULL; } ClientSocketContext * @@ -300,8 +305,7 @@ ClientSocketContextNew(clientHttpRequest * http) { ClientSocketContext *newContext; assert(http != NULL); - CBDATA_INIT_TYPE_FREECB(ClientSocketContext, ClientSocketContextFree); - newContext = cbdataAlloc(ClientSocketContext); + newContext = new ClientSocketContext; newContext->http = http; return newContext; } @@ -544,9 +548,9 @@ bool ConnStateData::areAllContextsForThisConnection() const { assert(this != NULL); - ClientSocketContext *context = connGetCurrentContext(this); + ClientSocketContext::Pointer context = getCurrentContext(); - while (context) { + while (context.getRaw()) { if (context->http->conn != this) return false; @@ -559,12 +563,13 @@ ConnStateData::areAllContextsForThisConnection() const void ConnStateData::freeAllContexts() { - ClientSocketContext *context; + ClientSocketContext::Pointer context; - while ((context = connGetCurrentContext(this)) != NULL) { - assert(connGetCurrentContext(this) != - connGetCurrentContext(this)->next); - cbdataFree(context); + while ((context = getCurrentContext()).getRaw() != NULL) { + assert(getCurrentContext() != + getCurrentContext()->next); + context->connIsFinished(); + assert (context != currentobject); } } @@ -679,11 +684,11 @@ connIsUsable(ConnStateData * conn) return 1; } -ClientSocketContext * -connGetCurrentContext(ConnStateData const * conn) +ClientSocketContext::Pointer +ConnStateData::getCurrentContext() const { - assert(conn); - return (ClientSocketContext *)conn->currentobject; + assert(this); + return currentobject; } void @@ -707,10 +712,10 @@ responseFinishedOrFailed(HttpReply * rep, StoreIOBuffer const & recievedData) return 0; } -int -contextStartOfOutput(ClientSocketContext * context) +bool +ClientSocketContext::startOfOutput() const { - return context->http->out.size == 0 ? 1 : 0; + return http->out.size == 0; } size_t @@ -1154,7 +1159,6 @@ clientSocketRecipient(clientStreamNode * node, clientHttpRequest * http, HttpReply * rep, StoreIOBuffer recievedData) { int fd; - ClientSocketContext *context; /* Test preconditions */ assert(node != NULL); /* TODO: handle this rather than asserting @@ -1163,24 +1167,24 @@ clientSocketRecipient(clientStreamNode * node, clientHttpRequest * http, * However, that itself shouldn't happen, so it stays as an assert for now. */ assert(cbdataReferenceValid(node)); - assert(node->data != NULL); assert(node->node.next == NULL); - context = (ClientSocketContext *)node->data; + ClientSocketContext::Pointer context = dynamic_cast(node->data.getRaw()); + assert(context.getRaw() != NULL); assert(connIsUsable(http->conn)); fd = http->conn->fd; /* TODO: check offset is what we asked for */ - if (connGetCurrentContext(http->conn) != context) { + if (context != http->conn->getCurrentContext()) { context->deferRecipientForLater(node, rep, recievedData); return; } if (responseFinishedOrFailed(rep, recievedData)) { - clientWriteComplete(fd, NULL, 0, COMM_OK, context); + context->writeComplete(fd, NULL, 0, COMM_OK); return; } - if (!contextStartOfOutput(context)) + if (!context->startOfOutput()) context->sendBody(rep, recievedData); else context->sendStartOfMessage(rep, recievedData); @@ -1193,7 +1197,6 @@ clientSocketRecipient(clientStreamNode * node, clientHttpRequest * http, void clientSocketDetach(clientStreamNode * node, clientHttpRequest * http) { - ClientSocketContext *context; /* Test preconditions */ assert(node != NULL); /* TODO: handle this rather than asserting @@ -1203,9 +1206,10 @@ clientSocketDetach(clientStreamNode * node, clientHttpRequest * http) */ assert(cbdataReferenceValid(node)); /* Set null by ContextFree */ - assert(node->data == NULL); assert(node->node.next == NULL); - context = (ClientSocketContext *)node->data; + ClientSocketContext *context = dynamic_cast(node->data.getRaw()); + /* this is the assert discussed above */ + assert(context == NULL); /* We are only called when the client socket shutsdown. * Tell the prev pipeline member we're finished */ @@ -1233,7 +1237,7 @@ ConnStateData::readNextRequest() } void -ClientSocketContextPushDeferredIfNeeded(ClientSocketContext * deferredRequest, ConnStateData * conn) +ClientSocketContextPushDeferredIfNeeded(ClientSocketContext::Pointer deferredRequest, ConnStateData * conn) { debug(33, 2) ("ClientSocketContextPushDeferredIfNeeded: FD %d Sending next\n", conn->fd); @@ -1253,17 +1257,17 @@ ClientSocketContextPushDeferredIfNeeded(ClientSocketContext * deferredRequest, C */ } -static void -clientKeepaliveNextRequest(ClientSocketContext * context) +void +ClientSocketContext::keepaliveNextRequest() { - clientHttpRequest *http = context->http; ConnStateData *conn = http->conn; - ClientSocketContext *deferredRequest; - debug(33, 3) ("clientKeepaliveNextRequest: FD %d\n", conn->fd); - cbdataFree(context); + debug(33, 3) ("ClientSocketContext::keepaliveNextRequest: FD %d\n", conn->fd); + connIsFinished(); + + ClientSocketContext::Pointer deferredRequest; - if ((deferredRequest = connGetCurrentContext(conn)) == NULL) + if ((deferredRequest = conn->getCurrentContext()).getRaw() == NULL) conn->readNextRequest(); else ClientSocketContextPushDeferredIfNeeded(deferredRequest, conn); @@ -1403,7 +1407,12 @@ void clientWriteComplete(int fd, char *bufnotused, size_t size, comm_err_t errflag, void *data) { ClientSocketContext *context = (ClientSocketContext *)data; - clientHttpRequest *http = context->http; + context->writeComplete (fd, bufnotused, size, errflag); +} + +void +ClientSocketContext::writeComplete(int fd, char *bufnotused, size_t size, comm_err_t errflag) +{ StoreEntry *entry = http->entry; http->out.size += size; assert(fd > -1); @@ -1418,15 +1427,15 @@ clientWriteComplete(int fd, char *bufnotused, size_t size, comm_err_t errflag, v return; } - switch (context->socketState()) { + switch (socketState()) { case STREAM_NONE: - context->pullData(); + pullData(); break; case STREAM_COMPLETE: debug(33, 5) ("clientWriteComplete: FD %d Keeping Alive\n", fd); - clientKeepaliveNextRequest(context); + keepaliveNextRequest(); return; case STREAM_UNPLANNED_COMPLETE: @@ -1460,7 +1469,7 @@ parseHttpRequestAbort(ConnStateData * conn, const char *uri) tempBuffer.data = context->reqbuf; tempBuffer.length = HTTP_REQBUF_SZ; clientStreamInit(&http->client_stream, clientGetMoreData, clientReplyDetach, - clientReplyStatus, clientReplyNewContext(http), clientSocketRecipient, + clientReplyStatus, new clientReplyContext(http), clientSocketRecipient, clientSocketDetach, context, tempBuffer); dlinkAdd(http, &http->active, &ClientActiveRequests); return context; @@ -1826,9 +1835,13 @@ parseHttpRequest(ConnStateData * conn, method_t * method_p, tempBuffer.length = HTTP_REQBUF_SZ; + ClientStreamData newServer = new clientReplyContext(http); + + ClientStreamData newClient = result; + clientStreamInit(&http->client_stream, clientGetMoreData, clientReplyDetach, - clientReplyStatus, clientReplyNewContext(http), clientSocketRecipient, - clientSocketDetach, result, tempBuffer); + clientReplyStatus, newServer, clientSocketRecipient, + clientSocketDetach, newClient, tempBuffer); *prefix_p = (char *)xmalloc(prefix_sz + 1); @@ -1893,27 +1906,27 @@ ConnStateData::makeSpaceAvailable() } void -connAddContextToQueue(ConnStateData * conn, ClientSocketContext * context) +ConnStateData::addContextToQueue(ClientSocketContext * context) { - ClientSocketContext **S; + ClientSocketContext::Pointer *S; - for (S = (ClientSocketContext **) & conn->currentobject; *S; + for (S = (ClientSocketContext::Pointer *) & currentobject; S->getRaw(); S = &(*S)->next) ; *S = context; - ++conn->nrequests; + ++nrequests; } int -connGetConcurrentRequestCount(ConnStateData * conn) +ConnStateData::getConcurrentRequestCount() const { int result = 0; - ClientSocketContext **T; + ClientSocketContext::Pointer *T; - for (T = (ClientSocketContext **) & conn->currentobject; - *T; T = &(*T)->next, ++result) + for (T = (ClientSocketContext::Pointer *) ¤tobject; + T->getRaw(); T = &(*T)->next, ++result) ; return result; @@ -1944,7 +1957,7 @@ int connFinishedWithConn(ConnStateData * conn, int size) { if (size == 0) { - if (connGetConcurrentRequestCount(conn) == 0 && conn->in.notYetUsed == 0) { + if (conn->getConcurrentRequestCount() == 0 && conn->in.notYetUsed == 0) { /* no current or pending requests */ debug(33, 4) ("connFinishedWithConn: FD %d closed\n", conn->fd); return 1; @@ -1990,10 +2003,12 @@ connCancelIncompleteRequests(ConnStateData * conn) (unsigned) conn->in.notYetUsed); debug(33, 1) ("Config 'request_header_max_size'= %ld bytes.\n", (long int) Config.maxRequestHeaderSize); - clientSetReplyToError(node->data, ERR_TOO_BIG, - HTTP_REQUEST_ENTITY_TOO_LARGE, METHOD_NONE, NULL, - &conn->peer.sin_addr, NULL, NULL, NULL); - connAddContextToQueue(conn, context); + clientReplyContext *repContext = dynamic_cast(node->data.getRaw()); + assert (repContext); + repContext->setReplyToError(ERR_TOO_BIG, + HTTP_REQUEST_ENTITY_TOO_LARGE, METHOD_NONE, NULL, + &conn->peer.sin_addr, NULL, NULL, NULL); + context->registerWithConn(); context->pullData(); } @@ -2035,14 +2050,15 @@ clientProcessRequest(ConnStateData *conn, ClientSocketContext *context, method_t /* setup our private context */ connNoteUseOfBuffer(conn, http->req_sz); - connAddContextToQueue(conn, context); + context->registerWithConn(); if (context->flags.parsed_ok == 0) { clientStreamNode *node = context->getClientReplyContext(); debug(33, 1) ("clientReadRequest: Invalid Request\n"); - clientSetReplyToError(node->data, - ERR_INVALID_REQ, HTTP_BAD_REQUEST, method, NULL, - &conn->peer.sin_addr, NULL, conn->in.buf, NULL); + clientReplyContext *repContext = dynamic_cast(node->data.getRaw()); + assert (repContext); + repContext->setReplyToError(ERR_INVALID_REQ, HTTP_BAD_REQUEST, method, NULL, + &conn->peer.sin_addr, NULL, conn->in.buf, NULL); assert(context->http->out.offset == 0); context->pullData(); conn->flags.readMoreRequests = 0; @@ -2052,9 +2068,11 @@ clientProcessRequest(ConnStateData *conn, ClientSocketContext *context, method_t if ((request = urlParse(method, http->uri)) == NULL) { clientStreamNode *node = context->getClientReplyContext(); debug(33, 5) ("Invalid URL: %s\n", http->uri); - clientSetReplyToError(node->data, - ERR_INVALID_URL, HTTP_BAD_REQUEST, method, http->uri, - &conn->peer.sin_addr, NULL, NULL, NULL); + clientReplyContext *repContext = dynamic_cast(node->data.getRaw()); + assert (repContext); + repContext->setReplyToError( + ERR_INVALID_URL, HTTP_BAD_REQUEST, method, http->uri, + &conn->peer.sin_addr, NULL, NULL, NULL); assert(context->http->out.offset == 0); context->pullData(); conn->flags.readMoreRequests = 0; @@ -2098,9 +2116,11 @@ clientProcessRequest(ConnStateData *conn, ClientSocketContext *context, method_t if (!urlCheckRequest(request) || httpHeaderHas(&request->header, HDR_TRANSFER_ENCODING)) { clientStreamNode *node = context->getClientReplyContext(); - clientSetReplyToError(node->data, ERR_UNSUP_REQ, - HTTP_NOT_IMPLEMENTED, request->method, NULL, - &conn->peer.sin_addr, request, NULL, NULL); + clientReplyContext *repContext = dynamic_cast(node->data.getRaw()); + assert (repContext); + repContext->setReplyToError(ERR_UNSUP_REQ, + HTTP_NOT_IMPLEMENTED, request->method, NULL, + &conn->peer.sin_addr, request, NULL, NULL); assert(context->http->out.offset == 0); context->pullData(); conn->flags.readMoreRequests = 0; @@ -2110,9 +2130,11 @@ clientProcessRequest(ConnStateData *conn, ClientSocketContext *context, method_t if (!clientIsContentLengthValid(request)) { clientStreamNode *node = context->getClientReplyContext(); - clientSetReplyToError(node->data, ERR_INVALID_REQ, - HTTP_LENGTH_REQUIRED, request->method, NULL, - &conn->peer.sin_addr, request, NULL, NULL); + clientReplyContext *repContext = dynamic_cast(node->data.getRaw()); + assert (repContext); + repContext->setReplyToError(ERR_INVALID_REQ, + HTTP_LENGTH_REQUIRED, request->method, NULL, + &conn->peer.sin_addr, request, NULL, NULL); assert(context->http->out.offset == 0); context->pullData(); conn->flags.readMoreRequests = 0; @@ -2131,9 +2153,11 @@ clientProcessRequest(ConnStateData *conn, ClientSocketContext *context, method_t if (!clientIsRequestBodyValid(request->content_length) || clientIsRequestBodyTooLargeForPolicy(request->content_length)) { clientStreamNode *node = context->getClientReplyContext(); - clientSetReplyToError(node->data, ERR_TOO_BIG, - HTTP_REQUEST_ENTITY_TOO_LARGE, METHOD_NONE, NULL, - &conn->peer.sin_addr, http->request, NULL, NULL); + clientReplyContext *repContext = dynamic_cast(node->data.getRaw()); + assert (repContext); + repContext->setReplyToError(ERR_TOO_BIG, + HTTP_REQUEST_ENTITY_TOO_LARGE, METHOD_NONE, NULL, + &conn->peer.sin_addr, http->request, NULL, NULL); assert(context->http->out.offset == 0); context->pullData(); conn->flags.readMoreRequests = 0; @@ -2162,7 +2186,7 @@ connStripBufferWhitespace (ConnStateData *conn) static int connOkToAddRequest(ConnStateData *conn) { - int result = connGetConcurrentRequestCount(conn) < (Config.onoff.pipeline_prefetch ? 2 : 1); + int result = conn->getConcurrentRequestCount() < (Config.onoff.pipeline_prefetch ? 2 : 1); if (!result) { debug(33, 3) ("clientReadRequest: FD %d max concurrent requests reached\n", @@ -2241,7 +2265,7 @@ clientReadRequest(int fd, char *buf, size_t size, comm_err_t flag, int xerrno, clientProcessBody(conn); /* Process next request */ - if (connGetConcurrentRequestCount(conn) == 0) + if (conn->getConcurrentRequestCount() == 0) fd_note(conn->fd, "Reading next request"); /* XXX: if we read *exactly* two requests, and the client sends no more, @@ -2482,9 +2506,11 @@ requestTimeout(int fd, void *data) clientHttpRequest *http = parseHttpRequestAbort(conn, "error:Connection%20lifetime%20expired"); node = http->client_stream.tail->prev->data; - clientSetReplyToError(node->data, ERR_LIFETIME_EXP, - HTTP_REQUEST_TIMEOUT, METHOD_NONE, "N/A", &conn->peer.sin_addr, - NULL, NULL, NULL); + clientReplyContext *repContext = dynamic_cast(node->data.getRaw()); + assert (repContext); + repContext->setReplyToError(ERR_LIFETIME_EXP, + HTTP_REQUEST_TIMEOUT, METHOD_NONE, "N/A", &conn->peer.sin_addr, + NULL, NULL, NULL); /* No requests can be outstanded */ assert(conn->chr == NULL); /* add to the client request queue */ diff --git a/src/client_side.h b/src/client_side.h index 18c969dd49..0e95224ed9 100644 --- a/src/client_side.h +++ b/src/client_side.h @@ -1,6 +1,6 @@ /* - * $Id: client_side.h,v 1.1 2003/03/04 02:57:50 robertc Exp $ + * $Id: client_side.h,v 1.2 2003/03/15 04:17:39 robertc Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -34,6 +34,89 @@ #ifndef SQUID_CLIENTSIDE_H #define SQUID_CLIENTSIDE_H +#include "StoreIOBuffer.h" + +class ConnStateData; + +class ClientHttpRequest; + +class clientStreamNode; + +class ClientSocketContext : public RefCountable +{ + +public: + typedef RefCount Pointer; + void *operator new(size_t); + void operator delete(void *); + void deleteSelf() const; + ClientSocketContext(); + ~ClientSocketContext(); + bool startOfOutput() const; + void writeComplete(int fd, char *bufnotused, size_t size, comm_err_t errflag); + void keepaliveNextRequest(); + ClientHttpRequest *http; /* we own this */ + char reqbuf[HTTP_REQBUF_SZ]; + Pointer next; + + struct + { + +int deferred: + 1; /* This is a pipelined request waiting for the current object to complete */ + +int parsed_ok: + 1; /* Was this parsed correctly? */ + } + + flags; + bool mayUseConnection() const {return mayUseConnection_;} + + void mayUseConnection(bool aBool) + { + mayUseConnection_ = aBool; + debug (33,3)("ClientSocketContext::mayUseConnection: This %p marked %d\n", + this, aBool); + } + + struct + { + clientStreamNode *node; + HttpReply *rep; + StoreIOBuffer queuedBuffer; + } + + deferredparams; + off_t writtenToSocket; + void pullData(); + off_t getNextRangeOffset() const; + bool canPackMoreRanges() const; + clientStream_status_t socketState(); + void sendBody(HttpReply * rep, StoreIOBuffer bodyData); + void sendStartOfMessage(HttpReply * rep, StoreIOBuffer bodyData); + size_t lengthToSend(size_t maximum); + void noteSentBodyBytes(size_t); + void buildRangeHeader(HttpReply * rep); + int fd() const; + clientStreamNode * getTail() const; + clientStreamNode * getClientReplyContext() const; + void connIsFinished(); + void removeFromConnectionList(ConnStateData * conn); + void deferRecipientForLater(clientStreamNode * node, HttpReply * rep, StoreIOBuffer recievedData); + bool multipartRangeRequest() const; + void packRange(const char **buf, + size_t size, + MemBuf * mb); + void registerWithConn(); + +private: + CBDATA_CLASS(ClientSocketContext); + void prepareReply(HttpReply * rep); + void deRegisterWithConn(); + bool mayUseConnection_; /* This request may use the connection. Don't read anymore requests for now */ + bool connRegistered_; +}; + class ConnStateData { @@ -51,6 +134,9 @@ public: void freeAllContexts(); void readNextRequest(); void makeSpaceAvailable(); + ClientSocketContext::Pointer getCurrentContext() const; + void addContextToQueue(ClientSocketContext * context); + int getConcurrentRequestCount() const; int fd; @@ -81,7 +167,8 @@ public: /* note this is ONLY connection based because NTLM is against HTTP spec */ /* the user details for connection based authentication */ auth_user_request_t *auth_user_request; - void *currentobject; /* used by the owner of the connection. Opaque otherwise */ + /* TODO: generalise the connection owner concept */ + ClientSocketContext::Pointer currentobject; /* used by the owner of the connection. Opaque otherwise */ struct sockaddr_in peer; diff --git a/src/client_side_reply.cc b/src/client_side_reply.cc index beb732e609..66850898fa 100644 --- a/src/client_side_reply.cc +++ b/src/client_side_reply.cc @@ -1,6 +1,6 @@ /* - * $Id: client_side_reply.cc,v 1.46 2003/03/11 08:24:42 robertc Exp $ + * $Id: client_side_reply.cc,v 1.47 2003/03/15 04:17:39 robertc Exp $ * * DEBUG: section 88 Client-side Reply Routines * AUTHOR: Robert Collins (Originally Duane Wessels in client_side.c) @@ -34,6 +34,7 @@ */ #include "squid.h" +#include "client_side_reply.h" #include "StoreClient.h" #include "Store.h" #include "HttpReply.h" @@ -45,7 +46,6 @@ #include "ESI.h" #endif #include "MemObject.h" -#include "client_side_request.h" #include "ACLChecklist.h" #include "ACL.h" #if DELAY_POOLS @@ -53,164 +53,53 @@ #endif #include "client_side.h" -static STCB clientHandleIMSReply; -static STCB clientSendMoreData; - -class clientReplyContext : public StoreClient -{ - -public: - void *operator new (size_t byteCount); - void operator delete (void *address); - - void saveState(clientHttpRequest *); - void restoreState(clientHttpRequest *); - void purgeRequest (); - void purgeRequestFindObjectToPurge(); - void purgeDoMissPurge(); - void purgeFoundGet(StoreEntry *newEntry); - void purgeFoundHead(StoreEntry *newEntry); - void purgeFoundObject(StoreEntry *entry); - void sendClientUpstreamResponse(); - void purgeDoPurgeGet(StoreEntry *entry); - void purgeDoPurgeHead(StoreEntry *entry); - void doGetMoreData(); - void identifyStoreObject(); - void identifyFoundObject(StoreEntry *entry); - int storeOKTransferDone() const; - int storeNotOKTransferDone() const; - - http_status purgeStatus; - - /* state variable - replace with class to handle storeentries at some point */ - int lookingforstore; - virtual void created (StoreEntry *newEntry); - - clientHttpRequest *http; - int headers_sz; - store_client *sc; /* The store_client we're using */ - store_client *old_sc; /* ... for entry to be validated */ - StoreIOBuffer tempBuffer; /* For use in validating requests via IMS */ - int old_reqsize; /* ... again, for the buffer */ - size_t reqsize; - off_t reqofs; - char tempbuf[HTTP_REQBUF_SZ]; /* a temporary buffer if we need working storage */ -#if USE_CACHE_DIGESTS - - const char *lookup_type; /* temporary hack: storeGet() result: HIT/MISS/NONE */ -#endif - - struct - { - -int storelogiccomplete: - 1; - -int complete: - 1; /* we have read all we can from upstream */ - bool headersSent; - } - - flags; - clientStreamNode *ourNode; /* This will go away if/when this file gets refactored some more */ - -private: - friend void clientSendMoreData(void *data, StoreIOBuffer result); - friend void clientHandleIMSReply(void *data, StoreIOBuffer result); - static STCB clientSendMoreData; - clientStreamNode *getNextNode() const; - void sendMoreData (StoreIOBuffer result); - void makeThisHead(); - bool errorInStream(StoreIOBuffer const &result, size_t const &sizeToProcess)const ; - void sendStreamError(StoreIOBuffer const &result); - void pushStreamData(StoreIOBuffer const &result, char *source); - void waitForMoreData (StoreIOBuffer const &result); - clientStreamNode * next() const; - void startSendProcess(); - StoreIOBuffer holdingBuffer; - HttpReply *holdingReply; - void processReplyAccess(); - static PF ProcessReply; - void processReply(bool accessAllowed); -}; - -CBDATA_TYPE(clientReplyContext); +CBDATA_CLASS_INIT(clientReplyContext); /* Local functions */ -static int clientGotNotEnough(clientHttpRequest const *); -static int clientReplyBodyTooLarge(HttpReply const *, ssize_t); -static int clientOnlyIfCached(clientHttpRequest * http); -static void clientProcessExpired(clientReplyContext *); -static void clientProcessMiss(clientReplyContext *); -static STCB clientCacheHit; -static void clientProcessOnlyIfCachedMiss(clientReplyContext *); -static int clientGetsOldEntry(StoreEntry *, StoreEntry * old, - request_t * request); - -static int modifiedSince(StoreEntry *, request_t *); -static void clientTraceReply(clientStreamNode *, clientReplyContext *); -static StoreEntry *clientCreateStoreEntry(clientReplyContext *, method_t, - request_flags); - -static void clientRemoveStoreReference(clientReplyContext *, store_client **, - StoreEntry **); extern "C" CSS clientReplyStatus; extern ErrorState *clientBuildError(err_type, http_status, char const *, struct in_addr *, request_t *); -static void startError(clientReplyContext * context, clientHttpRequest * http, ErrorState * err); -static void triggerInitialStoreReadWithClientParameters(clientReplyContext * context, clientHttpRequest * http); -static int clientCheckTransferDone(clientReplyContext * context); -static void clientObeyConnectionHeader(clientHttpRequest * http, HttpReply * rep); - -/* The clientReply clean interface */ /* privates */ -static FREE clientReplyFree; -void -clientReplyFree(void *data) +clientReplyContext::~clientReplyContext() { - clientReplyContext *thisClient = (clientReplyContext *)data; - clientRemoveStoreReference(thisClient, &thisClient->sc, &thisClient->http->entry); + removeStoreReference(&sc, &http->entry); /* old_entry might still be set if we didn't yet get the reply - * code in clientHandleIMSReply() */ - clientRemoveStoreReference(thisClient, &thisClient->old_sc, &thisClient->http->old_entry); - safe_free(thisClient->tempBuffer.data); - cbdataReferenceDone(thisClient->http); + * code in HandleIMSReply() */ + removeStoreReference(&old_sc, &old_entry); + safe_free(tempBuffer.data); + cbdataReferenceDone(http); } -void * -clientReplyNewContext(clientHttpRequest * clientContext) -{ - clientReplyContext *context = new clientReplyContext; - context->http = cbdataReference(clientContext); - return context; -} +clientReplyContext::clientReplyContext(clientHttpRequest *clientContext) : http (cbdataReference(clientContext)), old_entry (NULL), old_sc(NULL) +{} /* create an error in the store awaiting the client side to read it. */ +/* This may be better placed in the clientStream logic, but it has not been + * relocated there yet + */ void -clientSetReplyToError(void *data, - err_type err, http_status status, method_t method, char const *uri, +clientReplyContext::setReplyToError( + err_type err, http_status status, method_t method, char const *uri, - struct in_addr *addr, request_t * failedrequest, char *unparsedrequest, - auth_user_request_t * auth_user_request) + struct in_addr *addr, request_t * failedrequest, char *unparsedrequest, + auth_user_request_t * auth_user_request) { - clientReplyContext *context = (clientReplyContext *)data; ErrorState *errstate = clientBuildError(err, status, uri, addr, failedrequest); if (unparsedrequest) errstate->request_hdrs = xstrdup(unparsedrequest); - if (status == HTTP_NOT_IMPLEMENTED && context->http->request) + if (status == HTTP_NOT_IMPLEMENTED && http->request) /* prevent confusion over whether we default to persistent or not */ - context->http->request->flags.proxy_keepalive = 0; + http->request->flags.proxy_keepalive = 0; - context->http->al.http.code = errstate->httpStatus; + http->al.http.code = errstate->httpStatus; - context->http->entry = - clientCreateStoreEntry(context, method, request_flags()); + createStoreEntry(method, request_flags()); if (auth_user_request) { @@ -219,20 +108,20 @@ clientSetReplyToError(void *data, } assert(errstate->callback_data == NULL); - errorAppendEntry(context->http->entry, errstate); + errorAppendEntry(http->entry, errstate); /* Now the caller reads to get this */ } void -clientRemoveStoreReference(clientReplyContext * context, store_client ** scp, - StoreEntry ** ep) +clientReplyContext::removeStoreReference(store_client ** scp, + StoreEntry ** ep) { StoreEntry *e; store_client *sc = *scp; if ((e = *ep) != NULL) { *ep = NULL; - storeUnregister(sc, e, context); + storeUnregister(sc, e, this); *scp = NULL; storeUnlockObject(e); } @@ -243,7 +132,7 @@ clientReplyContext::operator new (size_t byteCount) { /* derived classes with different sizes must implement their own new */ assert (byteCount == sizeof (clientReplyContext)); - CBDATA_INIT_TYPE_FREECB(clientReplyContext, clientReplyFree); + CBDATA_INIT_TYPE(clientReplyContext); return cbdataAlloc(clientReplyContext); } @@ -253,13 +142,18 @@ clientReplyContext::operator delete (void *address) cbdataFree (address); } +void +clientReplyContext::deleteSelf() const +{ + delete this; +} void -clientReplyContext::saveState(clientHttpRequest * http) +clientReplyContext::saveState() { assert(old_sc == NULL); debug(88, 3)("clientReplyContext::saveState: saving store context\n"); - http->old_entry = http->entry; + old_entry = http->entry; old_sc = sc; old_reqsize = reqsize; tempBuffer.offset = reqofs; @@ -271,26 +165,27 @@ clientReplyContext::saveState(clientHttpRequest * http) } void -clientReplyContext::restoreState(clientHttpRequest * http) +clientReplyContext::restoreState() { assert(old_sc != NULL); debug(88, 3)("clientReplyContext::restoreState: Restoring store context\n"); - http->entry = http->old_entry; + removeStoreReference(&sc, &http->entry); + http->entry = old_entry; sc = old_sc; reqsize = old_reqsize; reqofs = tempBuffer.offset; /* Prevent accessed the old saved entries */ - http->old_entry = NULL; + old_entry = NULL; old_sc = NULL; old_reqsize = 0; tempBuffer.offset = 0; } void -startError(clientReplyContext * context, clientHttpRequest * http, ErrorState * err) +clientReplyContext::startError(ErrorState * err) { - http->entry = clientCreateStoreEntry(context, http->request->method, request_flags()); - triggerInitialStoreReadWithClientParameters(context, http); + createStoreEntry(http->request->method, request_flags()); + triggerInitialStoreRead(); errorAppendEntry(http->entry, err); } @@ -304,32 +199,28 @@ clientReplyContext::getNextNode() const * header offset */ void -triggerInitialStoreReadWithClientParameters(clientReplyContext * context, clientHttpRequest * http) +clientReplyContext::triggerInitialStoreRead() { - clientStreamNode *next = (clientStreamNode *)http->client_stream.head->next->data; StoreIOBuffer tempBuffer; - /* collapse this to one object if we never tickle the assert */ - assert(context->http == http); - /* when confident, 0 becomes context->reqofs, and then this factors into + /* when confident, 0 becomes reqofs, and then this factors into * startSendProcess */ - assert(context->reqofs == 0); + assert(reqofs == 0); tempBuffer.offset = 0; - tempBuffer.length = next->readBuffer.length; - tempBuffer.data = next->readBuffer.data; - storeClientCopy(context->sc, http->entry, tempBuffer, clientSendMoreData, context); + tempBuffer.length = next()->readBuffer.length; + tempBuffer.data = next()->readBuffer.data; + storeClientCopy(sc, http->entry, tempBuffer, SendMoreData, this); } /* there is an expired entry in the store. * setup a temporary buffer area and perform an IMS to the origin */ -static void -clientProcessExpired(clientReplyContext * context) +void +clientReplyContext::processExpired() { - clientHttpRequest *http = context->http; char *url = http->uri; StoreEntry *entry = NULL; - debug(88, 3)("clientProcessExpired: '%s'", http->uri); + debug(88, 3)("clientReplyContext::processExpired: '%s'", http->uri); assert(http->entry->lastmod >= 0); /* * check if we are allowed to contact other servers @@ -337,8 +228,8 @@ clientProcessExpired(clientReplyContext * context) * a stale entry *if* it matches client requirements */ - if (clientOnlyIfCached(http)) { - clientProcessOnlyIfCachedMiss(context); + if (http->onlyIfCached()) { + processOnlyIfCachedMiss(); return; } @@ -346,21 +237,21 @@ clientProcessExpired(clientReplyContext * context) #if STORE_CLIENT_LIST_DEBUG /* Prevent a race with the store client memory free routines */ - assert(storeClientIsThisAClient(context->sc, context)); + assert(storeClientIsThisAClient(sc, this)); #endif /* Prepare to make a new temporary request */ - context->saveState(http); + saveState(); entry = storeCreateEntry(url, http->log_uri, http->request->flags, http->request->method); /* NOTE, don't call storeLockObject(), storeCreateEntry() does it */ - context->sc = storeClientListAdd(entry, context); + sc = storeClientListAdd(entry, this); #if DELAY_POOLS /* delay_id is already set on original store client */ - context->sc->setDelayId(DelayId::DelayClient(http)); + sc->setDelayId(DelayId::DelayClient(http)); #endif - http->request->lastmod = http->old_entry->lastmod; - debug(88, 5)("clientProcessExpired : lastmod %ld", + http->request->lastmod = old_entry->lastmod; + debug(88, 5)("clientReplyContext::processExpired : lastmod %ld", (long int) entry->lastmod); http->entry = entry; assert(http->out.offset == 0); @@ -368,89 +259,45 @@ clientProcessExpired(clientReplyContext * context) /* Register with storage manager to receive updates when data comes in. */ if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) - debug(88, 0) ("clientProcessExpired: Found ENTRY_ABORTED object"); + debug(88, 0) ("clientReplyContext::processExpired: Found ENTRY_ABORTED object"); { - StoreIOBuffer tempBuffer; /* start counting the length from 0 */ - tempBuffer.offset = 0; - tempBuffer.length = HTTP_REQBUF_SZ; - tempBuffer.data = context->tempbuf; - storeClientCopy(context->sc, entry, - tempBuffer, clientHandleIMSReply, context); - } -} - -int -modifiedSince(StoreEntry * entry, request_t * request) -{ - int object_length; - time_t mod_time = entry->lastmod; - debug(88, 3) ("modifiedSince: '%s'\n", storeUrl(entry)); - - if (mod_time < 0) - mod_time = entry->timestamp; - - debug(88, 3) ("modifiedSince: mod_time = %ld\n", (long int) mod_time); - - if (mod_time < 0) - return 1; - - /* Find size of the object */ - object_length = entry->getReply()->content_length; - - if (object_length < 0) - object_length = contentLen(entry); - - if (mod_time > request->ims) { - debug(88, 3) ("--> YES: entry newer than client\n"); - return 1; - } else if (mod_time < request->ims) { - debug(88, 3) ("--> NO: entry older than client\n"); - return 0; - } else if (request->imslen < 0) { - debug(88, 3) ("--> NO: same LMT, no client length\n"); - return 0; - } else if (request->imslen == object_length) { - debug(88, 3) ("--> NO: same LMT, same length\n"); - return 0; - } else { - debug(88, 3) ("--> YES: same LMT, different length\n"); - return 1; + StoreIOBuffer tempBuffer(HTTP_REQBUF_SZ, 0, tempbuf); + storeClientCopy(sc, entry, tempBuffer, HandleIMSReply, this); } } -static int -clientGetsOldEntry(StoreEntry * new_entry, StoreEntry * old_entry, - request_t * request) +bool +clientReplyContext::clientGetsOldEntry()const { - const http_status status = new_entry->getReply()->sline.status; + const http_status status = http->entry->getReply()->sline.status; if (0 == status) { debug(88, 5) ("clientGetsOldEntry: YES, broken HTTP reply\n"); - return 1; + return true; } /* If the reply is a failure then send the old object as a last * resort */ if (status >= 500 && status < 600) { debug(88, 3) ("clientGetsOldEntry: YES, failure reply=%d\n", status); - return 1; + return true; } /* If the reply is anything but "Not Modified" then * we must forward it to the client */ if (HTTP_NOT_MODIFIED != status) { debug(88, 5) ("clientGetsOldEntry: NO, reply=%d\n", status); - return 0; + return false; } /* If the client did not send IMS in the request, then it * must get the old object, not this "Not Modified" reply * REGARDLESS of validation */ - if (!request->flags.ims) { + if (!http->request->flags.ims) { debug(88, 5) ("clientGetsOldEntry: YES, no client IMS\n"); - return 1; + return true; } /* If key metadata in the reply are not consistent with the @@ -461,23 +308,23 @@ clientGetsOldEntry(StoreEntry * new_entry, StoreEntry * old_entry, /* This is a duplicate call through the HandleIMS code path. * Can we guarantee we don't need it elsewhere? */ - if (!httpReplyValidatorsMatch(new_entry->getReply(), + if (!httpReplyValidatorsMatch(http->entry->getReply(), old_entry->getReply())) { debug(88, 5) ("clientGetsOldEntry: NO, Old object has been invalidated" "by the new one\n"); - return 0; + return false; } /* If the client IMS time is prior to the entry LASTMOD time we * need to send the old object */ - if (modifiedSince(old_entry, request)) { + if (old_entry->modifiedSince(http->request)) { debug(88, 5) ("clientGetsOldEntry: YES, modified since %ld\n", - (long int) request->ims); - return 1; + (long int) http->request->ims); + return true; } debug(88, 5) ("clientGetsOldEntry: NO, new one is fine\n"); - return 0; + return false; } void @@ -485,193 +332,198 @@ clientReplyContext::sendClientUpstreamResponse() { StoreIOBuffer tempresult; http->logType = LOG_TCP_REFRESH_MISS; - clientRemoveStoreReference(this, &old_sc, &http->old_entry); + removeStoreReference(&old_sc, &old_entry); /* here the data to send is the data we just recieved */ tempBuffer.offset = 0; old_reqsize = 0; - /* clientSendMoreData tracks the offset as well. + /* sendMoreData tracks the offset as well. * Force it back to zero */ reqofs = 0; assert(!EBIT_TEST(http->entry->flags, ENTRY_ABORTED)); - /* TODO: provide SendMoreData with the ready parsed reply */ + /* TODO: provide sendMoreData with the ready parsed reply */ tempresult.length = reqsize; tempresult.data = tempbuf; - clientSendMoreData(this, tempresult); + sendMoreData(tempresult); } void -clientHandleIMSReply(void *data, StoreIOBuffer result) +clientReplyContext::HandleIMSReply(void *data, StoreIOBuffer result) { clientReplyContext *context = (clientReplyContext *)data; - clientHttpRequest *http = context->http; - StoreEntry *entry = http->entry; - const char *url = storeUrl(entry); - int unlink_request = 0; - StoreEntry *oldentry; - http_status status; - debug(88, 3) ("clientHandleIMSReply: %s, %lu bytes\n", url, - (long unsigned) result.length); - - if (entry == NULL) { - return; - } - - if (result.flags.error && !EBIT_TEST(entry->flags, ENTRY_ABORTED)) { - return; - } + context->handleIMSReply(result); +} - /* update size of the request */ - context->reqsize = result.length + context->reqofs; +void +clientReplyContext::sendClientOldEntry() +{ + /* Get the old request back */ + restoreState(); + /* here the data to send is in the next nodes buffers already */ + assert(!EBIT_TEST(http->entry->flags, ENTRY_ABORTED)); + /* sendMoreData tracks the offset as well. + * Force it back to zero */ + reqofs = 0; + StoreIOBuffer tempresult (reqsize, reqofs, next()->readBuffer.data); + sendMoreData(tempresult); +} - status = entry->getReply()->sline.status; +void +clientReplyContext::cleanUpAfterIMSCheck() +{ + debug(88, 3) ("clientHandleIMSReply: ABORTED '%s'\n", storeUrl(http->entry)); + /* We have an existing entry, but failed to validate it */ + /* Its okay to send the old one anyway */ + http->logType = LOG_TCP_REFRESH_FAIL_HIT; + sendClientOldEntry(); +} - if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { - debug(88, 3) ("clientHandleIMSReply: ABORTED '%s'\n", url); - /* We have an existing entry, but failed to validate it */ - /* Its okay to send the old one anyway */ +void +clientReplyContext::handlePartialIMSHeaders() +{ + /* more headers needed to decide */ + debug(88, 3) ("clientHandleIMSReply: Incomplete headers for '%s'\n", + storeUrl(http->entry)); + + if (reqsize >= HTTP_REQBUF_SZ) { + /* will not get any bigger than that */ + debug(88, 3) + ("clientHandleIMSReply: Reply is too large '%s', using old entry\n", + storeUrl(http->entry)); + /* use old entry, this repeats the code above */ http->logType = LOG_TCP_REFRESH_FAIL_HIT; - clientRemoveStoreReference(context, &context->sc, &entry); - /* Get the old request back */ - context->restoreState(http); - entry = http->entry; - return; + sendClientOldEntry(); + } else { + reqofs = reqsize; + waitForMoreData(); } +} - if (STORE_PENDING == entry->store_status && 0 == status) { - /* more headers needed to decide */ - debug(88, 3) ("clientHandleIMSReply: Incomplete headers for '%s'\n", - url); - - if (result.length + context->reqsize >= HTTP_REQBUF_SZ) { - /* will not get any bigger than that */ - debug(88, 3) - ("clientHandleIMSReply: Reply is too large '%s', using old entry\n", - url); - /* use old entry, this repeats the code abovez */ - http->logType = LOG_TCP_REFRESH_FAIL_HIT; - clientRemoveStoreReference(context, &context->sc, &entry); - entry = http->entry = http->old_entry; - /* Get the old request back */ - context->restoreState(http); - entry = http->entry; - } else { - context->reqofs += result.length; - context->waitForMoreData(result); +void +clientReplyContext::handleIMSGiveClientUpdatedOldEntry() +{ + /* We initiated the IMS request and the IMS is compatible with + * our object. As the client is not expecting + * 304, so put the good one back. First, make sure the old entry + * headers have been loaded from disk. */ + http->logType = LOG_TCP_REFRESH_HIT; + + if (httpReplyValidatorsMatch(http->entry->getReply(), + old_entry->getReply())) { + int unlink_request = 0; + + if (old_entry->mem_obj->request == NULL) { + old_entry->mem_obj->request = requestLink(http->entry->mem_obj->request); + unlink_request = 1; } - return; - } - - if (clientGetsOldEntry(entry, http->old_entry, http->request)) { - /* We initiated the IMS request and the IMS is compatible with - * our object. As the client is not expecting - * 304, so put the good one back. First, make sure the old entry - * headers have been loaded from disk. */ - clientStreamNode *next = (clientStreamNode *)context->http->client_stream.head->next->data; - StoreIOBuffer tempresult; - oldentry = http->old_entry; - http->logType = LOG_TCP_REFRESH_HIT; - - if (httpReplyValidatorsMatch(entry->getReply(), - http->old_entry->getReply())) { - if (oldentry->mem_obj->request == NULL) { - oldentry->mem_obj->request = requestLink(entry->mem_obj->request); - unlink_request = 1; - } - - /* Don't memcpy() the whole reply structure here. For example, - * www.thegist.com (Netscape/1.13) returns a content-length for - * 304's which seems to be the length of the 304 HEADERS!!! and - * not the body they refer to. */ - httpReplyUpdateOnNotModified((HttpReply *)oldentry->getReply(), entry->getReply()); + /* Don't memcpy() the whole reply structure here. For example, + * www.thegist.com (Netscape/1.13) returns a content-length for + * 304's which seems to be the length of the 304 HEADERS!!! and + * not the body they refer to. */ + httpReplyUpdateOnNotModified((HttpReply *)old_entry->getReply(), http->entry->getReply()); - storeTimestampsSet(oldentry); + storeTimestampsSet(old_entry); - clientRemoveStoreReference(context, &context->sc, &entry); + old_entry->timestamp = squid_curtime; - oldentry->timestamp = squid_curtime; - - if (unlink_request) { - requestUnlink(oldentry->mem_obj->request); - oldentry->mem_obj->request = NULL; - } + if (unlink_request) { + requestUnlink(old_entry->mem_obj->request); + old_entry->mem_obj->request = NULL; } + } - /* Get the old request back */ - context->restoreState(http); + sendClientOldEntry(); +} + +void +clientReplyContext::handleIMSGiveClientNewEntry() +{ + /* The client gets the new entry, + * either as a 304 (they initiated the IMS) or + * as a full request from the upstream + * The new entry is *not* a 304 reply, or + * is a 304 that is incompatible with our cached entities. + */ - entry = http->entry; + if (http->request->flags.ims) { + /* The client asked for a IMS, and can deal + * with any reply + * XXX TODO: invalidate our object if it's not valid any more. + * Send the IMS reply to the client. + */ + sendClientUpstreamResponse(); + } else if (httpReplyValidatorsMatch (http->entry->getReply(), + old_entry->getReply())) { + /* Our object is usable once updated */ + /* the client did not ask for IMS, send the whole object + */ + /* the client needs to get this reply */ + StoreIOBuffer tempresult; + http->logType = LOG_TCP_REFRESH_MISS; - /* here the data to send is in the next nodes buffers already */ - assert(!EBIT_TEST(entry->flags, ENTRY_ABORTED)); + if (HTTP_NOT_MODIFIED == http->entry->getReply()->sline.status) { + httpReplyUpdateOnNotModified((HttpReply *)old_entry->getReply(), + http->entry->getReply()); + storeTimestampsSet(old_entry); + http->logType = LOG_TCP_REFRESH_HIT; + } - tempresult.length = context->reqsize; + removeStoreReference(&old_sc, &old_entry); + /* here the data to send is the data we just recieved */ + tempBuffer.offset = 0; + old_reqsize = 0; + /* clientSendMoreData tracks the offset as well. + * Force it back to zero */ + reqofs = 0; + assert(!EBIT_TEST(http->entry->flags, ENTRY_ABORTED)); + /* TODO: provide SendMoreData with the ready parsed reply */ + tempresult.length = reqsize; + tempresult.data = tempbuf; + sendMoreData(tempresult); + } else { + /* the client asked for the whole object, and + * 1) our object was stale + * 2) our internally generated IMS failed to validate + * 3) the server sent incompatible headers in it's reply + */ + http->logType = LOG_TCP_REFRESH_MISS; + processMiss(); + /* We start over for everything except IMS because: + * 1) HEAD requests will go straight through now + * 2) GET requests will go straight through now + * 3) IMS requests are a corner case. If the server + * decided to give us different data, we should give + * that to the client, which means returning our IMS request. + */ + } +} - tempresult.data = next->readBuffer.data; +void +clientReplyContext::handleIMSReply(StoreIOBuffer result) +{ + debug(88, 3) ("clientHandleIMSReply: %s, %lu bytes\n", + storeUrl(http->entry), + (long unsigned) result.length); - clientSendMoreData(context, tempresult); + if (http->entry == NULL) + return; + if (result.flags.error && !EBIT_TEST(http->entry->flags, ENTRY_ABORTED)) return; - } else { - /* The client gets the new entry, - * either as a 304 (they initiated the IMS) or - * as a full request from the upstream - * The new entry is *not* a 304 reply, or - * is a 304 that is incompatible with our cached entities. - */ - if (http->request->flags.ims) { - /* The client asked for a IMS, and can deal - * with any reply - * XXX TODO: invalidate our object if it's not valid any more. - * Send the IMS reply to the client. - */ - context->sendClientUpstreamResponse(); - } else if (httpReplyValidatorsMatch (entry->getReply(), - http->old_entry->getReply())) { - /* Our object is usable once updated */ - /* the client did not ask for IMS, send the whole object - */ - /* the client needs to get this reply */ - StoreIOBuffer tempresult; - http->logType = LOG_TCP_REFRESH_MISS; + /* update size of the request */ + reqsize = result.length + reqofs; - if (HTTP_NOT_MODIFIED == entry->getReply()->sline.status) { - httpReplyUpdateOnNotModified((HttpReply *)http->old_entry->getReply(), - entry->getReply()); - storeTimestampsSet(http->old_entry); - http->logType = LOG_TCP_REFRESH_HIT; - } + http_status status = http->entry->getReply()->sline.status; - clientRemoveStoreReference(context, &context->old_sc, &http->old_entry); - /* here the data to send is the data we just recieved */ - context->tempBuffer.offset = 0; - context->old_reqsize = 0; - /* clientSendMoreData tracks the offset as well. - * Force it back to zero */ - context->reqofs = 0; - assert(!EBIT_TEST(entry->flags, ENTRY_ABORTED)); - /* TODO: provide SendMoreData with the ready parsed reply */ - tempresult.length = context->reqsize; - tempresult.data = context->tempbuf; - clientSendMoreData(context, tempresult); - } else { - /* the client asked for the whole object, and - * 1) our object was stale - * 2) our internally generated IMS failed to validate - * 3) the server sent incompatible headers in it's reply - */ - http->logType = LOG_TCP_REFRESH_MISS; - clientProcessMiss(context); - /* We start over for everything except IMS because: - * 1) HEAD requests will go straight through now - * 2) GET requests will go straight through now - * 3) IMS requests are a corner case. If the server - * decided to give us different data, we should give - * that to the client, which means returning our IMS request. - */ - } - } + if (EBIT_TEST(http->entry->flags, ENTRY_ABORTED)) + cleanUpAfterIMSCheck(); + else if (STORE_PENDING == http->entry->store_status && 0 == status) + handlePartialIMSHeaders(); + else if (clientGetsOldEntry()) + handleIMSGiveClientUpdatedOldEntry(); + else + handleIMSGiveClientNewEntry(); } extern "C" CSR clientGetMoreData; @@ -681,14 +533,19 @@ extern "C" CSD clientReplyDetach; * clientCacheHit should only be called until the HTTP reply headers * have been parsed. Normally this should be a single call, but * it might take more than one. As soon as we have the headers, - * we hand off to clientSendMoreData, clientProcessExpired, or - * clientProcessMiss. + * we hand off to clientSendMoreData, processExpired, or + * processMiss. */ void -clientCacheHit(void *data, StoreIOBuffer result) +clientReplyContext::CacheHit(void *data, StoreIOBuffer result) { clientReplyContext *context = (clientReplyContext *)data; - clientHttpRequest *http = context->http; + context->cacheHit (result); +} + +void +clientReplyContext::cacheHit(StoreIOBuffer result) +{ StoreEntry *e = http->entry; request_t *r = http->request; debug(88, 3) ("clientCacheHit: %s, %ud bytes\n", http->uri, (unsigned int)result.length); @@ -700,8 +557,8 @@ clientCacheHit(void *data, StoreIOBuffer result) /* swap in failure */ debug(88, 3) ("clientCacheHit: swapin failure for %s\n", http->uri); http->logType = LOG_TCP_SWAPFAIL_MISS; - clientRemoveStoreReference(context, &context->sc, &http->entry); - clientProcessMiss(context); + removeStoreReference(&sc, &http->entry); + processMiss(); return; } @@ -711,13 +568,13 @@ clientCacheHit(void *data, StoreIOBuffer result) */ /* treat as a miss */ http->logType = LOG_TCP_MISS; - clientProcessMiss(context); + processMiss(); return; } assert(!EBIT_TEST(e->flags, ENTRY_ABORTED)); /* update size of the request */ - context->reqsize = result.length + context->reqofs; + reqsize = result.length + reqofs; if (e->getReply()->sline.status == 0) { /* @@ -726,25 +583,21 @@ clientCacheHit(void *data, StoreIOBuffer result) */ if (e->mem_status == IN_MEMORY || e->store_status == STORE_OK) { - clientProcessMiss(context); - } else if (result.length + context->reqofs >= HTTP_REQBUF_SZ + processMiss(); + } else if (result.length + reqofs >= HTTP_REQBUF_SZ && http->out.offset == 0) { - clientProcessMiss(context); + processMiss(); } else { - clientStreamNode *next; - StoreIOBuffer tempBuffer; debug(88, 3) ("clientCacheHit: waiting for HTTP reply headers\n"); - context->reqofs += result.length; - assert(context->reqofs <= HTTP_REQBUF_SZ); + reqofs += result.length; + assert(reqofs <= HTTP_REQBUF_SZ); /* get the next users' buffer */ - /* FIXME: HTTP_REQBUF_SZ must be wrong here ??! - */ - next = (clientStreamNode *)context->http->client_stream.head->next->data; - tempBuffer.offset = http->out.offset + context->reqofs; - tempBuffer.length = HTTP_REQBUF_SZ; - tempBuffer.data = next->readBuffer.data + context->reqofs; - storeClientCopy(context->sc, e, - tempBuffer, clientCacheHit, context); + StoreIOBuffer tempBuffer; + tempBuffer.offset = http->out.offset + reqofs; + tempBuffer.length = next()->readBuffer.length - reqofs; + tempBuffer.data = next()->readBuffer.data + reqofs; + storeClientCopy(sc, e, + tempBuffer, CacheHit, this); } return; @@ -770,32 +623,32 @@ clientCacheHit(void *data, StoreIOBuffer result) /* This is not the correct entity for this request. We need * to requery the cache. */ - clientRemoveStoreReference(context, &context->sc, &http->entry); + removeStoreReference(&sc, &http->entry); e = NULL; /* Note: varyEvalyateMatch updates the request with vary information * so we only get here once. (it also takes care of cancelling loops) */ debug(88, 2) ("clientProcessHit: Vary detected!\n"); - clientGetMoreData(context->ourNode, http); + clientGetMoreData(ourNode, http); return; case VARY_CANCEL: /* varyEvaluateMatch found a object loop. Process as miss */ debug(88, 1) ("clientProcessHit: Vary object loop!\n"); - clientProcessMiss(context); + processMiss(); return; } if (r->method == METHOD_PURGE) { - clientRemoveStoreReference(context, &context->sc, &http->entry); + removeStoreReference(&sc, &http->entry); e = NULL; - context->purgeRequest(); + purgeRequest(); return; } if (storeCheckNegativeHit(e)) { http->logType = LOG_TCP_NEGATIVE_HIT; - clientSendMoreData(context, result); + sendMoreData(result); } else if (!Config.onoff.offline && refreshCheckHTTP(e, r) && !http->flags.internal) { debug(88, 5) ("clientCacheHit: in refreshCheck() block\n"); /* @@ -816,28 +669,28 @@ clientCacheHit(void *data, StoreIOBuffer result) * we cannot revalidate it. */ http->logType = LOG_TCP_MISS; - clientProcessMiss(context); + processMiss(); } else if (r->flags.nocache) { /* * This did not match a refresh pattern that overrides no-cache * we should honour the client no-cache header. */ http->logType = LOG_TCP_CLIENT_REFRESH_MISS; - clientProcessMiss(context); + processMiss(); } else if (r->protocol == PROTO_HTTP) { /* * Object needs to be revalidated * XXX This could apply to FTP as well, if Last-Modified is known. */ http->logType = LOG_TCP_REFRESH_MISS; - clientProcessExpired(context); + processExpired(); } else { /* * We don't know how to re-validate other protocols. Handle * them as if the object has expired. */ http->logType = LOG_TCP_MISS; - clientProcessMiss(context); + processMiss(); } } else if (r->flags.ims) { /* @@ -848,18 +701,18 @@ clientCacheHit(void *data, StoreIOBuffer result) debug(88, 4) ("clientCacheHit: Reply code %d != 200\n", e->getReply()->sline.status); http->logType = LOG_TCP_MISS; - clientProcessMiss(context); - } else if (modifiedSince(e, http->request)) { + processMiss(); + } else if (e->modifiedSince(http->request)) { http->logType = LOG_TCP_IMS_HIT; - clientSendMoreData(context, result); + sendMoreData(result); } else { - time_t timestamp = e->timestamp; + time_t const timestamp = e->timestamp; HttpReply *temprep = httpReplyMake304 (e->getReply()); http->logType = LOG_TCP_IMS_HIT; - clientRemoveStoreReference(context, &context->sc, &http->entry); - http->entry = e = - clientCreateStoreEntry(context, http->request->method, - request_flags()); + removeStoreReference(&sc, &http->entry); + createStoreEntry(http->request->method, + request_flags()); + e = http->entry; /* * Copy timestamp from the original entry so the 304 * reply has a meaningful Age: header. @@ -871,7 +724,7 @@ clientCacheHit(void *data, StoreIOBuffer result) * Simply mark the request complete in our context and * write the reply struct to the client side */ - triggerInitialStoreReadWithClientParameters(context, http); + triggerInitialStoreRead(); } } else { /* @@ -883,7 +736,7 @@ clientCacheHit(void *data, StoreIOBuffer result) else if (Config.onoff.offline) http->logType = LOG_TCP_OFFLINE_HIT; - clientSendMoreData(context, result); + sendMoreData(result); } } @@ -891,9 +744,8 @@ clientCacheHit(void *data, StoreIOBuffer result) * Prepare to fetch the object as it's a cache miss of some kind. */ void -clientProcessMiss(clientReplyContext * context) +clientReplyContext::processMiss() { - clientHttpRequest *http = context->http; char *url = http->uri; request_t *r = http->request; ErrorState *err = NULL; @@ -912,16 +764,16 @@ clientProcessMiss(clientReplyContext * context) storeEntryDump(http->entry, 1); } - clientRemoveStoreReference(context, &context->sc, &http->entry); + removeStoreReference(&sc, &http->entry); } if (r->method == METHOD_PURGE) { - context->purgeRequest(); + purgeRequest(); return; } - if (clientOnlyIfCached(http)) { - clientProcessOnlyIfCachedMiss(context); + if (http->onlyIfCached()) { + processOnlyIfCachedMiss(); return; } @@ -933,15 +785,14 @@ clientProcessMiss(clientReplyContext * context) err = clientBuildError(ERR_ACCESS_DENIED, HTTP_FORBIDDEN, NULL, &http->conn->peer.sin_addr, http->request); - http->entry = - clientCreateStoreEntry(context, r->method, request_flags()); + createStoreEntry(r->method, request_flags()); errorAppendEntry(http->entry, err); - triggerInitialStoreReadWithClientParameters(context, http); + triggerInitialStoreRead(); return; } else { assert(http->out.offset == 0); - http->entry = clientCreateStoreEntry(context, r->method, r->flags); - triggerInitialStoreReadWithClientParameters(context, http); + createStoreEntry(r->method, r->flags); + triggerInitialStoreRead(); if (http->redirect.status) { HttpReply *rep = httpReplyCreate(); @@ -971,20 +822,17 @@ clientProcessMiss(clientReplyContext * context) * contacting other servers; * respond with a 504 (Gateway Timeout) as suggested in [RFC 2068] */ -static void -clientProcessOnlyIfCachedMiss(clientReplyContext * context) +void +clientReplyContext::processOnlyIfCachedMiss() { - clientHttpRequest *http = context->http; - char *url = http->uri; - request_t *r = http->request; ErrorState *err = NULL; debug(88, 4) ("clientProcessOnlyIfCachedMiss: '%s %s'\n", - RequestMethodStr[r->method], url); + RequestMethodStr[http->request->method], http->uri); http->al.http.code = HTTP_GATEWAY_TIMEOUT; err = clientBuildError(ERR_ONLY_IF_CACHED_MISS, HTTP_GATEWAY_TIMEOUT, NULL, &http->conn->peer.sin_addr, http->request); - clientRemoveStoreReference(context, &context->sc, &http->entry); - startError(context, http, err); + removeStoreReference(&sc, &http->entry); + startError(err); } void @@ -1044,11 +892,10 @@ clientReplyContext::purgeFoundObject(StoreEntry *entry) http->logType = LOG_TCP_HIT; reqofs = 0; tempBuffer.offset = http->out.offset; - clientStreamNode *next = (clientStreamNode *)http->client_stream.head->next->data; - tempBuffer.length = next->readBuffer.length; - tempBuffer.data = next->readBuffer.data; + tempBuffer.length = next()->readBuffer.length; + tempBuffer.data = next()->readBuffer.data; storeClientCopy(sc, http->entry, - tempBuffer, clientCacheHit, this); + tempBuffer, CacheHit, this); } void @@ -1062,7 +909,7 @@ clientReplyContext::purgeRequest() ErrorState *err = clientBuildError(ERR_ACCESS_DENIED, HTTP_FORBIDDEN, NULL, &http->conn->peer.sin_addr, http->request); - startError(this, http, err); + startError(err); return; } @@ -1143,11 +990,9 @@ clientReplyContext::purgeDoPurgeHead(StoreEntry *newEntry) /* FIXME: This doesn't need to go through the store. Simply * push down the client chain */ - http->entry = - clientCreateStoreEntry(this, http->request->method, - request_flags()); + createStoreEntry(http->request->method, request_flags()); - triggerInitialStoreReadWithClientParameters(this, http); + triggerInitialStoreRead(); r = httpReplyCreate(); @@ -1161,38 +1006,36 @@ clientReplyContext::purgeDoPurgeHead(StoreEntry *newEntry) } void -clientTraceReply(clientStreamNode * node, clientReplyContext * context) +clientReplyContext::traceReply(clientStreamNode * node) { HttpReply *rep; http_version_t version; clientStreamNode *next = (clientStreamNode *)node->node.next->data; StoreIOBuffer tempBuffer; - assert(context->http->request->max_forwards == 0); - context->http->entry = - clientCreateStoreEntry(context, context->http->request->method, - request_flags()); - tempBuffer.offset = next->readBuffer.offset + context->headers_sz; + assert(http->request->max_forwards == 0); + createStoreEntry(http->request->method, request_flags()); + tempBuffer.offset = next->readBuffer.offset + headers_sz; tempBuffer.length = next->readBuffer.length; tempBuffer.data = next->readBuffer.data; - storeClientCopy(context->sc, context->http->entry, - tempBuffer, clientSendMoreData, context); - storeReleaseRequest(context->http->entry); - storeBuffer(context->http->entry); + storeClientCopy(sc, http->entry, + tempBuffer, SendMoreData, this); + storeReleaseRequest(http->entry); + storeBuffer(http->entry); rep = httpReplyCreate(); httpBuildVersion(&version, 1, 0); httpReplySetHeaders(rep, version, HTTP_OK, NULL, "text/plain", - httpRequestPrefixLen(context->http->request), 0, squid_curtime); - httpReplySwapOut(rep, context->http->entry); - httpRequestSwapOut(context->http->request, context->http->entry); - context->http->entry->complete(); + httpRequestPrefixLen(http->request), 0, squid_curtime); + httpReplySwapOut(rep, http->entry); + httpRequestSwapOut(http->request, http->entry); + http->entry->complete(); } #define SENDING_BODY 0 #define SENDING_HDRSONLY 1 int -clientCheckTransferDone(clientReplyContext * context) +clientReplyContext::checkTransferDone() { - StoreEntry *entry = context->http->entry; + StoreEntry *entry = http->entry; if (entry == NULL) return 0; @@ -1201,7 +1044,7 @@ clientCheckTransferDone(clientReplyContext * context) * For now, 'done_copying' is used for special cases like * Range and HEAD requests. */ - if (context->http->flags.done_copying) + if (http->flags.done_copying) return 1; /* @@ -1211,9 +1054,9 @@ clientCheckTransferDone(clientReplyContext * context) * RC: Yes. */ if (entry->store_status == STORE_OK) { - return context->storeOKTransferDone(); + return storeOKTransferDone(); } else { - return context->storeNotOKTransferDone(); + return storeNotOKTransferDone(); } } @@ -1267,21 +1110,6 @@ clientReplyContext::storeNotOKTransferDone() const } - -int -clientGotNotEnough(clientHttpRequest const *http) -{ - int cl = - httpReplyBodySize(http->request->method, http->entry->mem_obj->getReply()); - assert(cl >= 0); - - if (http->out.offset < cl) - return 1; - - return 0; -} - - /* A write has completed, what is the next status based on the * canonical request data? * 1 something is wrong @@ -1332,7 +1160,15 @@ clientHttpRequestStatus(int fd, clientHttpRequest const *http) clientStream_status_t clientReplyStatus(clientStreamNode * aNode, clientHttpRequest * http) { - clientReplyContext *context = (clientReplyContext *)aNode->data; + clientReplyContext *context = dynamic_cast(aNode->data.getRaw()); + assert (context); + assert (context->http == http); + return context->replyStatus(); +} + +clientStream_status_t +clientReplyContext::replyStatus() +{ int done; /* Here because lower nodes don't need it */ @@ -1346,7 +1182,7 @@ clientReplyStatus(clientStreamNode * aNode, clientHttpRequest * http) */ return STREAM_FAILED; - if ((done = clientCheckTransferDone(context)) != 0 || context->flags.complete) { + if ((done = checkTransferDone()) != 0 || flags.complete) { debug(88, 5) ("clientReplyStatus: transfer is DONE\n"); /* Ok we're finished, but how? */ @@ -1361,7 +1197,7 @@ clientReplyStatus(clientStreamNode * aNode, clientHttpRequest * http) return STREAM_FAILED; } - if (clientGotNotEnough(http)) { + if (!http->gotEnough()) { debug(88, 5) ("clientReplyStatus: client didn't get all it expected\n"); return STREAM_UNPLANNED_COMPLETE; } @@ -1375,7 +1211,7 @@ clientReplyStatus(clientStreamNode * aNode, clientHttpRequest * http) return STREAM_UNPLANNED_COMPLETE; } - if (clientReplyBodyTooLarge(http->entry->getReply(), http->out.offset)) { + if (http->entry->getReply()->isBodyTooLarge(http->out.offset)) { debug(88, 5) ("clientReplyStatus: client reply body is too large\n"); return STREAM_FAILED; } @@ -1392,8 +1228,8 @@ clientReplyStatus(clientStreamNode * aNode, clientHttpRequest * http) * can choose to block these responses where appropriate, but won't get * mysterious breakages. */ -static int -clientAlwaysAllowResponse(http_status sline) +bool +clientReplyContext::alwaysAllowResponse(http_status sline) const { switch (sline) { @@ -1406,19 +1242,19 @@ clientAlwaysAllowResponse(http_status sline) case HTTP_NO_CONTENT: case HTTP_NOT_MODIFIED: - return 1; + return true; /* unreached */ break; default: - return 0; + return false; } } void -clientObeyConnectionHeader(clientHttpRequest * http, HttpReply * rep) +clientReplyContext::obeyConnectionHeader() { - HttpHeader *hdr = &rep->header; + HttpHeader *hdr = &holdingReply->header; if (httpHeaderHas(hdr, HDR_CONNECTION)) { /* anything that matches Connection list member will be deleted */ @@ -1449,11 +1285,10 @@ clientObeyConnectionHeader(clientHttpRequest * http, HttpReply * rep) * adds extra entries if we have more info than origin server * adds Squid specific entries */ -static void -clientBuildReplyHeader(clientReplyContext *context, HttpReply * rep) +void +clientReplyContext::buildReplyHeader() { - clientHttpRequest * http = context->http; - HttpHeader *hdr = &rep->header; + HttpHeader *hdr = &holdingReply->header; int is_hit = logTypeIsATcpHit(http->logType); request_t *request = http->request; #if DONT_FILTER_THESE @@ -1470,10 +1305,10 @@ clientBuildReplyHeader(clientReplyContext *context, HttpReply * rep) if (is_hit) httpHeaderDelById(hdr, HDR_SET_COOKIE); - clientObeyConnectionHeader(http, rep); + obeyConnectionHeader(); // if (request->range) - // clientBuildRangeHeader(http, rep); + // clientBuildRangeHeader(http, holdingReply); /* * Add a estimated Age header on cache hits. */ @@ -1545,7 +1380,7 @@ clientBuildReplyHeader(clientReplyContext *context, HttpReply * rep) /* Handle authentication headers */ if (request->auth_user_request) - authenticateFixHeader(rep, request->auth_user_request, request, + authenticateFixHeader(holdingReply, request->auth_user_request, request, http->flags.accel, 0); /* Append X-Cache */ @@ -1555,12 +1390,12 @@ clientBuildReplyHeader(clientReplyContext *context, HttpReply * rep) #if USE_CACHE_DIGESTS /* Append X-Cache-Lookup: -- temporary hack, to be removed @?@ @?@ */ httpHeaderPutStrf(hdr, HDR_X_CACHE_LOOKUP, "%s from %s:%d", - context->lookup_type ? context->lookup_type : "NONE", + lookup_type ? lookup_type : "NONE", getMyHostname(), getMyPort()); #endif - if (httpReplyBodySize(request->method, rep) < 0) { + if (httpReplyBodySize(request->method, holdingReply) < 0) { debug(88, 3) ("clientBuildReplyHeader: can't keep-alive, unknown body size\n"); @@ -1572,8 +1407,8 @@ clientBuildReplyHeader(clientReplyContext *context, HttpReply * rep) LOCAL_ARRAY(char, bbuf, MAX_URL + 32); String strVia = httpHeaderGetList(hdr, HDR_VIA); snprintf(bbuf, sizeof(bbuf), "%d.%d %s", - rep->sline.version.major, - rep->sline.version.minor, + holdingReply->sline.version.major, + holdingReply->sline.version.minor, ThisCache); strListAdd(&strVia, bbuf, ','); httpHeaderDelById(hdr, HDR_VIA); @@ -1601,32 +1436,35 @@ clientBuildReplyHeader(clientReplyContext *context, HttpReply * rep) } -static HttpReply * -clientBuildReply(clientReplyContext *context, const char *buf, size_t size) +void +clientReplyContext::buildReply(const char *buf, size_t size) { - HttpReply *rep = httpReplyCreate(); size_t k = headersEnd(buf, size); - if (k && httpReplyParse(rep, buf, k)) { - /* enforce 1.0 reply version */ - httpBuildVersion(&rep->sline.version, 1, 0); - /* do header conversions */ - clientBuildReplyHeader(context, rep); - } else { + if (!k) + return; + + holdReply(httpReplyCreate()); + + if (!httpReplyParse(holdingReply, buf, k)) { /* parsing failure, get rid of the invalid reply */ - httpReplyDestroy(rep); - rep = NULL; + httpReplyDestroy(holdingReply); + holdReply (NULL); /* This is wrong. httpReplyDestroy should to the rep * for us, and we can destroy our own range info */ - if (context->http->request->range) { + if (http->request->range) { /* this will fail and destroy request->range */ - // clientBuildRangeHeader(context->http, rep); + // clientBuildRangeHeader(http, holdingReply); } } - return rep; + /* enforce 1.0 reply version */ + httpBuildVersion(&holdingReply->sline.version, 1, 0); + + /* do header conversions */ + buildReplyHeader(); } void @@ -1759,18 +1597,16 @@ clientReplyContext::identifyFoundObject(StoreEntry *newEntry) void clientGetMoreData(clientStreamNode * aNode, clientHttpRequest * http) { - clientStreamNode *next; - clientReplyContext *context; /* Test preconditions */ assert(aNode != NULL); assert(cbdataReferenceValid(aNode)); - assert(aNode->data != NULL); assert(aNode->node.prev == NULL); assert(aNode->node.next != NULL); - context = (clientReplyContext *)aNode->data; + clientReplyContext *context = dynamic_cast(aNode->data.getRaw()); + assert (context); assert(context->http == http); - next = ( clientStreamNode *)aNode->node.next->data; + clientStreamNode *next = ( clientStreamNode *)aNode->node.next->data; if (!context->ourNode) context->ourNode = aNode; @@ -1783,7 +1619,7 @@ clientGetMoreData(clientStreamNode * aNode, clientHttpRequest * http) tempBuffer.data = next->readBuffer.data; storeClientCopy(context->sc, http->entry, - tempBuffer, clientSendMoreData, context); + tempBuffer, clientReplyContext::SendMoreData, context); return; } @@ -1794,7 +1630,7 @@ clientGetMoreData(clientStreamNode * aNode, clientHttpRequest * http) if (context->http->request->method == METHOD_TRACE) { if (context->http->request->max_forwards == 0) { - clientTraceReply(aNode, context); + context->traceReply(aNode); return; } @@ -1845,10 +1681,10 @@ clientReplyContext::doGetMoreData() tempBuffer.length = getNextNode()->readBuffer.length; tempBuffer.data = getNextNode()->readBuffer.data; storeClientCopy(sc, http->entry, - tempBuffer, clientCacheHit, this); + tempBuffer, CacheHit, this); } else { /* MISS CASE, http->logType is already set! */ - clientProcessMiss(this); + processMiss(); } } @@ -1857,10 +1693,6 @@ void clientReplyDetach(clientStreamNode * node, clientHttpRequest * http) { /* detach from the stream */ - /* NB: This cbdataFrees our context, - * so the clientSendMoreData callback (if any) - * pending in the store will not trigger - */ clientStreamDetach(node, http); } @@ -1869,13 +1701,7 @@ clientReplyDetach(clientStreamNode * node, clientHttpRequest * http) * such, writes processed message to the message recipient */ void -clientSendMoreData(void *data, StoreIOBuffer result) -{ - clientReplyContext::clientSendMoreData (data, result); -} - -void -clientReplyContext::clientSendMoreData (void *data, StoreIOBuffer result) +clientReplyContext::SendMoreData(void *data, StoreIOBuffer result) { clientReplyContext *context = static_cast(data); context->sendMoreData (result); @@ -1942,7 +1768,7 @@ clientReplyContext::next() const } void -clientReplyContext::waitForMoreData (StoreIOBuffer const &result) +clientReplyContext::waitForMoreData () { debug(88,5)("clientReplyContext::waitForMoreData: Waiting for more data to parse reply headers in client side.\n"); /* We don't have enough to parse the metadata yet */ @@ -1956,7 +1782,7 @@ clientReplyContext::waitForMoreData (StoreIOBuffer const &result) void clientReplyContext::startSendProcess() { - debug(88,5)("clientReplyContext::startSendProcess: triggering store read to clientSendMoreData\n"); + debug(88,5)("clientReplyContext::startSendProcess: triggering store read to SendMoreData\n"); assert(reqofs <= HTTP_REQBUF_SZ); /* TODO: copy into the supplied buffer */ StoreIOBuffer tempBuffer; @@ -1964,23 +1790,30 @@ clientReplyContext::startSendProcess() tempBuffer.length = next()->readBuffer.length - reqofs; tempBuffer.data = next()->readBuffer.data + reqofs; storeClientCopy(sc, http->entry, - tempBuffer, clientSendMoreData, this); + tempBuffer, SendMoreData, this); +} + +void +clientReplyContext::holdReply(HttpReply *aReply) +{ + assert (!holdingReply || !aReply); + holdingReply = aReply; } void clientReplyContext::processReplyAccess () { HttpReply *rep = holdingReply; - holdingReply = NULL; + holdReply(NULL); httpReplyBodyBuildSize(http->request, rep, &Config.ReplyBodySize); - if (clientReplyBodyTooLarge(rep, rep->content_length)) { + if (rep->isBodyTooLarge(rep->content_length)) { ErrorState *err = clientBuildError(ERR_TOO_BIG, HTTP_FORBIDDEN, NULL, http->conn ? &http->conn->peer.sin_addr : &no_addr, http->request); - clientRemoveStoreReference(this, &sc, &http->entry); - startError(this, http, err); + removeStoreReference(&sc, &http->entry); + startError(err); httpReplyDestroy(rep); return; } @@ -1989,29 +1822,29 @@ clientReplyContext::processReplyAccess () ACLChecklist *replyChecklist; replyChecklist = clientAclChecklistCreate(Config.accessList.reply, http); replyChecklist->reply = rep; - holdingReply = rep; - replyChecklist->nonBlockingCheck(ProcessReply, this); + holdReply (rep); + replyChecklist->nonBlockingCheck(ProcessReplyAccessResult, this); } void -clientReplyContext::ProcessReply (int rv, void *voidMe) +clientReplyContext::ProcessReplyAccessResult (int rv, void *voidMe) { clientReplyContext *me = static_cast(voidMe); - me->processReply(rv); + me->processReplyAccessResult(rv); } void -clientReplyContext::processReply(bool accessAllowed) +clientReplyContext::processReplyAccessResult(bool accessAllowed) { debug(88, 2) ("The reply for %s %s is %s, because it matched '%s'\n", RequestMethodStr[http->request->method], http->uri, accessAllowed ? "ALLOWED" : "DENIED", AclMatchedName ? AclMatchedName : "NO ACL's"); HttpReply *rep = holdingReply; - holdingReply = NULL; + holdReply (NULL); if (!accessAllowed && rep->sline.status != HTTP_FORBIDDEN - && !clientAlwaysAllowResponse(rep->sline.status)) { + && !alwaysAllowResponse(rep->sline.status)) { /* the if above is slightly broken, but there is no way * to tell if this is a squid generated error page, or one from * upstream at this point. */ @@ -2020,8 +1853,8 @@ clientReplyContext::processReply(bool accessAllowed) clientBuildError(ERR_ACCESS_DENIED, HTTP_FORBIDDEN, NULL, http->conn ? &http->conn->peer.sin_addr : &no_addr, http->request); - clientRemoveStoreReference(this, &sc, &http->entry); - startError(this, http, err); + removeStoreReference(&sc, &http->entry); + startError(err); httpReplyDestroy(rep); return; } @@ -2029,12 +1862,12 @@ clientReplyContext::processReply(bool accessAllowed) ssize_t body_size = reqofs - rep->hdr_sz; assert(body_size >= 0); debug(88,3) - ("clientSendMoreData: Appending %d bytes after %d bytes of headers\n", + ("clientReplyContext::sendMoreData: Appending %d bytes after %d bytes of headers\n", (int) body_size, rep->hdr_sz); #if ESI if (http->flags.accel && rep->sline.status != HTTP_FORBIDDEN && - !clientAlwaysAllowResponse(rep->sline.status) && + !alwaysAllowResponse(rep->sline.status) && esiEnableProcessing(rep)) { debug(88, 2) ("Enabling ESI processing for %s\n", http->uri); clientStreamInsertHead(&http->client_stream, esiStreamRead, @@ -2070,7 +1903,7 @@ clientReplyContext::processReply(bool accessAllowed) tempBuffer.data = body_buf; } - /* TODO: move the data in the buffer back by the request header size */ + /* TODO??: move the data in the buffer back by the request header size */ clientStreamCallback((clientStreamNode *)http->client_stream.head->data, http, rep, tempBuffer); @@ -2083,7 +1916,6 @@ clientReplyContext::sendMoreData (StoreIOBuffer result) StoreEntry *entry = http->entry; ConnStateData *conn = http->conn; int fd = conn ? conn->fd : -1; - HttpReply *rep = NULL; char *buf = next()->readBuffer.data; char *body_buf = buf; @@ -2121,10 +1953,10 @@ clientReplyContext::sendMoreData (StoreIOBuffer result) makeThisHead(); - debug(88, 5) ("clientSendMoreData: %s, %d bytes (%u new bytes)\n", + debug(88, 5) ("clientReplyContext::sendMoreData: %s, %d bytes (%u new bytes)\n", http->uri, (int) reqofs, (unsigned int)result.length); - debug(88, 5) ("clientSendMoreData: FD %d '%s', out.offset=%ld \n", + debug(88, 5) ("clientReplyContext::sendMoreData: FD %d '%s', out.offset=%ld \n", fd, storeUrl(entry), (long int) http->out.offset); /* update size of the request */ @@ -2160,24 +1992,23 @@ clientReplyContext::sendMoreData (StoreIOBuffer result) } } - rep = clientBuildReply(this, buf, reqofs); + buildReply(buf, reqofs); ssize_t body_size = reqofs; - if (rep) { - holdingReply = rep; + if (holdingReply) { holdingBuffer = result; processReplyAccess (); return; } else if (reqofs < HTTP_REQBUF_SZ && entry->store_status == STORE_PENDING) { - waitForMoreData(result); + waitForMoreData(); return; } else if (http->request->method == METHOD_HEAD) { /* * If we are here, then store_status == STORE_OK and it * seems we have a HEAD repsponse which is missing the * empty end-of-headers line (home.mira.net, phttpd/0.99.72 - * does this). Because clientBuildReply() fails we just + * does this). Because buildReply() fails we just * call this reply a body, set the done_copying flag and * continue... */ @@ -2195,16 +2026,15 @@ clientReplyContext::sendMoreData (StoreIOBuffer result) */ http->request->flags.proxy_keepalive = 0; - StoreIOBuffer tempBuffer; assert(body_buf && body_size); - tempBuffer.length = body_size; - tempBuffer.data = body_buf; + StoreIOBuffer tempBuffer (body_size, 0 ,body_buf); clientStreamCallback((clientStreamNode *)http->client_stream.head->data, http, NULL, tempBuffer); } else { debug (88,0)("clientReplyContext::sendMoreData: Unable to parse reply headers within a single HTTP_REQBUF_SZ length buffer\n"); StoreIOBuffer tempBuffer; tempBuffer.flags.error = 1; + /* XXX FIXME: make an html error page here */ sendStreamError(tempBuffer); return; } @@ -2212,81 +2042,52 @@ clientReplyContext::sendMoreData (StoreIOBuffer result) fatal ("clientReplyContext::sendMoreData: Unreachable code reached \n"); } -int -clientReplyBodyTooLarge(HttpReply const * rep, ssize_t clen) -{ - if (0 == rep->maxBodySize) - return 0; /* disabled */ - - if (clen < 0) - return 0; /* unknown */ - if ((unsigned int)clen > rep->maxBodySize) - return 1; /* too large */ - - return 0; -} - -/* - * returns true if client specified that the object must come from the cache - * without contacting origin server - */ -static int -clientOnlyIfCached(clientHttpRequest * http) -{ - const request_t *r = http->request; - assert(r); - return r->cache_control && - EBIT_TEST(r->cache_control->mask, CC_ONLY_IF_CACHED); -} /* Using this breaks the client layering just a little! */ -StoreEntry * -clientCreateStoreEntry(clientReplyContext * context, method_t m, - request_flags flags) +void +clientReplyContext::createStoreEntry(method_t m, request_flags flags) { - clientHttpRequest *h = context->http; - StoreEntry *e; - assert(h != NULL); + assert(http != NULL); /* * For erroneous requests, we might not have a h->request, * so make a fake one. */ - if (h->request == NULL) - h->request = requestLink(requestCreate(m, PROTO_NONE, null_string)); + if (http->request == NULL) + http->request = requestLink(requestCreate(m, PROTO_NONE, null_string)); - e = storeCreateEntry(h->uri, h->log_uri, flags, m); + StoreEntry *e = storeCreateEntry(http->uri, http->log_uri, flags, m); - context->sc = storeClientListAdd(e, context); + sc = storeClientListAdd(e, this); #if DELAY_POOLS - context->sc->setDelayId(DelayId::DelayClient(h)); + sc->setDelayId(DelayId::DelayClient(http)); #endif - context->reqofs = 0; + reqofs = 0; - context->reqsize = 0; + reqsize = 0; /* I don't think this is actually needed! -- adrian */ - /* h->reqbuf = h->norm_reqbuf; */ - // assert(h->reqbuf == h->norm_reqbuf); + /* http->reqbuf = http->norm_reqbuf; */ + // assert(http->reqbuf == http->norm_reqbuf); /* The next line is illegal because we don't know if the client stream * buffers have been set up */ - // storeClientCopy(h->sc, e, 0, HTTP_REQBUF_SZ, h->reqbuf, - // clientSendMoreData, context); + // storeClientCopy(http->sc, e, 0, HTTP_REQBUF_SZ, http->reqbuf, + // SendMoreData, this); /* So, we mark the store logic as complete */ - context->flags.storelogiccomplete = 1; + this->flags.storelogiccomplete = 1; /* and get the caller to request a read, from whereever they are */ /* NOTE: after ANY data flows down the pipe, even one step, * this function CAN NOT be used to manage errors */ - return e; + http->entry = e; } ErrorState * diff --git a/src/client_side_request.cc b/src/client_side_request.cc index 67bf096b5d..ee4888c128 100644 --- a/src/client_side_request.cc +++ b/src/client_side_request.cc @@ -1,6 +1,6 @@ /* - * $Id: client_side_request.cc,v 1.19 2003/03/04 01:40:27 robertc Exp $ + * $Id: client_side_request.cc,v 1.20 2003/03/15 04:17:39 robertc Exp $ * * DEBUG: section 85 Client-side Request Routines * AUTHOR: Robert Collins (Originally Duane Wessels in client_side.c) @@ -49,6 +49,9 @@ #include "ACLChecklist.h" #include "ACL.h" #include "client_side.h" +#include "client_side_reply.h" +#include "Store.h" +#include "HttpReply.h" #if LINGERING_CLOSE #define comm_close comm_lingering_close @@ -56,7 +59,7 @@ static const char *const crlf = "\r\n"; -class ClientRequestContext +class ClientRequestContext : public RefCountable { public: @@ -173,6 +176,18 @@ ClientHttpRequest::ClientHttpRequest() start = current_time; } +/* + * returns true if client specified that the object must come from the cache + * without contacting origin server + */ +bool +ClientHttpRequest::onlyIfCached()const +{ + assert(request); + return request->cache_control && + EBIT_TEST(request->cache_control->mask, CC_ONLY_IF_CACHED); +} + /* * This function is designed to serve a fairly specific purpose. * Occasionally our vBNS-connected caches can talk to each other, but not @@ -267,7 +282,7 @@ ClientHttpRequest::~ClientHttpRequest() */ int /* returns nonzero on failure */ clientBeginRequest(method_t method, char const *url, CSCB * streamcallback, - CSD * streamdetach, void *streamdata, HttpHeader const *header, + CSD * streamdetach, ClientStreamData streamdata, HttpHeader const *header, char *tailbuf, size_t taillen) { size_t url_sz; @@ -285,7 +300,7 @@ clientBeginRequest(method_t method, char const *url, CSCB * streamcallback, tempBuffer.data = tailbuf; /* client stream setup */ clientStreamInit(&http->client_stream, clientGetMoreData, clientReplyDetach, - clientReplyStatus, clientReplyNewContext(http), streamcallback, + clientReplyStatus, new clientReplyContext(http), streamcallback, streamdetach, streamdata, tempBuffer); /* make it visible in the 'current acctive requests list' */ dlinkAdd(http, &http->active, &ClientActiveRequests); @@ -426,12 +441,14 @@ clientAccessCheckDone(int answer, void *data) page_id = ERR_ACCESS_DENIED; } - clientSetReplyToError(node->data, page_id, status, - http->request->method, NULL, - http->conn ? &http->conn->peer.sin_addr : &no_addr, http->request, - NULL, http->conn - && http->conn->auth_user_request ? http->conn-> - auth_user_request : http->request->auth_user_request); + clientReplyContext *repContext = dynamic_cast(node->data.getRaw()); + assert (repContext); + repContext->setReplyToError(page_id, status, + http->request->method, NULL, + http->conn ? &http->conn->peer.sin_addr : &no_addr, http->request, + NULL, http->conn + && http->conn->auth_user_request ? http->conn-> + auth_user_request : http->request->auth_user_request); node = (clientStreamNode *)http->client_stream.tail->data; clientStreamRead(node, http, node->readBuffer); } @@ -846,3 +863,17 @@ ClientHttpRequest::httpStart() clientStreamNode *node = (clientStreamNode *)client_stream.tail->data; clientStreamRead(node, this, node->readBuffer); } + +bool +ClientHttpRequest::gotEnough() const +{ + int contentLength = + httpReplyBodySize(request->method, entry->mem_obj->getReply()); + assert(contentLength >= 0); + + if (out.offset < contentLength) + return false; + + return true; +} + diff --git a/src/client_side_request.h b/src/client_side_request.h index 0b15d91e85..62b0cbf922 100644 --- a/src/client_side_request.h +++ b/src/client_side_request.h @@ -1,6 +1,6 @@ /* - * $Id: client_side_request.h,v 1.8 2003/02/22 14:59:34 hno Exp $ + * $Id: client_side_request.h,v 1.9 2003/03/15 04:17:39 robertc Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -38,7 +38,7 @@ #include "clientStream.h" /* client_side_request.c - client side request related routines (pure logic) */ -extern int clientBeginRequest(method_t, char const *, CSCB *, CSD *, void *, HttpHeader const *, char *, size_t); +extern int clientBeginRequest(method_t, char const *, CSCB *, CSD *, ClientStreamData, HttpHeader const *, char *, size_t); class MemObject; @@ -66,6 +66,9 @@ public: bool multipartRangeRequest() const; void processRequest(); void httpStart(); + bool onlyIfCached()const; + bool gotEnough() const; + ConnStateData *conn; request_t *request; /* Parsed URL ... */ char *uri; @@ -82,7 +85,6 @@ public: HttpHdrRangeIter range_iter; /* data for iterating thru range specs */ size_t req_sz; /* raw request size on input, not current request size */ StoreEntry *entry; - StoreEntry *old_entry; log_type logType; struct timeval start; @@ -128,7 +130,6 @@ private: /* client http based routines */ SQUIDCEXTERN char *clientConstructTraceEcho(clientHttpRequest *); SQUIDCEXTERN ACLChecklist *clientAclChecklistCreate(const acl_access * acl, const clientHttpRequest * http); -SQUIDCEXTERN void *clientReplyNewContext(clientHttpRequest *); SQUIDCEXTERN int clientHttpRequestStatus(int fd, clientHttpRequest const *http); SQUIDCEXTERN void clientAccessCheck(ClientHttpRequest *); diff --git a/src/protos.h b/src/protos.h index 97d8cf1a3a..643994e453 100644 --- a/src/protos.h +++ b/src/protos.h @@ -1,6 +1,6 @@ /* - * $Id: protos.h,v 1.473 2003/03/10 04:56:38 robertc Exp $ + * $Id: protos.h,v 1.474 2003/03/15 04:17:39 robertc Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -121,10 +121,6 @@ SQUIDCEXTERN void httpRequestFree(void *); extern void clientAccessCheck(void *); -/* client_side_reply.c - client side reply related routines (pure logic, no comms) */ - -SQUIDCEXTERN void clientSetReplyToError(void *, err_type, http_status, method_t, char const *, struct in_addr *, request_t *, char *, auth_user_request_t * auth_user_request); - /* comm.c */ extern void comm_calliocallback(void); diff --git a/src/stat.cc b/src/stat.cc index 7b44b37e7b..f473cbb39f 100644 --- a/src/stat.cc +++ b/src/stat.cc @@ -1,6 +1,6 @@ /* - * $Id: stat.cc,v 1.371 2003/03/04 01:40:29 robertc Exp $ + * $Id: stat.cc,v 1.372 2003/03/15 04:17:41 robertc Exp $ * * DEBUG: section 18 Cache Manager Statistics * AUTHOR: Harvest Derived @@ -1596,8 +1596,12 @@ statClientRequests(StoreEntry * s) storeAppendPrintf(s, "req_sz %ld\n", (long int) http->req_sz); e = http->entry; storeAppendPrintf(s, "entry %p/%s\n", e, e ? e->getMD5Text() : "N/A"); +#if 0 + /* Not a member anymore */ e = http->old_entry; storeAppendPrintf(s, "old_entry %p/%s\n", e, e ? e->getMD5Text() : "N/A"); +#endif + storeAppendPrintf(s, "start %ld.%06d (%f seconds ago)\n", (long int) http->start.tv_sec, (int) http->start.tv_usec, diff --git a/src/store.cc b/src/store.cc index 00d0d97efd..0623f59d8a 100644 --- a/src/store.cc +++ b/src/store.cc @@ -1,6 +1,6 @@ /* - * $Id: store.cc,v 1.564 2003/03/10 04:56:38 robertc Exp $ + * $Id: store.cc,v 1.565 2003/03/15 04:17:41 robertc Exp $ * * DEBUG: section 20 Storage Manager * AUTHOR: Harvest Derived @@ -1857,6 +1857,47 @@ StoreEntry::trimMemory() } } +bool +StoreEntry::modifiedSince(request_t * request) const +{ + int object_length; + time_t mod_time = lastmod; + + if (mod_time < 0) + mod_time = timestamp; + + debug(88, 3) ("modifiedSince: '%s'\n", storeUrl(this)); + + debug(88, 3) ("modifiedSince: mod_time = %ld\n", (long int) mod_time); + + if (mod_time < 0) + return true; + + /* Find size of the object */ + object_length = getReply()->content_length; + + if (object_length < 0) + object_length = contentLen(this); + + if (mod_time > request->ims) { + debug(88, 3) ("--> YES: entry newer than client\n"); + return true; + } else if (mod_time < request->ims) { + debug(88, 3) ("--> NO: entry older than client\n"); + return false; + } else if (request->imslen < 0) { + debug(88, 3) ("--> NO: same LMT, no client length\n"); + return false; + } else if (request->imslen == object_length) { + debug(88, 3) ("--> NO: same LMT, same length\n"); + return false; + } else { + debug(88, 3) ("--> YES: same LMT, different length\n"); + return true; + } +} + + /* NullStoreEntry */ NullStoreEntry NullStoreEntry::_instance; diff --git a/src/structs.h b/src/structs.h index 3f003f73fe..53f05af048 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1,6 +1,6 @@ /* - * $Id: structs.h,v 1.459 2003/03/10 04:56:39 robertc Exp $ + * $Id: structs.h,v 1.460 2003/03/15 04:17:41 robertc Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -947,6 +947,7 @@ class HttpReply public: void *operator new (size_t); void operator delete (void *); + bool isBodyTooLarge(ssize_t clen) const; /* unsupported, writable, may disappear/change in the future */ int hdr_sz; /* sums _stored_ status-line, headers, and */