--------------------- PatchSet 1020 Date: 2004/06/03 22:50:05 Author: ahouhpuc Branch: varyetag Tag: (none) Log: the first prototype Members: doc/debug-sections.txt:1.6->1.6.2.1 src/HttpHeader.cc:1.14->1.14.2.1 src/HttpHeaderTools.cc:1.14->1.14.2.1 src/HttpReply.cc:1.17->1.17.2.1 src/HttpReply.h:1.7->1.7.2.1 src/HttpRequest.cc:1.14->1.14.2.1 src/HttpRequest.h:1.9->1.9.2.1 src/Makefile.am:1.50->1.50.2.1 src/MemObject.h:1.8->1.8.2.1 src/Packer.cc:1.2->1.2.4.1 src/StoreMetaVary.cc:1.4->1.4.2.1 src/StoreMetaVary.h:1.4->1.4.2.1 src/client_side.cc:1.60->1.60.2.1 src/client_side.h:1.7->1.7.4.1 src/client_side_reply.cc:1.48->1.48.2.1 src/client_side_reply.h:1.6->1.6.4.1 src/client_side_request.cc:1.28->1.28.2.1 src/http.cc:1.33->1.33.2.1 src/protos.h:1.41->1.41.2.1 src/store.cc:1.25->1.25.2.1 src/store_swapmeta.cc:1.5->1.5.2.1 src/store_swapout.cc:1.10->1.10.2.1 src/structs.h:1.51->1.51.2.1 Index: squid3/doc/debug-sections.txt =================================================================== RCS file: /cvsroot/squid-sf//squid3/doc/debug-sections.txt,v retrieving revision 1.6 retrieving revision 1.6.2.1 diff -u -r1.6 -r1.6.2.1 --- squid3/doc/debug-sections.txt 23 Jul 2003 02:12:50 -0000 1.6 +++ squid3/doc/debug-sections.txt 3 Jun 2004 22:50:05 -0000 1.6.2.1 @@ -96,3 +96,4 @@ section 90 Store Client section 91 Http Surrogate-Control Header section 92 Store File System +section 93 MMSquid Project Index: squid3/src/HttpHeader.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/HttpHeader.cc,v retrieving revision 1.14 retrieving revision 1.14.2.1 diff -u -r1.14 -r1.14.2.1 --- squid3/src/HttpHeader.cc 30 Sep 2003 02:12:40 -0000 1.14 +++ squid3/src/HttpHeader.cc 3 Jun 2004 22:50:06 -0000 1.14.2.1 @@ -1,6 +1,6 @@ /* - * $Id: HttpHeader.cc,v 1.14 2003/09/30 02:12:40 squidadm Exp $ + * $Id: HttpHeader.cc,v 1.14.2.1 2004/06/03 22:50:06 ahouhpuc Exp $ * * DEBUG: section 55 HTTP Header * AUTHOR: Alex Rousskov @@ -1162,6 +1162,22 @@ return etag; } +/* + * Extracts body of If-None-Match, returns empty String if there is no If-None-Match + */ +String +httpHeaderGetINM(const HttpHeader *hdr) { + assert(hdr); + + String inm; + + inm = httpHeaderGetStrOrList(hdr, HDR_IF_NONE_MATCH); + + debug(93, 5) ("httpHeaderGetINM: INM: %s\n", inm.buf()); + + return inm; +} + TimeOrTag httpHeaderGetTimeOrTag(const HttpHeader * hdr, http_hdr_type id) { Index: squid3/src/HttpHeaderTools.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/HttpHeaderTools.cc,v retrieving revision 1.14 retrieving revision 1.14.2.1 diff -u -r1.14 -r1.14.2.1 --- squid3/src/HttpHeaderTools.cc 21 Sep 2003 02:13:17 -0000 1.14 +++ squid3/src/HttpHeaderTools.cc 3 Jun 2004 22:50:06 -0000 1.14.2.1 @@ -1,6 +1,6 @@ /* - * $Id: HttpHeaderTools.cc,v 1.14 2003/09/21 02:13:17 squidadm Exp $ + * $Id: HttpHeaderTools.cc,v 1.14.2.1 2004/06/03 22:50:06 ahouhpuc Exp $ * * DEBUG: section 66 HTTP Header Tools * AUTHOR: Alex Rousskov @@ -318,6 +318,60 @@ return len > 0; } +/* + * creates array of char* and fills it with elements of str + * elements are separated by ',' + * len becomes number of elements + * XXX len and returned number arent the same? + */ +int +fillArrayWithStr(const String *str, char ***array, int *len) { + + assert(str); + + // for strListGetItem + const char *pos = NULL; + int ilen; + + // separate element + const char *item; + + // iterates the elements + int count = 0; + + // to start with + *len = 0; + + + // element number + while(strListGetItem(str, ',', &item, &ilen, &pos)) + (*len)++; + + //XXX shouldn't we safe_free? + *array = NULL; + + // if there are elements + if (*len) + *array = new (char *)[*len]; + + // for strListGetItem + const char *pos2 = NULL; + + //copy the elements + while(strListGetItem(str, ',', &item, &ilen, &pos2)) { + + debug(93,9) ("fillArrayWithStr: count=%d len=%d\n", count, *len); + assert(count < *len); + + (*array)[count] = (char*)xmalloc(ilen + 1); + xstrncpy((*array)[count++], item, ilen + 1); + + debug(93,3) ("fillArrayWithStr: item found %s\n", item); + } + + return count; +} + /* handy to printf prefixes of potentially very long buffers */ const char * getStringPrefix(const char *str, const char *end) Index: squid3/src/HttpReply.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/HttpReply.cc,v retrieving revision 1.17 retrieving revision 1.17.2.1 diff -u -r1.17 -r1.17.2.1 --- squid3/src/HttpReply.cc 24 Dec 2003 03:12:59 -0000 1.17 +++ squid3/src/HttpReply.cc 3 Jun 2004 22:50:06 -0000 1.17.2.1 @@ -1,6 +1,6 @@ /* - * $Id: HttpReply.cc,v 1.17 2003/12/24 03:12:59 squidadm Exp $ + * $Id: HttpReply.cc,v 1.17.2.1 2004/06/03 22:50:06 ahouhpuc Exp $ * * DEBUG: section 58 HTTP Reply (Response) * AUTHOR: Alex Rousskov @@ -87,7 +87,7 @@ return rep; } -HttpReply::HttpReply() : hdr_sz (0), content_length (0), date (0), last_modified (0), expires (0), cache_control (NULL), surrogate_control (NULL), content_range (NULL), keep_alive (0), pstate(psReadyToParseStartLine), header (hoReply) +HttpReply::HttpReply() : hdr_sz (0), content_length (0), date (0), last_modified (0), expires (0), cache_control (NULL), surrogate_control (NULL), content_range (NULL), keep_alive (0), saved304 (0), pstate(psReadyToParseStartLine), header (hoReply) { assert(this); httpBodyInit(&body); @@ -221,7 +221,7 @@ HttpReply * httpReplyMake304 (const HttpReply * rep) { - static const http_hdr_type ImsEntries[] = {HDR_DATE, HDR_CONTENT_TYPE, HDR_EXPIRES, HDR_LAST_MODIFIED, /* eof */ HDR_OTHER}; + static const http_hdr_type ImsEntries[] = {HDR_DATE, HDR_CONTENT_TYPE, HDR_EXPIRES, HDR_LAST_MODIFIED, HDR_ETAG, /* eof */ HDR_OTHER}; HttpReply *rv; int t; @@ -238,8 +238,11 @@ /* rv->content_range */ /* rv->keep_alive */ HttpVersion ver(1,0); + + // XXX was "" OK? httpStatusLineSet(&rv->sline, ver, - HTTP_NOT_MODIFIED, ""); + // HTTP_NOT_MODIFIED, ""); + HTTP_NOT_MODIFIED, "Not Modified"); for (t = 0; ImsEntries[t] != HDR_OTHER; ++t) if ((e = httpHeaderFindEntry(&rep->header, ImsEntries[t]))) @@ -329,6 +332,7 @@ /* Content-Length */ /* TODO: remove -1 bypass */ + debug(93, 9) ("httpReplyValidatorsMatch: %d %d\n", rep->content_length, otherRep->content_length); if (rep->content_length != otherRep->content_length && rep->content_length > -1 && otherRep->content_length > -1) @@ -339,12 +343,17 @@ two = httpHeaderGetStrOrList(&otherRep->header, HDR_ETAG); + debug(93, 9) ("httpReplyValidatorsMatch: %s %s!\n",one.buf(), two.buf()); + if (one.buf() || two.buf()) { if (!one.buf() || !two.buf() || strcasecmp (one.buf(), two.buf())) { + debug(93, 9) ("httpReplyValidatorsMatch: no etags!\n"); one.clean(); two.clean(); return 0; } + } + debug(93, 9) ("httpReplyValidatorsMatch: %ld %ld\n",rep->last_modified, otherRep->last_modified); if (rep->last_modified != otherRep->last_modified) return 0; @@ -353,11 +362,21 @@ two = httpHeaderGetStrOrList(&otherRep->header, HDR_CONTENT_MD5); + + + debug(93, 9) ("httpReplyValidatorsMatch: md5: %s, %s\n", one.buf(), two.buf()); + + // if any of MD5 is not NULL we are able to compare 'em + if (one.buf() || two.buf()) { + if (!one.buf() || !two.buf() || strcasecmp (one.buf(), two.buf())) { one.clean(); two.clean(); return 0; } + } + + debug(93, 9) ("httpReplyValidatorsMatch: true\n"); return 1; } @@ -366,9 +385,11 @@ void httpReplyUpdateOnNotModified(HttpReply * rep, HttpReply const * freshRep) { + debug(93, 9) ("httpReplyUpdateOnNotModified: start\n"); assert(rep && freshRep); /* Can not update modified headers that don't match! */ assert (httpReplyValidatorsMatch(rep, freshRep)); + debug(93, 9) ("httpReplyUpdateOnNotModified: after assert(httpReplyValidatorsMatch)\n"); /* clean cache */ httpReplyHdrCacheClean(rep); /* update raw headers */ @@ -376,6 +397,7 @@ (const HttpHeaderMask *) &Denied304HeadersMask); /* init cache */ httpReplyHdrCacheInit(rep); + debug(93, 9) ("httpReplyUpdateOnNotModified: end\n"); } Index: squid3/src/HttpReply.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/HttpReply.h,v retrieving revision 1.7 retrieving revision 1.7.2.1 diff -u -r1.7 -r1.7.2.1 --- squid3/src/HttpReply.h 2 Sep 2003 02:12:39 -0000 1.7 +++ squid3/src/HttpReply.h 3 Jun 2004 22:50:06 -0000 1.7.2.1 @@ -1,6 +1,6 @@ /* - * $Id: HttpReply.h,v 1.7 2003/09/02 02:12:39 squidadm Exp $ + * $Id: HttpReply.h,v 1.7.2.1 2004/06/03 22:50:06 ahouhpuc Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -102,6 +102,9 @@ HttpHdrContRange *content_range; short int keep_alive; + /* for handleConditionalMiss */ + int saved304; + /* public, readable */ HttpMsgParseState pstate; /* the current parsing state */ Index: squid3/src/HttpRequest.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/HttpRequest.cc,v retrieving revision 1.14 retrieving revision 1.14.2.1 diff -u -r1.14 -r1.14.2.1 --- squid3/src/HttpRequest.cc 2 Sep 2003 02:12:39 -0000 1.14 +++ squid3/src/HttpRequest.cc 3 Jun 2004 22:50:06 -0000 1.14.2.1 @@ -1,6 +1,6 @@ /* - * $Id: HttpRequest.cc,v 1.14 2003/09/02 02:12:39 squidadm Exp $ + * $Id: HttpRequest.cc,v 1.14.2.1 2004/06/03 22:50:06 ahouhpuc Exp $ * * DEBUG: section 73 HTTP Request * AUTHOR: Duane Wessels @@ -137,6 +137,8 @@ safe_free(req->vary_headers); + safe_free(req->real_vary_headers); + req->urlpath.clean(); httpHeaderClean(&req->header); @@ -155,6 +157,26 @@ req->extacl_log.clean(); + // clear inm information + if (req->inmlen) { + + assert(req->inm); + + for(int i=0; i < req->inmlen; i++) { + + assert(req->inm[i]); + safe_free(req->inm[i]); + + } + + delete req->inm; + } + + //clear etag information + if (req->etag) { + delete req->etag; + } + delete req; } Index: squid3/src/HttpRequest.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/HttpRequest.h,v retrieving revision 1.9 retrieving revision 1.9.2.1 diff -u -r1.9 -r1.9.2.1 --- squid3/src/HttpRequest.h 17 Oct 2003 02:12:32 -0000 1.9 +++ squid3/src/HttpRequest.h 3 Jun 2004 22:50:06 -0000 1.9.2.1 @@ -1,6 +1,6 @@ /* - * $Id: HttpRequest.h,v 1.9 2003/10/17 02:12:32 squidadm Exp $ + * $Id: HttpRequest.h,v 1.9.2.1 2004/06/03 22:50:06 ahouhpuc Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -80,6 +80,16 @@ HttpVersion http_ver; time_t ims; int imslen; + + // etags from client INM + char **inm; + + // number of etags in client INM + int inmlen; + + // whole INM string + String *etag; + int max_forwards; /* these in_addr's could probably be sockaddr_in's */ @@ -96,6 +106,7 @@ char *peer_login; /* Configured peer login:password */ time_t lastmod; /* Used on refreshes */ const char *vary_headers; /* Used when varying entities are detected. Changes how the store key is calculated */ + const char *real_vary_headers; /* original vary_headers (before vary mappings) */ char *peer_domain; /* Configured peer forceddomain */ String tag; /* Internal tag for this request */ String extacl_user; /* User name returned by extacl lookup */ Index: squid3/src/Makefile.am =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/Makefile.am,v retrieving revision 1.50 retrieving revision 1.50.2.1 diff -u -r1.50 -r1.50.2.1 --- squid3/src/Makefile.am 21 Oct 2003 02:12:44 -0000 1.50 +++ squid3/src/Makefile.am 3 Jun 2004 22:50:06 -0000 1.50.2.1 @@ -1,7 +1,7 @@ # # Makefile for the Squid Object Cache server # -# $Id: Makefile.am,v 1.50 2003/10/21 02:12:44 squidadm Exp $ +# $Id: Makefile.am,v 1.50.2.1 2004/06/03 22:50:06 ahouhpuc Exp $ # # Uncomment and customize the following to suit your needs: # @@ -316,6 +316,8 @@ client_side_request.h \ clientStream.cc \ clientStream.h \ + CharHashTable.cc \ + CharHashTable.h \ comm.cc \ comm.h \ comm_select.cc \ @@ -552,6 +554,8 @@ client_side_request.h \ clientStream.cc \ clientStream.h \ + CharHashTable.cc \ + CharHashTable.h \ comm.cc \ comm.h \ comm_select.cc \ Index: squid3/src/MemObject.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/MemObject.h,v retrieving revision 1.8 retrieving revision 1.8.2.1 diff -u -r1.8 -r1.8.2.1 --- squid3/src/MemObject.h 11 Aug 2003 02:13:02 -0000 1.8 +++ squid3/src/MemObject.h 3 Jun 2004 22:50:06 -0000 1.8.2.1 @@ -1,6 +1,6 @@ /* - * $Id: MemObject.h,v 1.8 2003/08/11 02:13:02 squidadm Exp $ + * $Id: MemObject.h,v 1.8.2.1 2004/06/03 22:50:06 ahouhpuc Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -38,6 +38,8 @@ #include "stmem.h" #include "CommRead.h" +#include "CharHashTable.h" + typedef void STMCB (void *data, StoreIOBuffer wroteBuffer); class store_client; @@ -135,8 +137,13 @@ unsigned int chksum; #endif + // the vary key for variant const char *vary_headers; + // information of variants for base vary entry + CharHashTable *etag_mapping; + CharHashTable *vary_headers_mapping; + void delayRead(DeferredRead const &); void kickReads(); Index: squid3/src/Packer.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/Packer.cc,v retrieving revision 1.2 retrieving revision 1.2.4.1 diff -u -r1.2 -r1.2.4.1 --- squid3/src/Packer.cc 22 Feb 2003 03:14:30 -0000 1.2 +++ squid3/src/Packer.cc 3 Jun 2004 22:50:06 -0000 1.2.4.1 @@ -1,6 +1,6 @@ /* - * $Id: Packer.cc,v 1.2 2003/02/22 03:14:30 squidadm Exp $ + * $Id: Packer.cc,v 1.2.4.1 2004/06/03 22:50:06 ahouhpuc Exp $ * * DEBUG: section 60 Packer: A uniform interface to store-like modules * AUTHOR: Alex Rousskov @@ -92,13 +92,49 @@ * warning (e.g., "warning: assignment from incompatible pointer type"). */ +/* + * Appends buf directly to result, increases result->length + */ +static void +storeIOBufferAppend(StoreIOBuffer *result, const char *buf, int sz) { + debug(93, 9) ("storeIOBufferAppend: buf: %s\n", buf); + + assert(result && buf && sz >= 0 && result->data); + + if (sz == 0) + return; + + xmemcpy(result->data + result->length, buf, sz); + result->length += sz; + result->data[result->length] = '\0'; + +} + +/* + * to be used with short 304 replies only (short replies) + * XXX deal with replies larger than 4096B + */ +static void +storeIOBufferAppendVPrintf(StoreIOBuffer *result, const char *fmt, va_list vargs) { + debug(93, 9) ("storeIOBufferAppend: fmt: %s\n", fmt); + + assert(result && fmt && result->data); + LOCAL_ARRAY(char, buf, 4096); + buf[0] = '\0'; + vsnprintf(buf, 4096, fmt, vargs); + storeIOBufferAppend(result, buf, strlen(buf)); + +} + /* append()'s */ static void (*const store_append) (StoreEntry *, const char *, int) = &storeAppend; static void (*const memBuf_append) (MemBuf *, const char *, mb_size_t) = &memBufAppend; +static void (*const sIOBuf_append) (StoreIOBuffer *, const char *, int) = &storeIOBufferAppend; /* vprintf()'s */ static void (*const store_vprintf) (StoreEntry *, const char *, va_list ap) = &storeAppendVPrintf; static void (*const memBuf_vprintf) (MemBuf *, const char *, va_list ap) = &memBufVPrintf; +static void (*const sIOBuf_vprintf) (StoreIOBuffer *, const char *, va_list ap) = &storeIOBufferAppendVPrintf; /* init/clean */ @@ -123,6 +159,23 @@ p->real_handler = mb; } +/* init with this to accumulate data in StoreIOBuffer */ +void +packerToStoreIOBufferInit(Packer *p, StoreIOBuffer *result) { + + debug(93, 9) ("packerToStoreIOBufferInit: p: %p, result: %p\n", p, result); + + assert(p && result); + assert(result->data); + + p->append = (append_f) sIOBuf_append; + p->vprintf = (vprintf_f) sIOBuf_vprintf; + p->real_handler = result; + + result->length = 0; + result->offset = 0; +} + /* call this when you are done */ void packerClean(Packer * p) Index: squid3/src/StoreMetaVary.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/StoreMetaVary.cc,v retrieving revision 1.4 retrieving revision 1.4.2.1 diff -u -r1.4 -r1.4.2.1 --- squid3/src/StoreMetaVary.cc 5 Aug 2003 02:12:48 -0000 1.4 +++ squid3/src/StoreMetaVary.cc 3 Jun 2004 22:50:06 -0000 1.4.2.1 @@ -1,6 +1,6 @@ /* - * $Id: StoreMetaVary.cc,v 1.4 2003/08/05 02:12:48 squidadm Exp $ + * $Id: StoreMetaVary.cc,v 1.4.2.1 2004/06/03 22:50:06 ahouhpuc Exp $ * * DEBUG: section 20 Storage Manager Swapfile Metadata * AUTHOR: Kostas Anagnostakis @@ -37,6 +37,7 @@ #include "StoreMetaVary.h" #include "Store.h" #include "MemObject.h" +#include "CharHashTable.h" MemPool *StoreMetaVary::pool = NULL; @@ -63,15 +64,204 @@ { assert (getType() == STORE_META_VARY_HEADERS); - if (!e->mem_obj->vary_headers) { - /* XXX separate this mutator from the query */ - /* Assume the object is OK.. remember the vary request headers */ - e->mem_obj->vary_headers = xstrdup((char *)value); - return true; + //unpacking + return storeMetaVaryUnpack(e->mem_obj, (char*)value); + +} + +bool +storeMetaVaryUnpack(MemObject *mem_obj, char* value) { + + debug(93, 9) ("\t*** storeMetaVaryUnpack: value: %p mem_obj: %p\n", value, mem_obj); + assert(value && mem_obj); + + // vary_headers length + int vary_headers_len; + + xmemcpy(&vary_headers_len, value, sizeof(int)); + + debug(93, 9) ("\t** storeMetaVaryUnpack: vary_headers_len: %d\n", vary_headers_len); + + char *vary_headers = NULL; + + if (vary_headers_len) { + // unpack vary_headers + vary_headers = (char*)xmalloc(vary_headers_len); + + xmemcpy(vary_headers, &value[sizeof(int)], vary_headers_len); + } + + + // packed etag_mapping length + int etag_mapping_packed_len; + + xmemcpy(&etag_mapping_packed_len, &value[sizeof(int) + vary_headers_len], sizeof(int)); + + debug(93, 9) ("\t** storeMetaVaryUnpack: etag_mapping_packed_len: %d\n", etag_mapping_packed_len); + + char *etag_mapping_packed = NULL; + + if (etag_mapping_packed_len) { + + // get packed etag_mapping + etag_mapping_packed = (char*)xmalloc(etag_mapping_packed_len + sizeof(int)); + + xmemcpy(etag_mapping_packed, + &value[sizeof(int) + vary_headers_len], + etag_mapping_packed_len + sizeof(int)); + } + + // packed vary_headers_mapping length + int vary_headers_mapping_packed_len; + + xmemcpy(&vary_headers_mapping_packed_len, + &value[sizeof(int) + vary_headers_len + sizeof(int) + etag_mapping_packed_len], + sizeof(int)); + + debug(93, 9) ("\t** storeMetaVaryUnpack: vary_headers_mapping_packed_len: %d\n", vary_headers_mapping_packed_len); + + char *vary_headers_mapping_packed = NULL; + + if (vary_headers_mapping_packed_len) { + + // get packed vary_headers_mapping + vary_headers_mapping_packed = (char*)xmalloc(vary_headers_mapping_packed_len + sizeof(int)); + + xmemcpy(vary_headers_mapping_packed, + &value[sizeof(int) + vary_headers_len + sizeof(int) + etag_mapping_packed_len], + vary_headers_mapping_packed_len + sizeof(int)); + + } + + debug(93, 9) ("\t*** storeMetaVaryUnpack: %d %d %d\n", vary_headers_mapping_packed_len, etag_mapping_packed_len, vary_headers_len); + + + // save data in mem_obj + + if (!mem_obj->vary_headers && vary_headers) { + mem_obj->vary_headers = xstrdup(vary_headers); + } + + // vary_headers means this is a variant, not a base object + if (!vary_headers) { + + // unpack mappings + mem_obj->etag_mapping = new CharHashTable(etag_mapping_packed); + mem_obj->vary_headers_mapping = new CharHashTable(vary_headers_mapping_packed); + } - if (strcmp(e->mem_obj->vary_headers, (char *)value) != 0) + + safe_free(etag_mapping_packed); + safe_free(vary_headers_mapping_packed); + + // decide if stuff unpacked correctly + // XXX check also mappings + if (mem_obj->vary_headers) { + + if (vary_headers) { + + if (strcmp(mem_obj->vary_headers, vary_headers) != 0) { + safe_free(vary_headers); + debug(93, 9) ("storeMetaVaryUnpack: end - false\n"); return false; + } + } else { + safe_free(vary_headers); + debug(93, 9) ("storeMetaVaryUnpack: end - false\n"); + return false; + } + } + + safe_free(vary_headers); + + debug(93, 9) ("storeMetaVaryUnpack: end - true\n"); return true; } + +/* + * Packs vary_headers or mappings + * rlen becomes length of the whole packed string (returned) + * + * LVH VH LEM VEM LVHM VVHM + */ +char * +storeMetaVaryPack(MemObject *mem_obj, int *rlen) { + + assert(mem_obj && rlen); + + debug(93, 9) ("storeMetaVaryPack: start\n"); + + // packed string to be returned + char *packed = NULL; + + // never all three + assert(!(mem_obj->vary_headers && mem_obj->etag_mapping && mem_obj->vary_headers_mapping)); + + debug(93, 9) ("storeMetaVaryPack: %p %p %p\n", mem_obj->vary_headers, mem_obj->etag_mapping, mem_obj->vary_headers_mapping); + + // which do we have? + int hasMappings = mem_obj->vary_headers_mapping && mem_obj->etag_mapping; + int hasVaryHeaders = (int)mem_obj->vary_headers; + + if (hasMappings || hasVaryHeaders) { + + // mappings lengths + int etag_mapping_len = sizeof(int); + int vary_headers_mapping_len = sizeof(int); + + // strings for packed mappings + char *etag_mapping_packed = NULL; + char *vary_headers_mapping_packed = NULL; + + // pack if we are to + if (hasMappings) { + etag_mapping_packed = mem_obj->etag_mapping->pack(&etag_mapping_len); + vary_headers_mapping_packed = mem_obj->vary_headers_mapping->pack(&vary_headers_mapping_len); + } + + debug(93, 9) ("storeMetaVaryPack: %d %d\n", etag_mapping_len, vary_headers_mapping_len); + + // vary_headers length + int vary_headers_len = 0; + + // pack if we are to + if (hasVaryHeaders) + vary_headers_len = strlen(mem_obj->vary_headers) + 1; + + // total length + int len = sizeof(int) + vary_headers_len + etag_mapping_len + vary_headers_mapping_len; + + // final allocation + packed = (char*)xmalloc(len); + + // LVH + xmemcpy(packed, &vary_headers_len, sizeof(int)); + + //VH + if (hasVaryHeaders) + xmemcpy(&packed[sizeof(int)], mem_obj->vary_headers, vary_headers_len); + + + if (hasMappings) { + debug(93, 9) ("storeMetaVaryPack: has mappings\n"); + // LEM VEM + xmemcpy(&packed[sizeof(int)+vary_headers_len], etag_mapping_packed, etag_mapping_len); + //LVH VVHM + xmemcpy(&packed[sizeof(int)+vary_headers_len + etag_mapping_len], + vary_headers_mapping_packed, vary_headers_mapping_len); + } else { + debug(93, 9) ("storeMetaVaryPack: has no mappings\n"); + int zero = 0; + xmemcpy(&packed[sizeof(int) + vary_headers_len], &zero, sizeof(int)); + xmemcpy(&packed[sizeof(int) + vary_headers_len + sizeof(int)], &zero, sizeof(int)); + } + + + *rlen = len; + } + + debug(93, 9) ("storeMetaVaryPack: end\n"); + return packed; +} Index: squid3/src/StoreMetaVary.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/StoreMetaVary.h,v retrieving revision 1.4 retrieving revision 1.4.2.1 diff -u -r1.4 -r1.4.2.1 --- squid3/src/StoreMetaVary.h 5 Aug 2003 02:12:48 -0000 1.4 +++ squid3/src/StoreMetaVary.h 3 Jun 2004 22:50:06 -0000 1.4.2.1 @@ -1,6 +1,6 @@ /* - * $Id: StoreMetaVary.h,v 1.4 2003/08/05 02:12:48 squidadm Exp $ + * $Id: StoreMetaVary.h,v 1.4.2.1 2004/06/03 22:50:06 ahouhpuc Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -35,6 +35,7 @@ #define SQUID_STOREMETAVARY_H #include "StoreMeta.h" +#include "MemObject.h" class StoreMetaVary : public StoreMeta { @@ -51,4 +52,7 @@ static MemPool *pool; }; +bool storeMetaVaryUnpack(MemObject *, char*); +char *storeMetaVaryPack(MemObject *, int *); + #endif /* SQUID_STOREMETAVARY_H */ Index: squid3/src/client_side.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/client_side.cc,v retrieving revision 1.60 retrieving revision 1.60.2.1 diff -u -r1.60 -r1.60.2.1 --- squid3/src/client_side.cc 5 Apr 2004 02:00:27 -0000 1.60 +++ squid3/src/client_side.cc 3 Jun 2004 22:50:06 -0000 1.60.2.1 @@ -1,6 +1,6 @@ /* - * $Id: client_side.cc,v 1.60 2004/04/05 02:00:27 squidadm Exp $ + * $Id: client_side.cc,v 1.60.2.1 2004/06/03 22:50:06 ahouhpuc Exp $ * * DEBUG: section 33 Client-side Routines * AUTHOR: Duane Wessels @@ -801,6 +801,8 @@ if (!multipartRangeRequest()) { size_t length = lengthToSend(bodyData.range()); noteSentBodyBytes (length); + if (flags.saved304) + length = 0; comm_write(fd(), bodyData.data, length, clientWriteBodyComplete, this); return; @@ -1165,10 +1167,16 @@ void ClientSocketContext::sendStartOfMessage(HttpReply * rep, StoreIOBuffer bodyData) { + debug(93, 9) ("sendStartOfMessage: length: %d, offset: %ld, data:\n%s\n-\n", + bodyData.length, bodyData.offset, bodyData.data); + // ranges prepareReply(rep); + /* init mb; put status line and headers if any */ assert (rep); + MemBuf mb = httpReplyPack(rep); + /* Save length of headers for persistent conn checks */ http->out.headers_sz = mb.size; #if HEADERS_LOG @@ -1176,17 +1184,23 @@ headersLog(0, 0, http->request->method, rep); #endif + debug(93, 9) ("sendStartOfMessage: mb.buf:\n%s\n", mb.buf); + if (bodyData.data && bodyData.length) { if (!multipartRangeRequest()) { size_t length = lengthToSend(bodyData.range()); noteSentBodyBytes (length); + if (! flags.saved304) memBufAppend(&mb, bodyData.data, length); + debug(93, 9) ("sendStartOfMessage: saved304: %d, mb.buf:\n%s\n", + flags.saved304, mb.buf); } else { packRange(bodyData, &mb); } } + debug(93, 9) ("sendStartOfMessage: comm_old_write_mbuf\n"); /* write */ comm_old_write_mbuf(fd(), mb, clientWriteComplete, this); @@ -1194,7 +1208,8 @@ } /* - * Write a chunk of data to a client socket. If the reply is present, send the reply headers down the wire too, + * Write a chunk of data to a client socket. If the reply is present, send + * the reply headers down the wire too, * and clean them up when finished. * Pre-condition: * The request is one backed by a connection, not an internal request. @@ -1205,6 +1220,8 @@ clientSocketRecipient(clientStreamNode * node, clientHttpRequest * http, HttpReply * rep, StoreIOBuffer recievedData) { + debug(93, 9) ("clientSocketRecipient: length: %d, offset: %ld, data:\n%s\n-\n", + recievedData.length, recievedData.offset, recievedData.data); int fd; /* Test preconditions */ assert(node != NULL); @@ -1226,11 +1243,23 @@ return; } + debug(93, 9) ("clientSocketRecipient: fd %d, rep: %p\n", + fd, rep); + if (responseFinishedOrFailed(rep, recievedData)) { + debug(93, 9) ("clientSocketRecipient: responseFinishedOrFailed()\n"); context->writeComplete(fd, NULL, 0, COMM_OK); return; } + debug(93, 9) ("clientSocketRecipient: context->startOfOutput(): %d, " + "rep->saved304: %d\n", + context->startOfOutput(), rep ? rep->saved304 : 0); + + int saved304 = rep ? rep->saved304 : 0; + if (saved304) + context->flags.saved304 = 1; + if (!context->startOfOutput()) context->sendBody(rep, recievedData); else { @@ -1522,6 +1551,8 @@ void ClientSocketContext::writeComplete(int fd, char *bufnotused, size_t size, comm_err_t errflag) { + + debug(93, 9) ("\t !!! writeComplete: bufnotused: \n%s\n-\n", bufnotused); StoreEntry *entry = http->storeEntry(); http->out.size += size; assert(fd > -1); @@ -2292,6 +2323,7 @@ context->mayUseConnection(true); clientAccessCheck(http); + } static void @@ -2836,6 +2868,7 @@ clientdbEstablished(details->peer.sin_addr, 1); incoming_sockets_accepted++; + } #if USE_SSL @@ -3078,7 +3111,12 @@ int varyEvaluateMatch(StoreEntry * entry, HttpRequest * request) { + + // vary_headers from Vary of base entry and request headers + // set after finding of Vary base entry const char *vary = request->vary_headers; + + // reply has Vary header int has_vary = httpHeaderHas(&entry->getReply()->header, HDR_VARY); #if X_ACCELERATOR_VARY @@ -3086,17 +3124,21 @@ httpHeaderHas(&entry->getReply()->header, HDR_X_ACCELERATOR_VARY); #endif + // mem_obj has vary_headers if reply is a variant if (!has_vary || !entry->mem_obj->vary_headers) { + + // we were looking for a variant and we haven't found one if (vary) { /* Oops... something odd is going on here.. */ - debug(33, - 1) + debug(33, 1) ("varyEvaluateMatch: Oops. Not a Vary object on second attempt, '%s' '%s'\n", entry->mem_obj->url, vary); safe_free(request->vary_headers); + safe_free(request->real_vary_headers); return VARY_CANCEL; } + // there never was any Vary/variants if (!has_vary) { /* This is not a varying object */ return VARY_NONE; @@ -3107,28 +3149,60 @@ */ vary = httpMakeVaryMark(request, entry->getReply()); + assert(entry->mem_obj->vary_headers_mapping); + assert(entry->mem_obj->etag_mapping); + + // always should be vary if (vary) { - request->vary_headers = xstrdup(vary); + + // saving vary_headers + request->real_vary_headers = xstrdup(vary); + request->vary_headers = entry->mem_obj->vary_headers_mapping->get((char *)request->real_vary_headers); + + // if there is no mapping + if (!request->vary_headers) + request->vary_headers = xstrdup(request->real_vary_headers); + else + request->vary_headers = xstrdup(request->vary_headers); + + return VARY_OTHER; } else { /* Ouch.. we cannot handle this kind of variance */ /* XXX This cannot really happen, but just to be complete */ return VARY_CANCEL; } + } else { + // reply has Vary header and reply is a variant + // XXX we're not sure if each variant has to have Vary header + + // first time we know the reply is a variant if (!vary) { + + // get variants key vary = httpMakeVaryMark(request, entry->getReply()); - if (vary) + // should always be vary + if (vary) { + request->vary_headers = xstrdup(vary); - } + request->real_vary_headers = xstrdup(vary); + + } else { - if (!vary) { /* Ouch.. we cannot handle this kind of variance */ /* XXX This cannot really happen, but just to be complete */ return VARY_CANCEL; - } else if (strcmp(vary, entry->mem_obj->vary_headers) == 0) { + } + + } + + + // check if this is the correct variant + if (strcmp(vary, entry->mem_obj->vary_headers) == 0) { return VARY_MATCH; + } else { /* Oops.. we have already been here and still haven't * found the requested variant. Bail out Index: squid3/src/client_side.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/client_side.h,v retrieving revision 1.7 retrieving revision 1.7.4.1 diff -u -r1.7 -r1.7.4.1 --- squid3/src/client_side.h 15 Aug 2003 02:12:38 -0000 1.7 +++ squid3/src/client_side.h 3 Jun 2004 22:50:06 -0000 1.7.4.1 @@ -1,6 +1,6 @@ /* - * $Id: client_side.h,v 1.7 2003/08/15 02:12:38 squidadm Exp $ + * $Id: client_side.h,v 1.7.4.1 2004/06/03 22:50:06 ahouhpuc Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -71,6 +71,10 @@ int parsed_ok: 1; /* Was this parsed correctly? */ + +int saved304: + 1; /* handleConditionalMiss path? */ + } flags; Index: squid3/src/client_side_reply.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/client_side_reply.cc,v retrieving revision 1.48 retrieving revision 1.48.2.1 diff -u -r1.48 -r1.48.2.1 --- squid3/src/client_side_reply.cc 5 Apr 2004 02:00:27 -0000 1.48 +++ squid3/src/client_side_reply.cc 3 Jun 2004 22:50:06 -0000 1.48.2.1 @@ -1,6 +1,6 @@ /* - * $Id: client_side_reply.cc,v 1.48 2004/04/05 02:00:27 squidadm Exp $ + * $Id: client_side_reply.cc,v 1.48.2.1 2004/06/03 22:50:06 ahouhpuc Exp $ * * DEBUG: section 88 Client-side Reply Routines * AUTHOR: Robert Collins (Originally Duane Wessels in client_side.c) @@ -77,7 +77,7 @@ cbdataReferenceDone(http); } -clientReplyContext::clientReplyContext(clientHttpRequest *clientContext) : http (cbdataReference(clientContext)), old_entry (NULL), old_sc(NULL), deleting(false) +clientReplyContext::clientReplyContext(clientHttpRequest *clientContext) : http (cbdataReference(clientContext)), old_entry (NULL), old_sc(NULL), vary_entry(NULL), vary_sc(NULL), deleting(false) {} /* create an error in the store awaiting the client side to read it. */ @@ -219,6 +219,24 @@ storeClientCopy(sc, http->storeEntry(), tempBuffer, SendMoreData, this); } +/* + * copy of triggerInitialStoreRead but takes also a callback to call back at the end + */ +void +clientReplyContext::triggerInitialStoreReadClone(STCB * callback) { + + StoreIOBuffer otherTempBuffer; + /* when confident, 0 becomes reqofs, and then this factors into + * startSendProcess + */ + assert(reqofs == 0); + otherTempBuffer.offset = 0; + otherTempBuffer.length = next()->readBuffer.length; + otherTempBuffer.data = next()->readBuffer.data; + debug(93, 9) ("triggerInitialStoreReadClone: sc = %p, callback: %p\n", sc, callback); + storeClientCopy(sc, http->storeEntry(), otherTempBuffer, callback, this); +} + /* there is an expired entry in the store. * setup a temporary buffer area and perform an IMS to the origin */ @@ -228,7 +246,13 @@ char *url = http->uri; StoreEntry *entry = NULL; debug(88, 3)("clientReplyContext::processExpired: '%s'", http->uri); - assert(http->storeEntry()->lastmod >= 0); + + // get ETag from reply + const HttpHeader *rep_hdr = &http->storeEntry()->getReply()->header; + ETag etag = httpHeaderGetETag(rep_hdr, HDR_ETAG); + + // Last-Modified or ETag + assert(http->storeEntry()->lastmod >= 0 || etag.str); /* * check if we are allowed to contact other servers * @?@: Instead of a 504 (Gateway Timeout) reply, we may want to return @@ -257,8 +281,60 @@ sc->setDelayId(DelayId::DelayClient(http)); #endif + // old_entry may be a variant + const char *vary_headers = old_entry->mem_obj->vary_headers; + + // vary_entry is base vary object + vary_entry = NULL; + + if (vary_headers) { + + vary_entry = storeGetPublic(old_entry->mem_obj->url, old_entry->mem_obj->method); + + } + + debug(93, 9) ("processExpired: vary_entry = %p\n", vary_entry); + + // if Vary + if (vary_entry) { + + // collect etags of all the variants to send to server + + // we should have mem_obj because base object was swapped in in cacheHit + assert(vary_entry->mem_obj); + + // get all the etags + char * etag_keys = vary_entry->mem_obj->etag_mapping->keys(); + debug (93, 9) ("processExpired: inm=[%s]\n", etag_keys); + + // save them + if (etag_keys) { + + http->request->lastmod = -1; + http->request->etag = new String(etag_keys); + + } else { + + // the variants has no etags -> try to validate with IMS + http->request->etag = NULL; http->request->lastmod = old_entry->lastmod; - debug(88, 5)("clientReplyContext::processExpired : lastmod %ld", + + } + + } else { + + // no vary, just casual single etag + + if (etag.str) + http->request->etag = new String(etag.str); + else + http->request->etag = NULL; + + http->request->lastmod = old_entry->lastmod; + + } + + debug(88, 5)("clientReplyContext::processExpired : lastmod %ld\n", (long int) entry->lastmod); http->storeEntry(entry); assert(http->out.offset == 0); @@ -299,24 +375,21 @@ return false; } - /* If the client did not send IMS in the request, then it + /* if client did not send INM in the request, then it * must get the old object, not this "Not Modified" reply * REGARDLESS of validation */ - if (!http->request->flags.ims) { - debug(88, 5) ("clientGetsOldEntry: YES, no client IMS\n"); + if (!http->request->flags.inm && !http->request->flags.ims) { + + debug(93, 5) ("clientGetsOldEntry: YES, no client INM, nor IMS\n"); return true; + } - /* If key metadata in the reply are not consistent with the - * old entry, we must use the new reply. - * Note: this means that the server is sending garbage replies - * in that it has sent an IMS that is incompatible with our request!? - */ - /* This is a duplicate call through the HandleIMS code path. - * Can we guarantee we don't need it elsewhere? - */ + + // to sum up: 304 and client's request was conditional if (!httpReplyValidatorsMatch(http->storeEntry()->getReply(), old_entry->getReply())) { + debug(88, 5) ("clientGetsOldEntry: NO, Old object has been invalidated" "by the new one\n"); return false; @@ -324,11 +397,42 @@ /* If the client IMS time is prior to the entry LASTMOD time we * need to send the old object */ + + if (http->request->flags.ims) { if (old_entry->modifiedSince(http->request)) { debug(88, 5) ("clientGetsOldEntry: YES, modified since %ld\n", (long int) http->request->ims); return true; } + } + + + // IMS(passed)+INM + if (http->request->flags.inm) { + + // check if one of the etags from reply matches client's one + + const HttpHeader *hdr = &http->storeEntry()->getReply()->header; + ETag etag = httpHeaderGetETag(hdr, HDR_ETAG); + const char *etag_str = etag.str; + int llen = 0; + char *etag_inm; + + debug(93,5) ("clientGetsOldEntry: etag from reply %s\n",etag_str); + + while(etag_str && llen < http->request->inmlen) { + etag_inm = http->request->inm[llen++]; + + debug(93,5) ("clientGetsOldEntry: parsing client INM: %s\n",etag_inm); + + if (strcmp(etag_str,etag_inm)) + continue; + + return false; + } + + return true; + } debug(88, 5) ("clientGetsOldEntry: NO, new one is fine\n"); return false; @@ -414,6 +518,10 @@ * headers have been loaded from disk. */ http->logType = LOG_TCP_REFRESH_HIT; + http_status status = http->storeEntry()->getReply()->sline.status; + + debug(93, 3) ("handleIMSGiveClientUpdatedOldEntry: reply=%d\n", status); + if (httpReplyValidatorsMatch(http->storeEntry()->getReply(), old_entry->getReply())) { int unlink_request = 0; @@ -505,6 +613,97 @@ } } +/* + * see variantUpdateSend + */ +void +clientReplyContext::VariantUpdateSend(void *data, StoreIOBuffer result) +{ + clientReplyContext *context = (clientReplyContext *)data; + context->variantUpdateSend(result); +} + +/* + * for now does nothing :( + * should update variant headers after revalidation + */ +void +clientReplyContext::variantUpdateSend(StoreIOBuffer result) +{ + sendMoreData(result); +} + +/* + * see fakeEntryToVariant + */ +void +clientReplyContext::FakeEntryToVariant(void *data, StoreIOBuffer result) +{ + clientReplyContext *context = (clientReplyContext *)data; + context->fakeEntryToVariant(result); +} + +/* + * Decide which variant to send to client upon receiving Not Modified after Vary INM + * etag based + */ +void +clientReplyContext::fakeEntryToVariant(StoreIOBuffer result) +{ + // assumptions: + // - tempBufferVary - result saved in handleIMSReply + // - vary_entry - base vary object + // - vary_sc + // - after saveState() + // - old_entry - new 304 response from server (saved) + + // 304's headers + const HttpHeader *hdr = &old_entry->getReply()->header; + ETag etag = httpHeaderGetETag(hdr, HDR_ETAG); + const char *etag_str = etag.str; + + assert(vary_entry->mem_obj); + + // vary_headers of the variant pointed to by etag_str + const char *vary_headers = vary_entry->mem_obj->etag_mapping->get((char*)etag_str); + + if (vary_headers) { + // we have such a variant + + // update for storeGetPublicByRequest + http->request->vary_headers = xstrdup(vary_headers); + StoreEntry *e = storeGetPublicByRequest(http->request); + + + if (e) { + sc = storeClientListAdd(e, this); + reqofs = 0; + reqsize = 0; + http->storeEntry(e); + + StoreIOBuffer tempBuffer; + tempBuffer.offset = reqofs; + tempBuffer.length = next()->readBuffer.length; + tempBuffer.data = next()->readBuffer.data; + storeClientCopy(sc, http->storeEntry(), tempBuffer, SendMoreData, this); + + } else { + + debug(93, 9) ("fakeEntryToVariant: sending supposed garbage - no variant found\n"); + restoreState(); + sendMoreData(tempBufferVary); + + } + + } else { + //we haven't found correct etag->vary_headers mapping, so we must send client + //server response (probably garbage) + debug(93, 9) ("fakeEntryToVariant: sending supposed garbage - no mapping\n"); + restoreState(); + sendMoreData(tempBufferVary); + } +} + void clientReplyContext::handleIMSReply(StoreIOBuffer result) { @@ -525,7 +724,65 @@ reqsize = result.length + reqofs; http_status status = http->storeEntry()->getReply()->sline.status; + debug(93, 3) ("handleIMSReply: reply=%d\n", status); + + // old_entry is not set in processMiss + // and is set in processExpired + if (!old_entry) { + + debug(93, 9) ("handleIMSReply: variant handling\n"); + + StoreEntry *entry = http->storeEntry(); + + // if other than HTTP_NOT_MODIFIED send response to client + if (status != HTTP_NOT_MODIFIED) { + debug(93, 9) ("handleIMSReply: new variant, proceed to sendMoreData()\n"); + sendMoreData(result); + return; + } + + // if HTTP_NOT_MODIFIED then go on with vary stuff + + // base vary object + vary_entry = storeGetPublic(entry->mem_obj->url, entry->mem_obj->method); + + if (vary_entry) { + + // save for fakeEntryToVariant + saveState(); + tempBufferVary = result; + + vary_sc = NULL; + + if (!vary_entry->mem_obj) { + + // "fake" (base) has no memobj -> swap it in + debug(93, 9) ("handleIMSReply: vary_entry has no mem_obj\n"); + storeCreateMemObject(vary_entry, http->uri, http->log_uri); + + vary_sc = storeClientListAdd(vary_entry, this); + + StoreIOBuffer tempBuffer2(HTTP_REQBUF_SZ, 0, (char*)xmalloc(HTTP_REQBUF_SZ)); + storeClientCopy(vary_sc, vary_entry, tempBuffer2, FakeEntryToVariant, this); + + } else { + // "fake" (base) has memobj + debug(93, 9) ("handleIMSReply: vary_entry has mem_obj\n"); + fakeEntryToVariant(result); + } + + } else { + + debug(93, 9) ("handleIMSReply: no base entry found, sendMoreData()\n"); + sendMoreData(result); + + } + return; + } + + // this is the code handling conditional requests + // if it was vary-conditional then we should check this in handleIMSGiveClientUpdatedOldEntry() if (EBIT_TEST(http->storeEntry()->flags, ENTRY_ABORTED)) cleanUpAfterIMSCheck(); else if (STORE_PENDING == http->storeEntry()->store_status && 0 == status) @@ -627,19 +884,28 @@ case VARY_NONE: /* No variance detected. Continue as normal */ + flags.varyother = 0; break; case VARY_MATCH: /* This is the correct entity for this request. Continue */ debug(88, 2) ("clientProcessHit: Vary MATCH!\n"); + flags.varyother = 0; break; case VARY_OTHER: + /* This is not the correct entity for this request. We need * to requery the cache. */ + + flags.varyother = 1; + + // XXX won't it remove base object from memory removeClientStoreReference(&sc, http); + e = NULL; + /* Note: varyEvalyateMatch updates the request with vary information * so we only get here once. (it also takes care of cancelling loops) */ @@ -650,6 +916,7 @@ case VARY_CANCEL: /* varyEvaluateMatch found a object loop. Process as miss */ debug(88, 1) ("clientProcessHit: Vary object loop!\n"); + flags.varyother = 0; processMiss(); return; } @@ -661,10 +928,15 @@ return; } + if (storeCheckNegativeHit(e)) { + http->logType = LOG_TCP_NEGATIVE_HIT; sendMoreData(result); + } else if (!Config.onoff.offline && refreshCheckHTTP(e, r) && !http->flags.internal) { + + debug(88, 5) ("clientCacheHit: in refreshCheck() block\n"); /* * We hold a stale copy; it needs to be validated @@ -678,9 +950,15 @@ */ r->flags.need_validation = 1; - if (e->lastmod < 0) { + // ETag check... + const HttpHeader *rep_hdr = &e->getReply()->header; + ETag etag = httpHeaderGetETag(rep_hdr, HDR_ETAG); + + debug(93, 9) ("cacheHit: ETag: %s\n", etag.str); + + if (e->lastmod < 0 && !etag.str) { /* - * Previous reply didn't have a Last-Modified header, + * Previous reply didn't have a Last-Modified header or ETag, * we cannot revalidate it. */ http->logType = LOG_TCP_MISS; @@ -707,9 +985,9 @@ http->logType = LOG_TCP_MISS; processMiss(); } - } else if (r->flags.ims) { + } else if (r->flags.ims || r->flags.inm) { /* - * Handle If-Modified-Since requests from the client + * Handle If-Modified-Since and If-None-Match requests from the client */ if (e->getReply()->sline.status != HTTP_OK) { @@ -717,17 +995,67 @@ e->getReply()->sline.status); http->logType = LOG_TCP_MISS; processMiss(); - } else if (e->modifiedSince(http->request)) { + return; + + } + + // 304 vs 200 decisions + + // IMS based + int modifiedSince = r->flags.ims ? e->modifiedSince(http->request) : false; + + // INM based + int etagNoneMatch = r->flags.inm; + + if (r->flags.inm) { + + // r->inm is client ETags array + + // reply's ETag + const HttpHeader *hdr = &e->getReply()->header; + ETag etag = httpHeaderGetETag(hdr, HDR_ETAG); + const char *etag_str = etag.str; + + debug(93,5) ("cacheHit: etag from stored reply %s\n",etag_str); + + + // check if any of client's ETags matches + char *etag_inm; + int llen = 0; + + while(etag.str && llen < r->inmlen) { + + etag_inm = r->inm[llen++]; + + debug(93,5) ("cacheHit: parsing client INM: %s\n",etag_inm); + + if (!strcmp(etag_str,etag_inm)) { + etagNoneMatch = false; + break; + } + } + } + + if (modifiedSince || etagNoneMatch) { + // one of validators doesn't match -> send 200 OK http->logType = LOG_TCP_IMS_HIT; sendMoreData(result); + } else { + // both validators match -> send 304 Not Modified + time_t const timestamp = e->timestamp; + HttpReply *temprep = httpReplyMake304 (e->getReply()); http->logType = LOG_TCP_IMS_HIT; + removeClientStoreReference(&sc, http); + createStoreEntry(http->request->method, request_flags()); + e = http->storeEntry(); + /* * Copy timestamp from the original entry so the 304 * reply has a meaningful Age: header. @@ -735,6 +1063,7 @@ e->timestamp = timestamp; httpReplySwapOut (temprep, e); e->complete(); + /* TODO: why put this in the store and then serialise it and then parse it again. * Simply mark the request complete in our context and * write the reply struct to the client side @@ -782,6 +1111,20 @@ removeClientStoreReference(&sc, http); } + // vary check + vary_entry = NULL; + + // there was no variant matching client's request + // the flag was set in cacheHit with VARY_OTHER. + + if (flags.varyother) { + // base vary object + vary_entry = storeGetPublic(urlCanonical(r), r->method); + } + + + debug(93,9) ("processMiss: varyother: %d, vary_entry: %p\n", flags.varyother, vary_entry); + if (r->method == METHOD_PURGE) { purgeRequest(); return; @@ -805,9 +1148,36 @@ triggerInitialStoreRead(); return; } else { + assert(http->out.offset == 0); createStoreEntry(r->method, r->flags); - triggerInitialStoreRead(); + + + // vary procesing start... + + if (vary_entry) { + + http->request->lastmod = -1; + + assert(vary_entry->mem_obj); + + // get all the variants' etags + char * etag_keys = vary_entry->mem_obj->etag_mapping->keys(); + debug (93, 9) ("processMiss: inm=[%s]\n", etag_keys); + + // and use 'em + if (etag_keys) { + + http->request->etag = new String(etag_keys); + + triggerInitialStoreReadClone(HandleIMSReply); + + } else + triggerInitialStoreReadClone(HandleConditionalMiss); + + } else + triggerInitialStoreReadClone(HandleConditionalMiss); + if (http->redirect.status) { HttpReply *rep = httpReplyCreate(); @@ -821,9 +1191,11 @@ http->redirect.location); httpReplySwapOut(rep, http->storeEntry()); http->storeEntry()->complete(); + return; } + if (http->flags.internal) r->protocol = PROTO_INTERNAL; @@ -1459,6 +1831,11 @@ return; } + // if handleConditionalMiss decided to send 304 + if (saved304) { + holdingReply = saved304; + } + /* enforce 1.0 reply version */ holdingReply->sline.version = HttpVersion(1,0); @@ -1833,6 +2210,7 @@ } headers_sz = rep->hdr_sz; + debug(93, 9) ("\t --- processReplyAccess: headers_sz: %d\n", headers_sz); ACLChecklist *replyChecklist; replyChecklist = clientAclChecklistCreate(Config.accessList.reply, http); replyChecklist->reply = rep; @@ -1882,7 +2260,7 @@ assert(body_size >= 0); debug(88,3) - ("clientReplyContext::sendMoreData: Appending %d bytes after %d bytes of headers\n", + ("clientReplyContext::processReplyAccessResult: Appending %d bytes after %d bytes of headers\n", (int) body_size, rep->hdr_sz); #if ESI @@ -1896,7 +2274,11 @@ } #endif - if (http->request->method == METHOD_HEAD) { + + debug(93, 9) ("processReplyAccessResult: saved304: %p\n", + saved304); + // method was head or we're sending 304 so we don't have the body + if ((http->request->method == METHOD_HEAD) /*|| saved304*/) { /* do not forward body for HEAD replies */ body_size = 0; http->flags.done_copying = 1; @@ -1929,13 +2311,193 @@ tempBuffer.data = body_buf; } + debug(93, 9) ("\t ------- processReplyAccessResult: t->length: %d, t->offset: %ld, t->data:\n%s\n-\n", + tempBuffer.length, tempBuffer.offset, tempBuffer.data); + debug(93, 9) ("\t ------- processReplyAccessResult: n->length: %d, n->offset: %ld, n->data:\n%s\n-\n", + next()->readBuffer.length, next()->readBuffer.offset, next()->readBuffer.data); + /* TODO??: move the data in the buffer back by the request header size */ - clientStreamCallback((clientStreamNode *)http->client_stream.head->data, - http, rep, tempBuffer); + clientStreamCallback((clientStreamNode *)http->client_stream.head->data, http, rep, tempBuffer); + + return; +} + +/* + * see handleConditionalMiss + */ +void +clientReplyContext::HandleConditionalMiss(void *data, StoreIOBuffer result) { + clientReplyContext *context = static_cast(data); + context->handleConditionalMiss(result); +} + +/* + * decides whether to send 304 or 200 + * when there is no cached reply and client's request was conditional + * + * in case the request isnot conditional passes to sendMoreData + */ +void +clientReplyContext::handleConditionalMiss(StoreIOBuffer result) { + + + HttpRequest *r = http->request; + StoreEntry *e = http->storeEntry(); + assert(r); + + debug(93, 9) ("handleConditionalMiss: ims: %d, inm: %d\n", + r->flags.ims, r->flags.inm); + + // if the request isnot conditional + if (!r->flags.ims && !r->flags.inm) { + sendMoreData(result); + return; + } + + + debug(93, 9) ("handleConditionalMiss: Reply code %d\n", + e->getReply()->sline.status); + if (e->getReply()->sline.status != HTTP_OK ) { + + // not 200... passing + + sendMoreData(result); return; + + } + + // check if validators match, the same as in cacheHit + int modifiedSince = r->flags.ims ? e->modifiedSince(http->request) : false; + int etagNoneMatch = r->flags.inm; + + if (r->flags.inm) { + const HttpHeader *hdr = &e->getReply()->header; + ETag etag = httpHeaderGetETag(hdr, HDR_ETAG); + const char *etag_str = etag.str; + char *etag_inm; + int llen = 0; + + debug(93,5) ("handleConditionalMiss: etag from stored reply %s\n",etag_str); + + while(etag.str && llen < r->inmlen) { + etag_inm = r->inm[llen++]; + if (!strcmp(etag_str,etag_inm)) { + etagNoneMatch = false; + break; + } + } + } + + debug(93, 9) ("handleConditionalMiss: modifiedSince: %d, etagNoneMatch: %d\n", + modifiedSince, etagNoneMatch); + + if (modifiedSince || etagNoneMatch) { + // one of validators doesn't match -> send 200 OK + sendMoreData(result); + return; + + } + + // both validators match -> send 304 Not Modified + + // magic trick + saved304 = httpReplyMake304 (e->getReply()); + saved304->saved304 = 1; + + // swap current 200 out -> clearly wrong + //e->complete(); + + // fill result with new saved304 reply + // XXX unnecessary? + //Packer p; + //packerToStoreIOBufferInit(&p, &result); + //httpReplyPackHeadersInto(saved304, &p); + //packerClean(&p); + + //saved304->hdr_sz = result.length; + + debug(93, 9) ("\t --- handleConditionalMiss: length: %d, offset: %ld, data:\n%s\n-\n", + result.length, result.offset, result.data); + + sendMoreData(result); +} + + +/* + * see updateFakeEntry + */ +void +clientReplyContext::UpdateFakeEntry(void *data, StoreIOBuffer result) +{ + clientReplyContext *context = static_cast(data); + context->updateFakeEntry(result); +} + +/* + * updates Vary mappings when result passes through sendMoreData + */ +void clientReplyContext::updateFakeEntry(StoreIOBuffer result) +{ + StoreEntry *entry = http->storeEntry(); + + ETag etag = httpHeaderGetETag(&entry->mem_obj->getReply()->header, HDR_ETAG); + + // this is wrong when Vary has changed + const char *vary_headers = http->request->real_vary_headers; + + assert(vary_entry); + + // get the mappings from base vary object + CharHashTable *vhm = vary_entry->mem_obj->vary_headers_mapping; + CharHashTable *em = vary_entry->mem_obj->etag_mapping; + + // tells if the code below changes the mappings + int changed = 1; + + + if (!vhm->get((char*)vary_headers)) { + + if (etag.str) { + // there is ETag + if (em->get((char*)etag.str)) { + vhm->put((char*)vary_headers, (char*)em->get((char*)etag.str)); + } else { + vhm->put((char*)vary_headers, (char*)vary_headers); + em->put((char*)etag.str, (char*)vary_headers); + } + } else { + // no ETag + vhm->put((char*)vary_headers, (char*)vary_headers); + } + + } else { + + if (etag.str) { + // there is ETag + if (em->get((char*)etag.str)) { + if (strcmp(vhm->get((char*)vary_headers), em->get((char*)etag.str))) { + vhm->remove((char*)vary_headers); + vhm->put((char*)vary_headers, em->get((char*)etag.str)); + } else + changed = 0; + } else { + vhm->remove((char*)vary_headers); + vhm->put((char*)vary_headers, (char*)vary_headers); + em->put((char*)etag.str, (char*)vary_headers); + } + } else + changed = 0; + } + + // XXX if (changed) swap out + + // set in sendMoreData to avoid reentering + if (flags.varycomplete == 1) + sendMoreData(tempBufferVary); } + void clientReplyContext::sendMoreData (StoreIOBuffer result) { @@ -1944,6 +2506,68 @@ StoreEntry *entry = http->storeEntry(); + + // this is wrong when Vary has changed + const char *vary_headers = http->request->real_vary_headers; + + // if base vary object should be updated + if (vary_headers && !flags.varycomplete) { + + // get base + vary_entry = storeGetPublic(entry->mem_obj->url, entry->mem_obj->method); + + + if (vary_entry) { + + if (!vary_entry->mem_obj) { + debug(93, 9) ("sendMoreData: base vary object has no mem_obj\n"); + + // swap the mem_obj in + + storeCreateMemObject(vary_entry, http->uri, http->log_uri); + + vary_sc = storeClientListAdd(vary_entry, this); + + tempBufferVary = result; + StoreIOBuffer tempBuffer2(HTTP_REQBUF_SZ, 0, (char*)xmalloc(HTTP_REQBUF_SZ)); + + flags.varycomplete = 1; + + // swap mem_obj in and go to updateFakeEntry + storeClientCopy(vary_sc, vary_entry, tempBuffer2, UpdateFakeEntry, this); + + return; + } else { + + flags.varycomplete = 2; + + // go to updateFakeEntry + updateFakeEntry(result); + } + + } else { + + flags.varycomplete = 2; + debug(93, 9) ("sendMoreData: no base vary entry found!\n");; + + } + + } else if (vary_headers && flags.varycomplete == 1) { + + // after updateFakeEntry + + // unregister store client from base vary entry + // and continue + + assert(vary_entry); + + flags.varycomplete = 2; + + storeUnregister(vary_sc, vary_entry, this); + } + + debug(93, 9) ("sendMoreData: after vary processing\n"); + ConnStateData::Pointer conn = http->getConn(); int fd = conn.getRaw() != NULL ? conn->fd : -1; @@ -1958,6 +2582,14 @@ */ assert(reqofs == 0 || flags.storelogiccomplete); + debug(93, 9) ("\t --- sendMoreData: headersSent: %d, reqofs: %ld, buf:\n%s\n-\n", + flags.headersSent, reqofs, buf); + + debug(93, 9) ("\t --- sendMoreData: n->length: %d, n->offset: %ld, r->data:\n%s\n-\n", + next()->readBuffer.length, + next()->readBuffer.offset, + next()->readBuffer.data); + if (flags.headersSent && buf != result.data) { /* we've got to copy some data */ assert(result.length <= next()->readBuffer.length); @@ -2028,6 +2660,9 @@ buildReply(buf, reqofs); ssize_t body_size = reqofs; + debug(93, 9) ("\t --- sendMoreData: body_size: %d, buf: \n%s\n-\n", + (int)body_size, buf); + if (holdingReply) { holdingBuffer = result; processReplyAccess (); Index: squid3/src/client_side_reply.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/client_side_reply.h,v retrieving revision 1.6 retrieving revision 1.6.4.1 diff -u -r1.6 -r1.6.4.1 --- squid3/src/client_side_reply.h 11 Aug 2003 02:13:02 -0000 1.6 +++ squid3/src/client_side_reply.h 3 Jun 2004 22:50:07 -0000 1.6.4.1 @@ -1,6 +1,6 @@ /* - * $Id: client_side_reply.h,v 1.6 2003/08/11 02:13:02 squidadm Exp $ + * $Id: client_side_reply.h,v 1.6.4.1 2004/06/03 22:50:07 ahouhpuc Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -51,7 +51,11 @@ void operator delete (void *address); static STCB CacheHit; static STCB HandleIMSReply; + static STCB HandleConditionalMiss; static STCB SendMoreData; + static STCB UpdateFakeEntry; + static STCB FakeEntryToVariant; + static STCB VariantUpdateSend; clientReplyContext(clientHttpRequest *); ~clientReplyContext(); @@ -108,7 +112,10 @@ int storelogiccomplete: 1; - +int varycomplete: + 2; +int varyother: + 1; int complete: 1; /* we have read all we can from upstream */ bool headersSent; @@ -129,6 +136,8 @@ void startSendProcess(); StoreIOBuffer holdingBuffer; HttpReply *holdingReply; + + HttpReply *saved304; void processReplyAccess(); static PF ProcessReplyAccessResult; void processReplyAccessResult(bool accessAllowed); @@ -141,8 +150,15 @@ void processOnlyIfCachedMiss(); void cacheHit(StoreIOBuffer result); void handleIMSReply(StoreIOBuffer result); + + void updateFakeEntry(StoreIOBuffer result); + void fakeEntryToVariant(StoreIOBuffer result); + void variantUpdateSend(StoreIOBuffer result); + void handleConditionalMiss(StoreIOBuffer result); + void sendMoreData(StoreIOBuffer result); void triggerInitialStoreRead(); + void triggerInitialStoreReadClone(STCB* callback); void cleanUpAfterIMSCheck(); void handlePartialIMSHeaders(); void handleIMSGiveClientUpdatedOldEntry(); @@ -153,6 +169,13 @@ StoreEntry *old_entry; store_client *old_sc; /* ... for entry to be validated */ + + //base vary StoreEntry + StoreEntry *vary_entry; + store_client *vary_sc; + // buffer for base vary object updates + StoreIOBuffer tempBufferVary; + bool deleting; }; Index: squid3/src/client_side_request.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/client_side_request.cc,v retrieving revision 1.28 retrieving revision 1.28.2.1 diff -u -r1.28 -r1.28.2.1 --- squid3/src/client_side_request.cc 8 Apr 2004 01:59:44 -0000 1.28 +++ squid3/src/client_side_request.cc 3 Jun 2004 22:50:07 -0000 1.28.2.1 @@ -1,6 +1,6 @@ /* - * $Id: client_side_request.cc,v 1.28 2004/04/08 01:59:44 squidadm Exp $ + * $Id: client_side_request.cc,v 1.28.2.1 2004/06/03 22:50:07 ahouhpuc Exp $ * * DEBUG: section 85 Client-side Request Routines * AUTHOR: Robert Collins (Originally Duane Wessels in client_side.c) @@ -548,6 +548,19 @@ const char *str; #endif + + // check for INM + String inm = httpHeaderGetINM(req_hdr); + debug(93, 1) ("clientInterpretRequestHeaders: INM: %s\n", inm.buf()); + + // parse INM into ETag array + if (fillArrayWithStr(&inm, &request->inm, &request->inmlen)) + request->flags.inm = 1; + + debug(93, 9) ("clientInterpretRequestHeaders: inmlen=%d flags.inm=%d\n",request->inmlen, request->flags.inm); + + + // check for IMS request->imslen = -1; request->ims = httpHeaderGetTime(req_hdr, HDR_IF_MODIFIED_SINCE); Index: squid3/src/http.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/http.cc,v retrieving revision 1.33 retrieving revision 1.33.2.1 diff -u -r1.33 -r1.33.2.1 --- squid3/src/http.cc 5 Apr 2004 02:00:28 -0000 1.33 +++ squid3/src/http.cc 3 Jun 2004 22:50:07 -0000 1.33.2.1 @@ -1,6 +1,6 @@ /* - * $Id: http.cc,v 1.33 2004/04/05 02:00:28 squidadm Exp $ + * $Id: http.cc,v 1.33.2.1 2004/06/03 22:50:07 ahouhpuc Exp $ * * DEBUG: section 11 Hypertext Transfer Protocol (HTTP) * AUTHOR: Harvest Derived @@ -601,6 +601,8 @@ debug(11, 3) ("httpProcessReplyHeader: key '%s'\n", entry->getMD5Text()); + debug(93, 9) ("processReplyHeader: reply got, header being parsed\n"); + if (reply_hdr == NULL) reply_hdr = (char *)memAllocate(MEM_8K_BUF); @@ -698,6 +700,8 @@ if (vary) { entry->mem_obj->vary_headers = xstrdup(vary); + /* XXX: ^^^ possible memory leak */ + /* Kill the old base object if a change in variance is detected */ httpMakePublic(entry); } else { @@ -937,9 +941,16 @@ * we want to process the reply headers. */ /* doesn't return */ + { processReplyHeader(buf, len); + } else { + + // store_status may be STORE_OK if we passed through handleConditionalMiss + // and decided to return 304 there + //if (entry->store_status == STORE_PENDING) fwdComplete(fwd); + do_next_read = 0; comm_close(fd); } @@ -972,6 +983,10 @@ void HttpStateData::processReplyData(const char *buf, size_t len) { + + debug(93, 9) ("\t --- processReplyData: reply_hdr_state: %d, len: %d, buf: \n%s\n-\n", + reply_hdr_state, len, buf); + if (reply_hdr_state < 2) { do_next_read = 1; maybeReadData(); @@ -1002,7 +1017,12 @@ tempBuffer.length = len; tempBuffer.offset = currentOffset; currentOffset += len; + + // store_status may be STORE_OK if we passed through handleConditionalMiss + // and decided to send 304 there + //if (entry->store_status == STORE_PENDING) entry->write(tempBuffer); + } if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { @@ -1016,11 +1036,13 @@ switch (persistentConnStatus()) { case INCOMPLETE_MSG: + debug(93, 9) ("processReplyData: persistentConnStatus(): INCOMPLETE_MSG\n"); /* Wait for EOF condition */ do_next_read = 1; break; case COMPLETE_PERSISTENT_MSG: + debug(93, 9) ("processReplyData: persistentConnStatus(): COMPLETE_PERSISTENT_MSG\n"); /* yes we have to clear all these! */ commSetTimeout(fd, -1, NULL, NULL); do_next_read = 0; @@ -1043,6 +1065,7 @@ return; case COMPLETE_NONPERSISTENT_MSG: + debug(93, 9) ("processReplyData: persistentConnStatus(): COMPLETE_NONPERSISTENT_MSG\n"); /* close the connection ourselves */ /* yes - same as for a complete persistent conn here */ commSetTimeout(fd, -1, NULL, NULL); @@ -1057,6 +1080,7 @@ return; } + debug(93, 9) ("processReplyData: before maybeReadData\n"); maybeReadData(); } @@ -1137,9 +1161,15 @@ assert (hdr_out->owner == hoRequest); /* append our IMS header */ + // add If-Modified-Since if needed if (request->lastmod > -1 && request->method == METHOD_GET) httpHeaderPutTime(hdr_out, HDR_IF_MODIFIED_SINCE, request->lastmod); + // add If-None-Match if needed, etags prepared earlier + if (request->etag && request->method == METHOD_GET) { + httpHeaderPutStr(hdr_out, HDR_IF_NONE_MATCH, request->etag->buf()); + } + bool we_do_ranges = decideIfWeDoRanges (orig_request); String strConnection (httpHeaderGetList(hdr_in, HDR_CONNECTION)); @@ -1406,12 +1436,9 @@ break; + // don't pass clients IMS or INM case HDR_IF_MODIFIED_SINCE: - /* append unless we added our own; - * note: at most one client's ims header can pass through */ - - if (!httpHeaderHas(hdr_out, HDR_IF_MODIFIED_SINCE)) - httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e)); + case HDR_IF_NONE_MATCH: break; Index: squid3/src/protos.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/protos.h,v retrieving revision 1.41 retrieving revision 1.41.2.1 diff -u -r1.41 -r1.41.2.1 --- squid3/src/protos.h 5 Apr 2004 02:00:28 -0000 1.41 +++ squid3/src/protos.h 3 Jun 2004 22:50:07 -0000 1.41.2.1 @@ -1,6 +1,6 @@ /* - * $Id: protos.h,v 1.41 2004/04/05 02:00:28 squidadm Exp $ + * $Id: protos.h,v 1.41.2.1 2004/06/03 22:50:07 ahouhpuc Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -163,6 +163,9 @@ SQUIDCEXTERN void packerToStoreInit(Packer * p, StoreEntry * e); SQUIDCEXTERN void packerToMemInit(Packer * p, MemBuf * mb); + +class StoreIOBuffer; +SQUIDCEXTERN void packerToStoreIOBufferInit(Packer * p, StoreIOBuffer * res); SQUIDCEXTERN void packerClean(Packer * p); SQUIDCEXTERN void packerAppend(Packer * p, const char *buf, int size); #if STDC_HEADERS @@ -415,6 +418,10 @@ SQUIDCEXTERN const char *httpHeaderGetStr(const HttpHeader * hdr, http_hdr_type id); SQUIDCEXTERN const char *httpHeaderGetLastStr(const HttpHeader * hdr, http_hdr_type id); SQUIDCEXTERN const char *httpHeaderGetAuth(const HttpHeader * hdr, http_hdr_type id, const char *auth_scheme); + +extern int fillArrayWithStr(const String *, char ***, int *); +extern String httpHeaderGetINM(const HttpHeader * hdr); + extern String httpHeaderGetList(const HttpHeader * hdr, http_hdr_type id); extern String httpHeaderGetStrOrList(const HttpHeader * hdr, http_hdr_type id); extern String httpHeaderGetByName(const HttpHeader * hdr, const char *name); Index: squid3/src/store.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/store.cc,v retrieving revision 1.25 retrieving revision 1.25.2.1 diff -u -r1.25 -r1.25.2.1 --- squid3/src/store.cc 30 Sep 2003 02:12:40 -0000 1.25 +++ squid3/src/store.cc 3 Jun 2004 22:50:07 -0000 1.25.2.1 @@ -1,6 +1,6 @@ /* - * $Id: store.cc,v 1.25 2003/09/30 02:12:40 squidadm Exp $ + * $Id: store.cc,v 1.25.2.1 2004/06/03 22:50:07 ahouhpuc Exp $ * * DEBUG: section 20 Storage Manager * AUTHOR: Harvest Derived @@ -310,8 +310,19 @@ { storeSetMemStatus(e, NOT_IN_MEMORY); MemObject *mem = e->mem_obj; + + // since MemObject holds additional vary information, this has to be done + if (mem) { + + if (mem->etag_mapping) + delete mem->etag_mapping; + + if (mem->vary_headers_mapping) + delete mem->vary_headers_mapping; + e->mem_obj = NULL; delete mem; + } } static void @@ -626,12 +637,17 @@ if (!mem->vary_headers) { /* First handle the case where the object no longer varies */ safe_free(request->vary_headers); + safe_free(request->real_vary_headers); + } else { - if (request->vary_headers && strcmp(request->vary_headers, mem->vary_headers) != 0) { + + if (request->real_vary_headers && strcmp(request->real_vary_headers, mem->vary_headers) != 0) { /* Oops.. the variance has changed. Kill the base object * to record the new variance key */ safe_free(request->vary_headers); /* free old "bad" variance key */ + safe_free(request->real_vary_headers); /* free old "bad" variance key */ + pe = storeGetPublic(mem->url, mem->method); if (pe) @@ -662,6 +678,19 @@ vary.clean(); } + // add mappings + pe->mem_obj->etag_mapping = new CharHashTable(); + pe->mem_obj->vary_headers_mapping = new CharHashTable(); + + // fill the mappings + pe->mem_obj->vary_headers_mapping->put((char*)request->vary_headers, (char*)request->vary_headers); + ETag etag = httpHeaderGetETag(&mem->getReply()->header, HDR_ETAG); + // XXX ^^^ memory leak? + + if (etag.str) { + pe->mem_obj->etag_mapping->put((char*)etag.str, (char*)request->vary_headers); + } + #if X_ACCELERATOR_VARY vary = httpHeaderGetList(&mem->getReply()->header, HDR_X_ACCELERATOR_VARY); Index: squid3/src/store_swapmeta.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/store_swapmeta.cc,v retrieving revision 1.5 retrieving revision 1.5.2.1 diff -u -r1.5 -r1.5.2.1 --- squid3/src/store_swapmeta.cc 5 Aug 2003 02:12:49 -0000 1.5 +++ squid3/src/store_swapmeta.cc 3 Jun 2004 22:50:07 -0000 1.5.2.1 @@ -1,6 +1,6 @@ /* - * $Id: store_swapmeta.cc,v 1.5 2003/08/05 02:12:49 squidadm Exp $ + * $Id: store_swapmeta.cc,v 1.5.2.1 2004/06/03 22:50:07 ahouhpuc Exp $ * * DEBUG: section 20 Storage Manager Swapfile Metadata * AUTHOR: Kostas Anagnostakis @@ -39,6 +39,8 @@ #include "StoreMeta.h" #include "StoreMetaUnpacker.h" +#include "StoreMetaVary.h" + void storeSwapTLVFree(tlv * n) { @@ -60,7 +62,11 @@ tlv *TLV = NULL; /* we'll return this */ tlv **T = &TLV; const char *url; - const char *vary; + + // packed vary stuff + const char *packed_vary; + int packed_vary_len = 0; + assert(e->mem_obj != NULL); assert(e->swap_status == SWAPOUT_WRITING); url = storeUrl(e); @@ -89,10 +95,11 @@ } T = StoreMeta::Add(T, t); - vary = e->mem_obj->vary_headers; + // pack vary stuff + packed_vary = storeMetaVaryPack(e->mem_obj, &packed_vary_len); - if (vary) { - t =StoreMeta::Factory(STORE_META_VARY_HEADERS, strlen(vary) + 1, vary); + if (packed_vary) { + t =StoreMeta::Factory(STORE_META_VARY_HEADERS, packed_vary_len, packed_vary); if (!t) { storeSwapTLVFree(TLV); Index: squid3/src/store_swapout.cc =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/store_swapout.cc,v retrieving revision 1.10 retrieving revision 1.10.2.1 diff -u -r1.10 -r1.10.2.1 --- squid3/src/store_swapout.cc 12 Feb 2004 03:09:05 -0000 1.10 +++ squid3/src/store_swapout.cc 3 Jun 2004 22:50:07 -0000 1.10.2.1 @@ -1,6 +1,6 @@ /* - * $Id: store_swapout.cc,v 1.10 2004/02/12 03:09:05 squidadm Exp $ + * $Id: store_swapout.cc,v 1.10.2.1 2004/06/03 22:50:07 ahouhpuc Exp $ * * DEBUG: section 20 Storage Manager Swapout Functions * AUTHOR: Duane Wessels @@ -172,6 +172,7 @@ void storeSwapOut(StoreEntry * e) { + if (!e->mem_obj) return; Index: squid3/src/structs.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/src/structs.h,v retrieving revision 1.51 retrieving revision 1.51.2.1 diff -u -r1.51 -r1.51.2.1 --- squid3/src/structs.h 5 Apr 2004 02:00:28 -0000 1.51 +++ squid3/src/structs.h 3 Jun 2004 22:50:07 -0000 1.51.2.1 @@ -1,6 +1,6 @@ /* - * $Id: structs.h,v 1.51 2004/04/05 02:00:28 squidadm Exp $ + * $Id: structs.h,v 1.51.2.1 2004/06/03 22:50:07 ahouhpuc Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -1412,6 +1412,9 @@ unsigned int ims: 1; +unsigned int inm: + 1; + unsigned int auth: 1;