From: rousskov <> Date: Sat, 21 Mar 1998 01:06:37 +0000 (+0000) Subject: - Separated raw HTTP headers from their "compiled" values. Squid is now X-Git-Tag: SQUID_3_0_PRE1~3777 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d8b249ef67c9f0faf42a85cf719c161751fcf766;p=thirdparty%2Fsquid.git - Separated raw HTTP headers from their "compiled" values. Squid is now forwarding headers even it cannot "compile" them. Virtually no changes to common format headers are done. Compiled values are stored in Reply/Request objects. --- diff --git a/src/HttpHdrCc.cc b/src/HttpHdrCc.cc index 30abe23600..0f6ab9414e 100644 --- a/src/HttpHdrCc.cc +++ b/src/HttpHdrCc.cc @@ -1,6 +1,6 @@ /* - * $Id: HttpHdrCc.cc,v 1.7 1998/03/18 00:29:55 wessels Exp $ + * $Id: HttpHdrCc.cc,v 1.8 1998/03/20 18:06:37 rousskov Exp $ * * DEBUG: section 65 HTTP Cache Control Header * AUTHOR: Alex Rousskov @@ -41,7 +41,9 @@ static const HttpHeaderFieldAttrs CcAttrs[CC_ENUM_END] = {"no-transform", CC_NO_TRANSFORM}, {"must-revalidate", CC_MUST_REVALIDATE}, {"proxy-revalidate", CC_PROXY_REVALIDATE}, - {"max-age", CC_MAX_AGE} + {"only-if-cached", CC_ONLY_IF_CACHED}, + {"max-age", CC_MAX_AGE}, + {"Other,", CC_OTHER} /* ',' will protect from matches */ }; HttpHeaderFieldInfo *CcFieldsInfo = NULL; @@ -108,13 +110,14 @@ httpHdrCcParseInit(HttpHdrCc * cc, const char *str) ilen = p++ - item; /* find type */ type = httpHeaderIdByName(item, ilen, - CcFieldsInfo, CC_ENUM_END, -1); + CcFieldsInfo, CC_ENUM_END); if (type < 0) { debug(65, 2) ("hdr cc: unknown cache-directive: near '%s' in '%s'\n", item, str); - continue; + type = CC_OTHER; } if (EBIT_TEST(cc->mask, type)) { - debug(65, 2) ("hdr cc: ignoring duplicate cache-directive: near '%s' in '%s'\n", item, str); + if (type != CC_OTHER) + debug(65, 2) ("hdr cc: ignoring duplicate cache-directive: near '%s' in '%s'\n", item, str); CcFieldsInfo[type].stat.repCount++; continue; } @@ -123,16 +126,14 @@ httpHdrCcParseInit(HttpHdrCc * cc, const char *str) /* post-processing special cases */ switch (type) { case CC_MAX_AGE: - if (p) - cc->max_age = (time_t) atoi(p); - if (cc->max_age < 0) { + if (!p || !httpHeaderParseInt(p, &cc->max_age)) { debug(65, 2) ("cc: invalid max-age specs near '%s'\n", item); cc->max_age = -1; EBIT_CLR(cc->mask, type); } break; default: - /* note that we ignore most of '=' specs @?@ */ + /* note that we ignore most of '=' specs */ break; } } @@ -168,7 +169,7 @@ httpHdrCcPackInto(const HttpHdrCc * cc, Packer * p) pcount++; } for (flag = 0; flag < CC_ENUM_END; flag++) { - if (EBIT_TEST(cc->mask, flag)) { + if (EBIT_TEST(cc->mask, flag) && flag != CC_OTHER) { packerPrintf(p, pcount ? ", %s" : "%s", CcFieldsInfo[flag].name); pcount++; } diff --git a/src/HttpHeader.cc b/src/HttpHeader.cc index 471ffa6e96..593d5ac968 100644 --- a/src/HttpHeader.cc +++ b/src/HttpHeader.cc @@ -1,6 +1,6 @@ /* - * $Id: HttpHeader.cc,v 1.25 1998/03/17 17:35:12 rousskov Exp $ + * $Id: HttpHeader.cc,v 1.26 1998/03/20 18:06:38 rousskov Exp $ * * DEBUG: section 55 HTTP Header * AUTHOR: Alex Rousskov @@ -46,27 +46,17 @@ * HttpHeader is an object that represents all message-headers in a message. * HttpHeader does not manage start-line. * - * HttpHeader is implemented as a collection of header "entries" - * An entry is a (field_id, field) pair where - * - field_id is one of the http_hdr_type ids, - * - field is a compiled(parsed) image of message-header. + * HttpHeader is implemented as a collection of header "entries". + * An entry is a (field_id, field_name, field_value) triplet. */ -/* - * local types - */ +/* To-Do: fix parseCount stats @?@ @?@ */ + /* - * HttpHeader entry (type of cached value is Headers[id].type) + * local types */ -struct _HttpHeaderEntry { - String name; - String value; - field_store cache; - short int id; -}; - /* per header statistics */ typedef struct { @@ -93,6 +83,9 @@ typedef struct { static const HttpHeaderFieldAttrs HeadersAttrs[] = { {"Accept", HDR_ACCEPT, ftStr}, + {"Accept-Charset", HDR_ACCEPT_CHARSET, ftStr}, + {"Accept-Encoding", HDR_ACCEPT_ENCODING, ftStr}, + {"Accept-Language", HDR_ACCEPT_LANGUAGE, ftStr}, {"Accept-Ranges", HDR_ACCEPT_RANGES, ftStr}, {"Age", HDR_AGE, ftInt}, {"Cache-Control", HDR_CACHE_CONTROL, ftPCc}, @@ -110,8 +103,9 @@ static const HttpHeaderFieldAttrs HeadersAttrs[] = {"Last-Modified", HDR_LAST_MODIFIED, ftDate_1123}, {"Location", HDR_LOCATION, ftStr}, {"Max-Forwards", HDR_MAX_FORWARDS, ftInt}, + {"Mime-Version", HDR_MIME_VERSION, ftStr}, /* for now */ {"Proxy-Authenticate", HDR_PROXY_AUTHENTICATE, ftStr}, - {"Proxy-Connection", HDR_PROXY_KEEPALIVE, ftInt}, /* true/false */ + {"Proxy-Connection", HDR_PROXY_CONNECTION, ftStr}, {"Public", HDR_PUBLIC, ftStr}, {"Range", HDR_RANGE, ftPRange}, {"Retry-After", HDR_RETRY_AFTER, ftStr}, /* for now */ @@ -121,22 +115,19 @@ static const HttpHeaderFieldAttrs HeadersAttrs[] = {"Warning", HDR_WARNING, ftStr}, /* for now */ {"WWW-Authenticate", HDR_WWW_AUTHENTICATE, ftStr}, {"X-Cache", HDR_X_CACHE, ftStr}, - {"Other:", HDR_OTHER, ftPExtField} /* ':' will not allow matches */ + {"Other:", HDR_OTHER, ftStr} /* ':' will not allow matches */ }; static HttpHeaderFieldInfo *Headers = NULL; /* * headers with field values defined as #(values) in HTTP/1.1 - * - * We have listed all possible list headers according to - * draft-ietf-http-v11-spec-rev-01.txt. Headers that are currently not - * recognized, are commented out. + * Headers that are currently not recognized, are commented out. */ -static int ListHeadersMask = 0; /* set run-time using ListHeadersArr */ +static HttpHeaderMask ListHeadersMask; /* set run-time using ListHeadersArr */ static http_hdr_type ListHeadersArr[] = { HDR_ACCEPT, - /* HDR_ACCEPT_CHARSET, HDR_ACCEPT_ENCODING, HDR_ACCEPT_LANGUAGE, */ + HDR_ACCEPT_CHARSET, HDR_ACCEPT_ENCODING, HDR_ACCEPT_LANGUAGE, HDR_ACCEPT_RANGES, /* HDR_ALLOW, */ HDR_CACHE_CONTROL, HDR_CONNECTION, @@ -150,32 +141,23 @@ static http_hdr_type ListHeadersArr[] = /* HDR_EXPECT, HDR_TE, HDR_TRAILER */ }; -/* for these headers duplicates are left; list headers do not belong here */ -static int DupHeadersMask = 0; /* set run-time */ -static http_hdr_type DupHeadersArr[] = { - HDR_SET_COOKIE, HDR_X_CACHE, HDR_OTHER -}; - -static int ReplyHeadersMask = 0; /* set run-time using ReplyHeaders */ +static HttpHeaderMask ReplyHeadersMask; /* set run-time using ReplyHeaders */ static http_hdr_type ReplyHeadersArr[] = { - HDR_RANGE, - - HDR_ACCEPT, HDR_ACCEPT_RANGES, HDR_AGE, HDR_CACHE_CONTROL, HDR_CONTENT_LENGTH, - HDR_CONTENT_MD5, HDR_CONTENT_RANGE, HDR_CONTENT_TYPE, HDR_DATE, HDR_ETAG, HDR_EXPIRES, - HDR_LAST_MODIFIED, HDR_LOCATION, HDR_MAX_FORWARDS, HDR_PUBLIC, HDR_RETRY_AFTER, - HDR_SERVER, HDR_SET_COOKIE, HDR_UPGRADE, HDR_WARNING, HDR_PROXY_KEEPALIVE, HDR_X_CACHE, HDR_OTHER + HDR_ACCEPT, HDR_ACCEPT_CHARSET, HDR_ACCEPT_ENCODING, HDR_ACCEPT_LANGUAGE, + HDR_ACCEPT_RANGES, HDR_AGE, HDR_CACHE_CONTROL, HDR_CONTENT_LENGTH, + HDR_CONTENT_MD5, HDR_CONTENT_RANGE, HDR_CONTENT_TYPE, HDR_DATE, HDR_ETAG, + HDR_EXPIRES, HDR_LAST_MODIFIED, HDR_LOCATION, HDR_MAX_FORWARDS, + HDR_MIME_VERSION, HDR_PUBLIC, HDR_RETRY_AFTER, HDR_SERVER, HDR_SET_COOKIE, + HDR_UPGRADE, HDR_WARNING, HDR_PROXY_CONNECTION, HDR_X_CACHE, HDR_OTHER }; -static int RequestHeadersMask = 0; /* set run-time using RequestHeaders */ +static HttpHeaderMask RequestHeadersMask; /* set run-time using RequestHeaders */ static http_hdr_type RequestHeadersArr[] = { HDR_RANGE, HDR_OTHER }; -/* when first field is added, this is how much entries we allocate */ -#define INIT_FIELDS_PER_HEADER 8 - /* header accounting */ static HttpHeaderStat HttpHeaderStats[] = { @@ -198,38 +180,16 @@ static int HeaderEntryParsedCount = 0; #define assert_eid(id) assert((id) >= 0 && (id) < HDR_ENUM_END) static HttpHeaderEntry *httpHeaderGetEntry(const HttpHeader * hdr, HttpHeaderPos * pos); -static void httpHeaderDelAt(HttpHeader * hdr, HttpHeaderPos pos, int auto_sync); -static void httpHeaderDelById(HttpHeader * hdr, http_hdr_type id); -static void httpHeaderAddParsedEntry(HttpHeader * hdr, HttpHeaderEntry * e); -static void httpHeaderAddNewEntry(HttpHeader * hdr, const HttpHeaderEntry * e); -static field_store httpHeaderGetCache(const HttpHeader * hdr, http_hdr_type id); -static void httpHeaderSet(HttpHeader * hdr, HttpHeaderEntry *e); -static void httpHeaderSyncMasks(HttpHeader * hdr, const HttpHeaderEntry * e, int add); -static void httpHeaderGrow(HttpHeader * hdr); - -static void httpHeaderEntryInit(HttpHeaderEntry * e, http_hdr_type id, const char *value, field_store cache); -static void httpHeaderEntryExtInit(HttpHeaderEntry * e, const char *name, const char *value); -static void httpHeaderEntryClean(HttpHeaderEntry * e); -static int httpHeaderEntryParseInit(HttpHeaderEntry * e, const char *field_start, const char *field_end, int mask); -static int httpHeaderEntryParse(HttpHeaderEntry * e, const char *field_start, const char *field_end); -static void httpHeaderEntrySyncCache(HttpHeaderEntry * e); -static void httpHeaderEntrySyncCacheByType(HttpHeaderEntry * e); -/* -static int httpHeaderEntryParseExtFieldInit(HttpHeaderEntry * e, int id, const HttpHdrExtField * f); -static int httpHeaderEntryParseByTypeInit(HttpHeaderEntry * e, int id, const HttpHdrExtField * f); -*/ -static HttpHeaderEntry httpHeaderEntryClone(const HttpHeaderEntry * e); -/* -static void httpHeaderEntryPackByType(const HttpHeaderEntry * e, Packer * p); -*/ -static void httpHeaderEntryJoinWith(HttpHeaderEntry * e, const HttpHeaderEntry * newe); -/* -static const char *httpHeaderEntryName(const HttpHeaderEntry * e); -*/ +static void httpHeaderDelAt(HttpHeader * hdr, HttpHeaderPos pos); +/* static int httpHeaderDelById(HttpHeader * hdr, http_hdr_type id); */ +static void httpHeaderAddEntry(HttpHeader * hdr, HttpHeaderEntry * e); +static String httpHeaderJoinEntries(const HttpHeader *hdr, http_hdr_type id); -static void httpHeaderFieldInit(field_store * field); -static field_store httpHeaderFieldDup(field_type type, field_store value); -static field_store httpHeaderFieldBadValue(field_type type); +static HttpHeaderEntry *httpHeaderEntryCreate(http_hdr_type id, const char *name, const char *value); +static void httpHeaderEntryDestroy(HttpHeaderEntry * e); +static HttpHeaderEntry *httpHeaderEntryParseCreate(const char *field_start, const char *field_end); +static HttpHeaderEntry *httpHeaderEntryClone(const HttpHeaderEntry * e); +static void httpHeaderNoteParsedEntry(http_hdr_type id, String value, int error); static void httpHeaderStatInit(HttpHeaderStat * hs, const char *label); static void httpHeaderStatDump(const HttpHeaderStat * hs, StoreEntry * e); @@ -237,40 +197,6 @@ static void httpHeaderStatDump(const HttpHeaderStat * hs, StoreEntry * e); /* handy to determine the #elements in a static array */ #define countof(arr) (sizeof(arr)/sizeof(*arr)) -/* - * some compilers do not want to convert a type into a union which that type - * belongs to so we have to do it manualy - */ -static field_store -intField(int n) -{ - field_store f; - f.v_int = n; - return f; -} -static field_store -timeField(time_t t) -{ - field_store f; - f.v_time = t; - return f; -} -static field_store -strField(String s) -{ - field_store f; - f.v_str = s; - return f; -} -static field_store -ptrField(void *p) -{ - field_store f; - f.v_pcc = p; - return f; -} - - /* * Module initialization routines */ @@ -279,16 +205,13 @@ void httpHeaderInitModule() { int i; - /* paranoid check if smbd put a big object into field_store */ - assert(sizeof(field_store) == sizeof(String)); + /* check that we have enough space for masks */ + assert(8*sizeof(HttpHeaderMask) >= HDR_ENUM_END); Headers = httpHeaderBuildFieldsInfo(HeadersAttrs, HDR_ENUM_END); /* create masks */ - ListHeadersMask = httpHeaderCalcMask((const int *) ListHeadersArr, countof(ListHeadersArr)); - DupHeadersMask = httpHeaderCalcMask((const int *) DupHeadersArr, countof(DupHeadersArr)); - /* dup-headers cannot be joined */ - assert(!(ListHeadersMask & DupHeadersMask)); - ReplyHeadersMask = httpHeaderCalcMask((const int *) ReplyHeadersArr, countof(ReplyHeadersArr)); - RequestHeadersMask = httpHeaderCalcMask((const int *) RequestHeadersArr, countof(RequestHeadersArr)); + httpHeaderCalcMask(&ListHeadersMask, (const int *) ListHeadersArr, countof(ListHeadersArr)); + httpHeaderCalcMask(&ReplyHeadersMask, (const int *) ReplyHeadersArr, countof(ReplyHeadersArr)); + httpHeaderCalcMask(&RequestHeadersMask, (const int *) RequestHeadersArr, countof(RequestHeadersArr)); /* init header stats */ for (i = 0; i < HttpHeaderStatCount; i++) httpHeaderStatInit(HttpHeaderStats + i, HttpHeaderStats[i].label); @@ -320,12 +243,13 @@ httpHeaderStatInit(HttpHeaderStat * hs, const char *label) * HttpHeader Implementation */ - void httpHeaderInit(HttpHeader * hdr) { assert(hdr); + debug(55, 7) ("init-ing hdr: %p\n", hdr); memset(hdr, 0, sizeof(*hdr)); + arrayInit(&hdr->entries); } void @@ -337,33 +261,32 @@ httpHeaderClean(HttpHeader * hdr) debug(55, 7) ("cleaning hdr: %p\n", hdr); assert(hdr); - statHistCount(&HttpHeaderStats[0].hdrUCountDistr, hdr->ucount); + statHistCount(&HttpHeaderStats[0].hdrUCountDistr, hdr->entries.count); HeaderDestroyedCount++; - NonEmptyHeaderDestroyedCount += hdr->ucount > 0; + NonEmptyHeaderDestroyedCount += hdr->entries.count > 0; while ((e = httpHeaderGetEntry(hdr, &pos))) { - /* fix this (for cc too) for req headers @?@ */ + /* fix this for req headers @?@ */ statHistCount(&HttpHeaderStats[0].fieldTypeDistr, e->id); - if (e->id == HDR_CACHE_CONTROL && e->cache.v_pcc) - httpHdrCcUpdateStats(e->cache.v_pcc, &HttpHeaderStats[0].ccTypeDistr); - httpHeaderEntryClean(e); /* yes, this leaves us in inconsistent state */ + /* yes, this destroy() leaves us in an incosistent state */ + httpHeaderEntryDestroy(e); } - xfree(hdr->entries); - hdr->emask = 0; - hdr->entries = NULL; - hdr->capacity = hdr->ucount = 0; + arrayClean(&hdr->entries); } +/* use fresh entries to replace old ones */ void -httpHeaderCopy(HttpHeader *dest, const HttpHeader *src) +httpHeaderUpdate(HttpHeader *old, const HttpHeader *fresh) { HttpHeaderEntry *e; + HttpHeaderEntry *e_clone; HttpHeaderPos pos = HttpHeaderInitPos; - assert(dest && src); - debug(55, 7) ("copying hdr: %p <- %p\n", dest, src); + assert(old && fresh); + debug(55, 7) ("updating hdr: %p <- %p\n", old, fresh); - while ((e = httpHeaderGetEntry(src, &pos))) { - HttpHeaderEntry e_clone = httpHeaderEntryClone(e); - httpHeaderAddNewEntry(dest, &e_clone); + while ((e = httpHeaderGetEntry(fresh, &pos))) { + httpHeaderDelByName(old, strBuf(e->name)); + e_clone = httpHeaderEntryClone(e); + httpHeaderAddEntry(old, e_clone); } } @@ -380,36 +303,23 @@ int httpHeaderParse(HttpHeader * hdr, const char *header_start, const char *header_end) { const char *field_start = header_start; - HttpHeaderEntry e; - int mask = 0; + HttpHeaderEntry *e; assert(hdr); assert(header_start && header_end); - debug(55, 7) ("parsing hdr: (%p) '%s'\n...\n", hdr, getStringPrefix(header_start)); + debug(55, 7) ("parsing hdr: (%p)\n%s\n", hdr, getStringPrefix(header_start, header_end)); HeaderParsedCount++; - /* select appropriate field mask */ - mask = ( /* fix this @?@ @?@ */ 1) ? ReplyHeadersMask : RequestHeadersMask; /* commonn format headers are ":[ws]" lines delimited by */ while (field_start < header_end) { const char *field_end = field_start + strcspn(field_start, "\r\n"); - /*tmp_debug(here) ("found end of field: %d\n", (int)*field_end); */ if (!*field_end || field_end > header_end) return httpHeaderReset(hdr); /* missing */ - /* - * If we fail to parse a field, we ignore it. We also could claim that - * the whole header is invalid. The latter is safer, but less robust. - * Note that we should be able to parse any commonn format field. - */ - if (!httpHeaderEntryParseInit(&e, field_start, field_end, mask)) - debug(55, 2) ("warning: ignoring unparseable http header field near '%s'\n", - getStringPrefix(field_start)); + e = httpHeaderEntryParseCreate(field_start, field_end); + if (e != NULL) + httpHeaderAddEntry(hdr, e); else - httpHeaderAddParsedEntry(hdr, &e); - /* - * Note that we init() "e", bit never clean() it which is equivalent to - * creating a fresh entry on each loop iteration; thus, it is safe to - * add e without dup()-ing it. - */ + debug(55, 2) ("warning: ignoring unparseable http header field near '%s'\n", + getStringPrefix(field_start, field_end)); field_start = field_end; /* skip CRLF */ if (*field_start == '\r') @@ -432,9 +342,8 @@ httpHeaderPackInto(const HttpHeader * hdr, Packer * p) assert(hdr && p); debug(55, 7) ("packing hdr: (%p)\n", hdr); /* pack all entries one by one */ - while ((e = httpHeaderGetEntry(hdr, &pos))) { + while ((e = httpHeaderGetEntry(hdr, &pos))) httpHeaderEntryPackInto(e, p); - } } /* returns next valid entry */ @@ -442,43 +351,36 @@ static HttpHeaderEntry * httpHeaderGetEntry(const HttpHeader * hdr, HttpHeaderPos * pos) { assert(hdr && pos); - assert(*pos >= HttpHeaderInitPos && *pos < hdr->capacity); - debug(55, 8) ("searching next e in hdr %p from %d\n", hdr, *pos); - for ((*pos)++; *pos < hdr->ucount; (*pos)++) { - HttpHeaderEntry *e = hdr->entries + *pos; - if (e->id >= 0) { - debug(55, 8) ("%p returning entry: %s at %d\n", - hdr, strBuf(e->name), *pos); - return e; - } + assert(*pos >= HttpHeaderInitPos && *pos < hdr->entries.count); + debug(55, 8) ("searching for next e in hdr %p from %d\n", hdr, *pos); + for ((*pos)++; *pos < hdr->entries.count; (*pos)++) { + if (hdr->entries.items[*pos]) + return hdr->entries.items[*pos]; } debug(55, 8) ("no more entries in hdr %p\n", hdr); return NULL; } /* - * returns a pointer to a specified entry and updates pos; - * note that we search from the very begining so it does not make much sense to - * ask for headers that maybe repeated. + * returns a pointer to a specified entry if any + * note that we return one entry so it does not make much sense to ask for + * "list" headers */ HttpHeaderEntry * -httpHeaderFindEntry(const HttpHeader * hdr, http_hdr_type id, HttpHeaderPos * pos) +httpHeaderFindEntry(const HttpHeader * hdr, http_hdr_type id) { - HttpHeaderPos p; + HttpHeaderPos pos = HttpHeaderInitPos; HttpHeaderEntry *e; assert(hdr); assert_eid(id); - assert(!EBIT_TEST(DupHeadersMask, id)); + assert(!CBIT_TEST(ListHeadersMask, id)); debug(55, 8) ("finding entry %d in hdr %p\n", id, hdr); /* check mask first */ - if (!EBIT_TEST(hdr->emask, id)) + if (!CBIT_TEST(hdr->mask, id)) return NULL; /* looks like we must have it, do linear search */ - if (!pos) - pos = &p; - *pos = HttpHeaderInitPos; - while ((e = httpHeaderGetEntry(hdr, pos))) { + while ((e = httpHeaderGetEntry(hdr, &pos))) { if (e->id == id) return e; } @@ -488,48 +390,57 @@ httpHeaderFindEntry(const HttpHeader * hdr, http_hdr_type id, HttpHeaderPos * po } /* - * deletes all field(s) with a given name if any, returns #fields deleted; - * used to process Connection: header and delete fields in "paranoid" setup + * deletes all fields with a given name if any, returns #fields deleted; */ int -httpHeaderDelFields(HttpHeader * hdr, const char *name) +httpHeaderDelByName(HttpHeader * hdr, const char *name) { int count = 0; - int mask = 0; HttpHeaderPos pos = HttpHeaderInitPos; HttpHeaderEntry *e; - + httpHeaderMaskInit(&hdr->mask); /* temporal inconsistency */ debug(55, 7) ("deleting '%s' fields in hdr %p\n", name, hdr); while ((e = httpHeaderGetEntry(hdr, &pos))) { if (!strCmp(e->name, name)) { - httpHeaderDelAt(hdr, pos, 0); + httpHeaderDelAt(hdr, pos); count++; } else - EBIT_SET(mask, e->id); + CBIT_SET(hdr->mask, e->id); } - hdr->emask = mask; return count; } +#if FUTURE_CODE +static int +httpHeaderDelById(HttpHeader * hdr, http_hdr_type id) +{ + int count = 0; + HttpHeaderPos pos = HttpHeaderInitPos; + HttpHeaderEntry *e; + debug(55, 8) ("%p del-by-id %d\n", hdr, id); + if (!CBIT_TEST(hdr->mask, id)) + return 0; + while ((e = httpHeaderGetEntry(hdr, &pos))) { + if (e->id == id) { + httpHeaderDelAt(hdr, pos); + count++; + } + } + CBIT_CLR(hdr->mask, id); + assert(count); + return count; +} +#endif + /* * deletes an entry at pos and leaves a gap; leaving a gap makes it * possible to iterate(search) and delete fields at the same time */ static void -httpHeaderDelAt(HttpHeader * hdr, HttpHeaderPos pos, int auto_sync) +httpHeaderDelAt(HttpHeader * hdr, HttpHeaderPos pos) { - HttpHeaderEntry *e; - assert(hdr); - assert(pos >= 0 && pos < hdr->ucount); - e = hdr->entries + pos; - debug(55, 7) ("%p deling entry at %d: id: %d (%p:%p)\n", - hdr, pos, e->id, hdr->entries, e); - /* sync masks */ - if (auto_sync) { - assert(!EBIT_TEST(DupHeadersMask, e->id)); - httpHeaderSyncMasks(hdr, e, 0); - } - httpHeaderEntryClean(e); + httpHeaderEntryDestroy(hdr->entries.items[pos]); + hdr->entries.items[pos] = NULL; } /* @@ -538,50 +449,40 @@ httpHeaderDelAt(HttpHeader * hdr, HttpHeaderPos pos, int auto_sync) * this function returns. */ static void -httpHeaderAddParsedEntry(HttpHeader * hdr, HttpHeaderEntry * e) +httpHeaderAddEntry(HttpHeader * hdr, HttpHeaderEntry * e) { - HttpHeaderEntry *olde; - assert(hdr); - assert(e); + assert(hdr && e); assert_eid(e->id); - debug(55, 7) ("%p adding parsed entry %d\n", hdr, e->id); - - if (EBIT_TEST(hdr->emask, e->id)) + debug(55, 7) ("%p adding entry: %d at %d\n", + hdr, e->id, hdr->entries.count); + if (CBIT_TEST(hdr->mask, e->id)) Headers[e->id].stat.repCount++; - olde = EBIT_TEST(DupHeadersMask, e->id) ? NULL : httpHeaderFindEntry(hdr, e->id, NULL); - if (olde) { - if (EBIT_TEST(ListHeadersMask, e->id)) - httpHeaderEntryJoinWith(olde, e); - else - debug(55, 3) ("ignoring duplicate header: %s\n", strBuf(e->name)); - httpHeaderEntryClean(e); - } else { - /* actual add */ - httpHeaderAddNewEntry(hdr, e); - debug(55, 6) ("%p done adding parsed entry %d (%s)\n", hdr, e->id, strBuf(e->name)); - } + else + CBIT_SET(hdr->mask, e->id); + arrayAppend(&hdr->entries, e); } -/* - * adds a new entry (low level append, does not check if entry is new) note: we - * copy e value, thus, e can point to a tmp variable (but e->field is not dupped!) - */ -static void -httpHeaderAddNewEntry(HttpHeader * hdr, const HttpHeaderEntry *e) +static String +httpHeaderJoinEntries(const HttpHeader *hdr, http_hdr_type id) { - assert(hdr && e); - debug(55, 8) ("%p adding entry: %d at %d, (%p:%p)\n", - hdr, e->id, hdr->ucount, - hdr->entries, hdr->entries + hdr->ucount); - if (hdr->ucount >= hdr->capacity) - httpHeaderGrow(hdr); - hdr->entries[hdr->ucount++] = *e; - /* sync masks */ - if (EBIT_TEST(DupHeadersMask, e->id)) - EBIT_SET(DupHeadersMask, e->id); - else - httpHeaderSyncMasks(hdr, e, 1); + String s = StringNull; + HttpHeaderEntry *e; + HttpHeaderPos pos = HttpHeaderInitPos; + debug(55, 6) ("%p: joining for id %d\n", hdr, id); + assert(CBIT_TEST(ListHeadersMask, id)); + while ((e = httpHeaderGetEntry(hdr, &pos))) { + if (e->id == id) { + if (strLen(s)) { + stringAppend(&s, ",", 1); + stringAppend(&s, strBuf(e->value), strLen(e->value)); + } else + s = stringDup(&e->value); + } + } + assert(strLen(s)); + debug(55, 6) ("%p: joined for id %d: %s\n", hdr, id, strBuf(s)); + return s; } @@ -593,118 +494,83 @@ httpHeaderHas(const HttpHeader * hdr, http_hdr_type id) assert_eid(id); assert(id != HDR_OTHER); debug(55, 7) ("%p lookup for %d\n", hdr, id); - return EBIT_TEST(hdr->emask, id); -} - -/* delete a field if any; see httpHeaderFindEntry for restrictions */ -static void -httpHeaderDelById(HttpHeader * hdr, http_hdr_type id) -{ - HttpHeaderPos pos = HttpHeaderInitPos; - debug(55, 8) ("%p del-by-id %d\n", hdr, id); - if (httpHeaderFindEntry(hdr, id, &pos)) - httpHeaderDelAt(hdr, pos, 1); -} - -/* - * set a field - * old content, if any, is destroyed. - */ -static void -httpHeaderSet(HttpHeader * hdr, HttpHeaderEntry *e) -{ - assert(hdr); - assert_eid(e->id); - - debug(55, 7) ("%p sets entry with id: %d\n", hdr, e->id); - httpHeaderDelById(hdr, e->id); /* delete old entry if any */ - httpHeaderAddNewEntry(hdr, e); + return CBIT_TEST(hdr->mask, id); } void -httpHeaderSetInt(HttpHeader * hdr, http_hdr_type id, int number) +httpHeaderPutInt(HttpHeader * hdr, http_hdr_type id, int number) { - HttpHeaderEntry e; assert_eid(id); - assert(Headers[id].type == ftInt); /* must be of an appropriatre type */ + assert(Headers[id].type == ftInt); /* must be of an appropriatre type */ assert(number >= 0); - httpHeaderEntryInit(&e, id, xitoa(number), intField(number)); - httpHeaderSet(hdr, &e); + httpHeaderAddEntry(hdr, httpHeaderEntryCreate(id, NULL, xitoa(number))); } void -httpHeaderSetTime(HttpHeader * hdr, http_hdr_type id, time_t time) +httpHeaderPutTime(HttpHeader * hdr, http_hdr_type id, time_t time) { - HttpHeaderEntry e; assert_eid(id); - assert(Headers[id].type == ftDate_1123); /* must be of an appropriatre type */ - if (time >= 0) { - httpHeaderEntryInit(&e, id, mkrfc1123(time), timeField(time)); - httpHeaderSet(hdr, &e); - } else - httpHeaderDelById(hdr, id); + assert(Headers[id].type == ftDate_1123); /* must be of an appropriatre type */ + assert(time >= 0); + httpHeaderAddEntry(hdr, httpHeaderEntryCreate(id, NULL, mkrfc1123(time))); } void -httpHeaderSetStr(HttpHeader * hdr, http_hdr_type id, const char *str) +httpHeaderPutStr(HttpHeader * hdr, http_hdr_type id, const char *str) { - HttpHeaderEntry e; assert_eid(id); - assert(Headers[id].type == ftStr); /* must be of a string type */ + assert(Headers[id].type == ftStr); /* must be of an appropriatre type */ assert(str); - httpHeaderEntryInit(&e, id, str, strField(StringNull)); - httpHeaderSet(hdr, &e); + httpHeaderAddEntry(hdr, httpHeaderEntryCreate(id, NULL, str)); } void -httpHeaderSetAuth(HttpHeader * hdr, const char *authScheme, const char *realm) +httpHeaderPutAuth(HttpHeader * hdr, const char *authScheme, const char *realm) { MemBuf mb; assert(hdr && authScheme && realm); memBufDefInit(&mb); memBufPrintf(&mb, "%s realm=\"%s\"", authScheme, realm); - httpHeaderSetStr(hdr, HDR_WWW_AUTHENTICATE, mb.buf); + httpHeaderPutStr(hdr, HDR_WWW_AUTHENTICATE, mb.buf); memBufClean(&mb); } /* add extension header (these fields are not parsed/analyzed/joined, etc.) */ void -httpHeaderAddExt(HttpHeader * hdr, const char *name, const char *value) +httpHeaderPutExt(HttpHeader * hdr, const char *name, const char *value) { - HttpHeaderEntry e; - assert(name && value); + assert(name && value); debug(55, 8) ("%p adds ext entry '%s: %s'\n", hdr, name, value); - httpHeaderEntryExtInit(&e, name, value); - httpHeaderAddNewEntry(hdr, &e); -} - -/* get a ["right"] cached value of a field, see httpHeaderFindEntry for restrictions */ -static field_store -httpHeaderGetCache(const HttpHeader * hdr, http_hdr_type id) -{ - HttpHeaderEntry *e; - assert_eid(id); - debug(55, 7) ("%p get for id %d\n", hdr, id); - if ((e = httpHeaderFindEntry(hdr, id, NULL))) - return e->cache; - else - return httpHeaderFieldBadValue(Headers[id].type); + httpHeaderAddEntry(hdr, httpHeaderEntryCreate(HDR_OTHER, name, value)); } int httpHeaderGetInt(const HttpHeader * hdr, http_hdr_type id) { + HttpHeaderEntry *e; + int value = -1; + int ok; assert_eid(id); assert(Headers[id].type == ftInt); /* must be of an appropriate type */ - return httpHeaderGetCache(hdr, id).v_int; + if ((e = httpHeaderFindEntry(hdr, id))) { + ok = httpHeaderParseInt(strBuf(e->value), &value); + httpHeaderNoteParsedEntry(e->id, e->value, !ok); + } + return value; } time_t httpHeaderGetTime(const HttpHeader * hdr, http_hdr_type id) { + HttpHeaderEntry *e; + time_t value = -1; assert_eid(id); assert(Headers[id].type == ftDate_1123); /* must be of an appropriate type */ - return httpHeaderGetCache(hdr, id).v_time; + if ((e = httpHeaderFindEntry(hdr, id))) { + value = parse_rfc1123(strBuf(e->value)); + httpHeaderNoteParsedEntry(e->id, e->value, value < 0); + } + return value; } const char * @@ -713,285 +579,154 @@ httpHeaderGetStr(const HttpHeader * hdr, http_hdr_type id) HttpHeaderEntry *e; assert_eid(id); assert(Headers[id].type == ftStr); /* must be of an appropriate type */ - if ((e = httpHeaderFindEntry(hdr, id, NULL))) - if (strBuf(e->cache.v_str)) - return strBuf(e->cache.v_str); - else /* use real value if no cached one */ - return strBuf(e->value); + if ((e = httpHeaderFindEntry(hdr, id))) { + httpHeaderNoteParsedEntry(e->id, e->value, 0); /* no errors are possible */ + return strBuf(e->value); + } return NULL; } HttpHdrCc * httpHeaderGetCc(const HttpHeader * hdr) { - return httpHeaderGetCache(hdr, HDR_CACHE_CONTROL).v_pcc; + HttpHdrCc *cc; + String s; + if (!CBIT_TEST(hdr->mask, HDR_CACHE_CONTROL)) + return NULL; + s = httpHeaderJoinEntries(hdr, HDR_CACHE_CONTROL); + cc = httpHdrCcParseCreate(strBuf(s)); + /* fix this for req headers @?@ */ + if (cc) + httpHdrCcUpdateStats(cc, &HttpHeaderStats[0].ccTypeDistr); + httpHeaderNoteParsedEntry(HDR_CACHE_CONTROL, s, !cc); + stringClean(&s); + return cc; } HttpHdrRange * httpHeaderGetRange(const HttpHeader * hdr) { - return httpHeaderGetCache(hdr, HDR_RANGE).v_prange; + HttpHdrRange *r; + String s; + if (!CBIT_TEST(hdr->mask, HDR_RANGE)) + return NULL; + s = httpHeaderJoinEntries(hdr, HDR_RANGE); + r = httpHdrRangeParseCreate(strBuf(s)); + httpHeaderNoteParsedEntry(HDR_RANGE, s, !r); + stringClean(&s); + return r; } HttpHdrContRange * httpHeaderGetContRange(const HttpHeader * hdr) { - return httpHeaderGetCache(hdr, HDR_CONTENT_RANGE).v_pcont_range; -} - -/* updates header masks */ -static void -httpHeaderSyncMasks(HttpHeader * hdr, const HttpHeaderEntry * e, int add) -{ - const int isSet = EBIT_TEST(hdr->emask, e->id) != 0; - add = add != 0; - assert(isSet ^ add); - add ? EBIT_SET(hdr->emask, e->id) : EBIT_CLR(hdr->emask, e->id); + HttpHeaderEntry *e; + HttpHdrContRange *cr = NULL; + if ((e = httpHeaderFindEntry(hdr, HDR_CONTENT_RANGE))) { + cr = httpHdrContRangeParseCreate(strBuf(e->value)); + httpHeaderNoteParsedEntry(e->id, e->value, !cr); + } + return cr; } -/* doubles the size of the fields index, starts with INIT_FIELDS_PER_HEADER */ -static void -httpHeaderGrow(HttpHeader * hdr) +#if FUTURE_CODE +HttpHdrConn * +httpHeaderGetConn(const HttpHeader * hdr) { - int new_cap; - int new_size; - assert(hdr); - new_cap = (hdr->capacity) ? 2 * hdr->capacity : INIT_FIELDS_PER_HEADER; - new_size = new_cap * sizeof(HttpHeaderEntry); - - debug(55, 9) ("%p grow (%p) %d->%d\n", hdr, hdr->entries, hdr->capacity, new_cap); - hdr->entries = hdr->entries ? - xrealloc(hdr->entries, new_size) : - xmalloc(new_size); - memset(hdr->entries + hdr->capacity, 0, (new_cap - hdr->capacity) * sizeof(HttpHeaderEntry)); - hdr->capacity = new_cap; - debug(55, 9) ("%p grew (%p)\n", hdr, hdr->entries); + HttpHdrConn *conn; + String s; + if (!CBIT_TEST(hdr->mask, HDR_CONNECTION)) + return NULL; + s = httpHeaderJoinEntries(hdr, HDR_CONNECTION); + conn = httpHdrConnParseCreate(s); + httpHeaderNoteParsedEntry(HDR_CONNECTION, s, !conn); + stringClean(&s); + return conn; } +#endif /* * HttpHeaderEntry */ -static void -httpHeaderEntryDoInit(HttpHeaderEntry * e, http_hdr_type id, const char *name, const char *value, field_store cache) +static HttpHeaderEntry * +httpHeaderEntryCreate(http_hdr_type id, const char *name, const char *value) { - assert(e); + HttpHeaderEntry *e; assert_eid(id); + e = memAllocate(MEM_HTTP_HDR_ENTRY); e->id = id; if (id != HDR_OTHER) e->name = Headers[id].name; else stringInit(&e->name, name); stringInit(&e->value, value); - e->cache = cache; Headers[id].stat.aliveCount++; + debug(55, 9) ("created entry %p: '%s: %s'\n", e, strBuf(e->name), strBuf(e->value)); + return e; } static void -httpHeaderEntryInit(HttpHeaderEntry * e, http_hdr_type id, const char *value, field_store cache) -{ - httpHeaderEntryDoInit(e, id, NULL, value, cache); -} - -static void -httpHeaderEntryExtInit(HttpHeaderEntry * e, const char *name, const char *value) -{ - httpHeaderEntryDoInit(e, HDR_OTHER, name, value, strField(StringNull)); -} - -static void -httpHeaderEntryClean(HttpHeaderEntry * e) +httpHeaderEntryDestroy(HttpHeaderEntry * e) { assert(e); assert_eid(e->id); - /* type-based cleanup */ - switch (Headers[e->id].type) { - case ftInvalid: - case ftInt: - case ftDate_1123: - case ftPExtField: - /* no special cleaning is necessary */ - break; - case ftStr: - stringClean(&e->cache.v_str); - break; - case ftPCc: - if (e->cache.v_pcc) - httpHdrCcDestroy(e->cache.v_pcc); - break; - case ftPRange: - if (e->cache.v_prange) - httpHdrRangeDestroy(e->cache.v_prange); - break; - case ftPContRange: - if (e->cache.v_pcont_range) - httpHdrContRangeDestroy(e->cache.v_pcont_range); - break; - default: - assert(0); /* somebody added a new type? */ - } + debug(55, 9) ("destroying entry %p: '%s: %s'\n", e, strBuf(e->name), strBuf(e->value)); /* clean name if needed */ if (e->id == HDR_OTHER) stringClean(&e->name); stringClean(&e->value); + assert(Headers[e->id].stat.aliveCount); Headers[e->id].stat.aliveCount--; - /* we have to do that so entry will be _invlaid_ */ - e->id = -1; - httpHeaderFieldInit(&e->cache); -} - -/* parses and inits header entry, returns true on success */ -static int -httpHeaderEntryParseInit(HttpHeaderEntry * e, const char *field_start, const char *field_end, int mask) -{ - HeaderEntryParsedCount++; - /* paranoid reset */ - memset(e, 0, sizeof(*e)); - e->id = -1; - if (!httpHeaderEntryParse(e, field_start, field_end)) - return 0; /* total parsing failure */ - e->id = httpHeaderIdByName(strBuf(e->name), -1, Headers, HDR_ENUM_END, mask); - debug(55, 8) ("EntryParseInit: '%s'.id = %d\n", strBuf(e->name), e->id); - if (e->id < 0) - e->id = HDR_OTHER; - Headers[e->id].stat.parsCount++; - Headers[e->id].stat.aliveCount++; - if (e->id != HDR_OTHER) { - /* get rid of name copy */ - stringClean(&e->name); - e->name = Headers[e->id].name; - /* we got something interesting, parse and cache the value */ - httpHeaderEntrySyncCache(e); - } - return 1; + memFree(MEM_HTTP_HDR_ENTRY, e); } -static int -httpHeaderEntryParse(HttpHeaderEntry * e, const char *field_start, const char *field_end) +/* parses and inits header entry, returns new entry on success */ +static HttpHeaderEntry * +httpHeaderEntryParseCreate(const char *field_start, const char *field_end) { + HttpHeaderEntry *e; + int id; /* note: name_start == field_start */ const char *name_end = strchr(field_start, ':'); - const char *value_start; + const int name_len = name_end ? name_end - field_start : 0; + const char *value_start = field_start + name_len + 1; /* skip ':' */ /* note: value_end == field_end */ - if (!name_end || name_end <= field_start || name_end > field_end) - return 0; + HeaderEntryParsedCount++; - value_start = name_end + 1; /* skip ':' */ - /* skip white space */ + /* do we have a valid field name within this field? */ + if (!name_len || name_end > field_end) + return NULL; + /* now we know we can parse it */ + e = memAllocate(MEM_HTTP_HDR_ENTRY); + debug(55, 9) ("creating entry %p: near '%s'\n", e, getStringPrefix(field_start, field_end)); + /* is it a "known" field? */ + id = httpHeaderIdByName(field_start, name_len, Headers, HDR_ENUM_END); + if (id < 0) + id = HDR_OTHER; + assert_eid(id); + e->id = id; + /* set field name */ + if (id == HDR_OTHER) + stringLimitInit(&e->name, field_start, name_len); + else + e->name = Headers[id].name; + /* trim field value */ while (value_start < field_end && isspace(*value_start)) value_start++; - - stringLimitInit(&e->name, field_start, name_end - field_start); + /* set field value */ stringLimitInit(&e->value, value_start, field_end - value_start); - return 1; -} - -/* tries to parse field value further and cache the result */ -static void -httpHeaderEntrySyncCache(HttpHeaderEntry * e) -{ - assert(e); - assert_eid(e->id); - debug(55, 9) ("httpHeaderEntrySyncCache: start with %s: %s\n", - strBuf(e->name), strBuf(e->value)); - httpHeaderFieldInit(&e->cache); - /* - * check for exceptions first (parsing is not determined by value type) - * then parse using value type if needed - */ - switch (e->id) { - case HDR_PROXY_KEEPALIVE: - /* we treat Proxy-Connection as "keep alive" only if it says so */ - e->cache = intField(!strcasecmp(strBuf(e->value), "Keep-Alive")); - break; - case HDR_CONTENT_TYPE: - /* strip content type params */ - stringLimitInit(&e->cache.v_str, strBuf(e->value), - strcspn(strBuf(e->value), ";\t ")); - break; - default: - /* if we got here, it is something that can be parsed based on value type */ - httpHeaderEntrySyncCacheByType(e); - } - /* post-processing */ - switch (e->id) { - case HDR_EXPIRES: - /* - * The HTTP/1.0 specs says that robust implementations should - * consider bad or malformed Expires header as equivalent to - * "expires immediately." - */ - if (e->cache.v_time <= 0) - e->cache.v_time = squid_curtime; - /* - * real expiration value also depends on max-age too, - * HttpReply should handle that - */ - break; - } -} - -static void -httpHeaderEntrySyncCacheByType(HttpHeaderEntry * e) -{ - const char *err_entry_descr = NULL; - const field_type type = Headers[e->id].type; - - debug(55, 8) ("httpHeaderEntrySyncCacheByType: id: %d type: %d\n", e->id, type); - switch (type) { - case ftInt: - if (!httpHeaderParseInt(strBuf(e->value), &e->cache.v_int)) - err_entry_descr = "integer field"; - break; - case ftStr: - /* we do not cache string values to avoid duplicating e->value */ - break; - case ftDate_1123: - e->cache.v_time = parse_rfc1123(strBuf(e->value)); - if (e->cache.v_time <= 0) - err_entry_descr = "date field"; - break; - case ftPCc: - e->cache.v_pcc = httpHdrCcParseCreate(strBuf(e->value)); - if (!e->cache.v_pcc) - err_entry_descr = "cache control hdr"; - break; - case ftPRange: - e->cache.v_prange = httpHdrRangeParseCreate(strBuf(e->value)); - if (!e->cache.v_prange) - err_entry_descr = "range hdr"; - break; - case ftPContRange: - e->cache.v_pcont_range = httpHdrContRangeParseCreate(strBuf(e->value)); - if (!e->cache.v_pcont_range) - err_entry_descr = "content range hdr"; - break; - default: - debug(55, 2) ("something went wrong with hdr field type analysis: id: %d, type: %d, field: '%s: %s'\n", - e->id, type, strBuf(e->name), strBuf(e->value)); - assert(0); - } - /* notify of failure if any */ - if (err_entry_descr) { - debug(55, 2) ("failed to parse %s: id: %d, field: '%s: %s'\n", - err_entry_descr, e->id, strBuf(e->name), strBuf(e->value)); - Headers[e->id].stat.errCount++; - } + Headers[id].stat.seenCount++; + Headers[id].stat.aliveCount++; + debug(55, 9) ("created entry %p: '%s: %s'\n", e, strBuf(e->name), strBuf(e->value)); + return e; } -static HttpHeaderEntry +static HttpHeaderEntry * httpHeaderEntryClone(const HttpHeaderEntry * e) { - HttpHeaderEntry clone; - assert(e); - assert_eid(e->id); - if (e->id == HDR_OTHER) - httpHeaderEntryExtInit(&clone, strBuf(e->name), strBuf(e->value)); - else - httpHeaderEntryInit(&clone, e->id, strBuf(e->value), - httpHeaderFieldDup(Headers[e->id].type, e->cache)); - return clone; + return httpHeaderEntryCreate(e->id, strBuf(e->name), strBuf(e->value)); } void @@ -1005,116 +740,14 @@ httpHeaderEntryPackInto(const HttpHeaderEntry * e, Packer * p) } static void -httpHeaderEntryJoinWith(HttpHeaderEntry * e, const HttpHeaderEntry * newe) -{ - field_type type; - assert(e && newe); - assert_eid(e->id); - assert(e->id == newe->id); - - debug(55, 6) ("joining entry (%p) with (%p)\n", e, newe); - /* append value */ - stringAppend(&e->value, ",", 1); - stringAppend(&e->value, strBuf(newe->value), strLen(newe->value)); - /* type-based join */ - type = Headers[e->id].type; - switch (type) { - case ftStr: - assert(!strBuf(e->cache.v_str)); /* currently others should not be join-able */ - break; - case ftPCc: - httpHdrCcJoinWith(e->cache.v_pcc, newe->cache.v_pcc); - break; - default: - debug(55, 0) ("join for invalid/unknown type: id: %d, type: %d\n", e->id, type); - assert(0); - } -} - - -#if OLD_CODE -static int -httpHeaderFieldIsValid(field_type type, const HttpHeaderEntry * e) -{ - /* type-based analysis */ - switch (type) { - case ftInvalid: - return 0; - case ftInt: - return e->cache.v_int >= 0; - case ftStr: - return strBuf(e->cache.v_str) != NULL; - case ftDate_1123: - return e->cache.v_time >= 0; - case ftPCc: - return e->cache.v_pcc != NULL; - case ftPRange: - return e->cache.v_prange != NULL; - case ftPContRange: - return e->cache.v_pcont_range != NULL; - default: - assert(0); /* query for invalid/unknown type */ - } - return 0; /* not reached */ -} -#endif - -/* - * HttpHeaderField - */ - -static void -httpHeaderFieldInit(field_store * field) -{ - assert(field); - memset(field, 0, sizeof(field_store)); -} - -static field_store -httpHeaderFieldDup(field_type type, field_store value) -{ - /* type based duplication */ - switch (type) { - case ftInt: - case ftDate_1123: - return value; - case ftStr: - return strField(stringDup(&value.v_str)); - case ftPCc: - return ptrField(httpHdrCcDup(value.v_pcc)); - case ftPRange: - return ptrField(httpHdrRangeDup(value.v_prange)); - case ftPContRange: - return ptrField(httpHdrContRangeDup(value.v_pcont_range)); - default: - assert(0); /* dup of invalid/unknown type */ - } - return ptrField(NULL); /* not reached */ -} - -/* - * bad value table; currently bad values are determined by field type, but this - * can be changed in the future to reflect dependence on entry id if any - */ -static field_store -httpHeaderFieldBadValue(field_type type) +httpHeaderNoteParsedEntry(http_hdr_type id, String context, int error) { - switch (type) { - case ftInt: - return intField(-1); - case ftDate_1123: - return timeField(-1); - case ftStr: - return strField(StringNull); - case ftPCc: - case ftPRange: - case ftPContRange: - return ptrField(NULL); - case ftInvalid: - default: - assert(0); /* query for invalid/unknown type */ + Headers[id].stat.parsCount++; + if (error) { + Headers[id].stat.errCount++; + debug(55,2) ("cannot parse hdr field: '%s: %s'\n", + strBuf(Headers[id].name), strBuf(context)); } - return ptrField(NULL); /* not reached */ } /* @@ -1156,8 +789,7 @@ httpHeaderStatDump(const HttpHeaderStat * hs, StoreEntry * e) storeAppendPrintf(e, "%2s\t %-20s\t %5s\t %6s\n", "id", "name", "count", "#/cc_field"); statHistDump(&hs->ccTypeDistr, e, httpHdrCcStatDumper); - storeAppendPrintf(e, "

Number of fields per header distribution (init size: %d)

\n", - INIT_FIELDS_PER_HEADER); + storeAppendPrintf(e, "

Number of fields per header distribution

\n"); storeAppendPrintf(e, "%2s\t %-5s\t %5s\t %6s\n", "id", "#flds", "count", "%total"); statHistDump(&hs->hdrUCountDistr, e, httpHeaderFldsPerHdrDumper); @@ -1185,7 +817,7 @@ httpHeaderStoreReport(StoreEntry * e) storeAppendPrintf(e, "%2d\t %-20s\t %5d\t %6.3f\t %6.3f\n", f->id, strBuf(f->name), f->stat.aliveCount, xpercent(f->stat.errCount, f->stat.parsCount), - xpercent(f->stat.repCount, f->stat.parsCount)); + xpercent(f->stat.repCount, f->stat.seenCount)); } storeAppendPrintf(e, "Headers Parsed: %d\n", HeaderParsedCount); storeAppendPrintf(e, "Hdr Fields Parsed: %d\n", HeaderEntryParsedCount); diff --git a/src/HttpHeaderTools.cc b/src/HttpHeaderTools.cc index 8fea8ce578..ed56a5d590 100644 --- a/src/HttpHeaderTools.cc +++ b/src/HttpHeaderTools.cc @@ -1,5 +1,5 @@ /* - * $Id: HttpHeaderTools.cc,v 1.5 1998/03/15 04:25:28 rousskov Exp $ + * $Id: HttpHeaderTools.cc,v 1.6 1998/03/20 18:06:39 rousskov Exp $ * * DEBUG: section 66 HTTP Header Tools * AUTHOR: Alex Rousskov @@ -70,36 +70,38 @@ httpHeaderDestroyFieldsInfo(HttpHeaderFieldInfo *table, int count) xfree(table); } +void +httpHeaderMaskInit(HttpHeaderMask *mask) +{ + memset(mask, 0, sizeof(*mask)); +} + /* calculates a bit mask of a given array */ -int -httpHeaderCalcMask(const int *enums, int count) +void +httpHeaderCalcMask(HttpHeaderMask *mask, const int *enums, int count) { int i; - int mask = 0; - assert(enums); + assert(mask && enums); assert(count < sizeof(int) * 8); /* check for overflow */ + httpHeaderMaskInit(mask); for (i = 0; i < count; ++i) { - assert(enums[i] < sizeof(int) * 8); /* check for overflow again */ - assert(!EBIT_TEST(mask, enums[i])); /* check for duplicates */ - EBIT_SET(mask, enums[i]); + assert(!CBIT_TEST(*mask, enums[i])); /* check for duplicates */ + CBIT_SET(*mask, enums[i]); } - return mask; } int -httpHeaderIdByName(const char *name, int name_len, const HttpHeaderFieldInfo *info, int end, int mask) +httpHeaderIdByName(const char *name, int name_len, const HttpHeaderFieldInfo *info, int end) { int i; for (i = 0; i < end; ++i) { - if (mask < 0 || EBIT_TEST(mask, i)) { - if (name_len >= 0 && name_len != strLen(info[i].name)) - continue; - if (!strncasecmp(name, strBuf(info[i].name), - name_len < 0 ? strLen(info[i].name) + 1 : name_len)) + if (name_len >= 0 && name_len != strLen(info[i].name)) + continue; + if (!strncasecmp(name, strBuf(info[i].name), + name_len < 0 ? strLen(info[i].name) + 1 : name_len)) return i; - } } return -1; } @@ -143,11 +145,12 @@ strListGetItem(const char *str, char del, const char **item, int *ilen, const ch /* handy to printf prefixes of potentially very long buffers */ const char * -getStringPrefix(const char *str) +getStringPrefix(const char *str, const char *end) { -#define SHORT_PREFIX_SIZE 256 +#define SHORT_PREFIX_SIZE 512 LOCAL_ARRAY(char, buf, SHORT_PREFIX_SIZE); - xstrncpy(buf, str, SHORT_PREFIX_SIZE); + const int sz = 1 + (end ? end-str : strlen(str)); + xstrncpy(buf, str, (sz > SHORT_PREFIX_SIZE) ? SHORT_PREFIX_SIZE : sz); return buf; } @@ -193,9 +196,9 @@ void httpHeaderTestParser(const char *hstr) MemBuf mb; assert(hstr); /* disabled for now */ - return; + /* return; */ /* do not print too much, kludge */ - if (bug_count > 50 && (lrand48() % bug_count) > 25L) + if (bug_count > 25 && (lrand48() % bug_count) > 3L) return; /* skip start line if any */ if (!strncasecmp(hstr, "HTTP/", 5)) { @@ -221,7 +224,7 @@ void httpHeaderTestParser(const char *hstr) parse_success = httpHeaderParse(&hdr, hstr, hstr+hstr_len); /* debugLevels[55] = 2; */ if (!parse_success) { - debug(66, 2) ("TEST: failed to parsed a header: {\n%s}\n", hstr); + debug(66, 2) ("TEST (%d): failed to parsed a header: {\n%s}\n", bug_count, hstr); return; } /* we think that we parsed it, veryfy */ @@ -230,8 +233,8 @@ void httpHeaderTestParser(const char *hstr) httpHeaderPackInto(&hdr, &p); if ((pos = abs(httpHeaderStrCmp(hstr, mb.buf, hstr_len)))) { bug_count++; - debug(66, 2) ("TEST: hdr parsing bug (pos: %d near '%s'): expected: {\n%s} got: {\n%s}\n", - pos, hstr+pos, hstr, mb.buf); + debug(66, 2) ("TEST (%d): hdr parsing bug (pos: %d near '%s'): expected: {\n%s} got: {\n%s}\n", + bug_count, pos, hstr+pos, hstr, mb.buf); } httpHeaderClean(&hdr); packerClean(&p); diff --git a/src/HttpReply.cc b/src/HttpReply.cc index 585ad09749..a10bd7ee05 100644 --- a/src/HttpReply.cc +++ b/src/HttpReply.cc @@ -1,6 +1,6 @@ /* - * $Id: HttpReply.cc,v 1.12 1998/03/11 22:18:46 rousskov Exp $ + * $Id: HttpReply.cc,v 1.13 1998/03/20 18:06:39 rousskov Exp $ * * DEBUG: section 58 HTTP Reply (Response) * AUTHOR: Alex Rousskov @@ -29,9 +29,6 @@ * */ -/* tmp hack, delete it @?@ */ -#define Const - #include "squid.h" @@ -39,6 +36,8 @@ /* local routines */ static void httpReplyDoDestroy(HttpReply * rep); +static void httpReplyHdrCacheInit(HttpReply * rep); +static void httpReplyHdrCacheClean(HttpReply * rep); static int httpReplyParseStep(HttpReply * rep, const char *parse_start, int atEnd); static int httpReplyParseError(HttpReply * rep); static int httpReplyIsolateStart(const char **parse_start, const char **blk_start, const char **blk_end); @@ -48,7 +47,7 @@ static int httpReplyIsolateHeaders(const char **parse_start, const char **blk_st HttpReply * httpReplyCreate() { - HttpReply *rep = memAllocate(MEM_HTTPREPLY); + HttpReply *rep = memAllocate(MEM_HTTP_REPLY); debug(58, 7) ("creating rep: %p\n", rep); httpReplyInit(rep); return rep; @@ -61,7 +60,8 @@ httpReplyInit(HttpReply * rep) rep->hdr_sz = 0; rep->pstate = psReadyToParseStartLine; httpBodyInit(&rep->body); - httpHeaderInit(&rep->hdr); + httpHeaderInit(&rep->header); + httpReplyHdrCacheInit(rep); httpStatusLineInit(&rep->sline); } @@ -70,7 +70,8 @@ httpReplyClean(HttpReply * rep) { assert(rep); httpBodyClean(&rep->body); - httpHeaderClean(&rep->hdr); + httpReplyHdrCacheClean(rep); + httpHeaderClean(&rep->header); httpStatusLineClean(&rep->sline); } @@ -126,7 +127,7 @@ httpReplyPackInto(const HttpReply * rep, Packer * p) { assert(rep); httpStatusLinePackInto(&rep->sline, p); - httpHeaderPackInto(&rep->hdr, p); + httpHeaderPackInto(&rep->header, p); packerAppend(p, "\r\n", 2); httpBodyPackInto(&rep->body, p); } @@ -184,7 +185,7 @@ httpPacked304Reply(const HttpReply * rep) packerToMemInit(&p, &mb); memBufPrintf(&mb, "%s", "HTTP/1.0 304 Not Modified\r\n"); for (t = 0; ImsEntries[t] != HDR_OTHER; ++t) - if ((e = httpHeaderFindEntry(&rep->hdr, ImsEntries[t], NULL))) + if ((e = httpHeaderFindEntry(&rep->header, ImsEntries[t]))) httpHeaderEntryPackInto(e, &p); memBufAppend(&mb, "\r\n", 2); packerClean(&p); @@ -198,42 +199,31 @@ httpReplySetHeaders(HttpReply * reply, double ver, http_status status, const cha HttpHeader *hdr; assert(reply); httpStatusLineSet(&reply->sline, ver, status, reason); - hdr = &reply->hdr; - httpHeaderAddExt(hdr, "Server", full_appname_string); - httpHeaderAddExt(hdr, "MIME-Version", "1.0"); /* do we need this? @?@ */ - httpHeaderSetTime(hdr, HDR_DATE, squid_curtime); - if (ctype) - httpHeaderSetStr(hdr, HDR_CONTENT_TYPE, ctype); + hdr = &reply->header; + httpHeaderPutStr(hdr, HDR_SERVER, full_appname_string); + httpHeaderPutStr(hdr, HDR_MIME_VERSION, "1.0"); + httpHeaderPutTime(hdr, HDR_DATE, squid_curtime); + if (ctype) { + httpHeaderPutStr(hdr, HDR_CONTENT_TYPE, ctype); + stringInit(&reply->content_type, ctype); + } else + reply->content_type = StringNull; if (clen >= 0) - httpHeaderSetInt(hdr, HDR_CONTENT_LENGTH, clen); + httpHeaderPutInt(hdr, HDR_CONTENT_LENGTH, clen); if (expires >= 0) - httpHeaderSetTime(hdr, HDR_EXPIRES, expires); + httpHeaderPutTime(hdr, HDR_EXPIRES, expires); if (lmt > 0) /* this used to be lmt != 0 @?@ */ - httpHeaderSetTime(hdr, HDR_LAST_MODIFIED, lmt); + httpHeaderPutTime(hdr, HDR_LAST_MODIFIED, lmt); + reply->date = squid_curtime; + reply->content_length = clen; + reply->expires = expires; + reply->last_modified = lmt; } -/* - * header manipulation - * - * never go to header directly if you can use these: - * - * our interpretation of headers often changes and you may get into trouble - * if you, for example, assume that HDR_EXPIRES contains expire info - * - * if you think about it, in most cases, you are not looking for the information - * in the header, but rather for current state of the reply, which may or may - * not depend on headers. - * - * For example, the _real_ question is - * "when does this object expire?" - * not - * "what is the value of the 'Expires:' header?" - */ - void httpReplyUpdateOnNotModified(HttpReply * rep, HttpReply * freshRep) { -#if 0 /* this is what we want: */ +#if OLD_CODE rep->cache_control = freshRep->cache_control; rep->misc_headers = freshRep->misc_headers; if (freshRep->date > -1) @@ -243,78 +233,66 @@ httpReplyUpdateOnNotModified(HttpReply * rep, HttpReply * freshRep) if (freshRep->expires > -1) rep->expires = freshRep->expires; #endif - time_t date; - time_t expires; - time_t lmt; assert(rep && freshRep); - /* save precious info */ - date = httpHeaderGetTime(&rep->hdr, HDR_DATE); - expires = httpReplyExpires(rep); - lmt = httpHeaderGetTime(&rep->hdr, HDR_LAST_MODIFIED); - /* clean old headers */ - httpHeaderClean(&rep->hdr); - httpHeaderInit(&rep->hdr); - /* copy */ - httpHeaderCopy(&rep->hdr, &freshRep->hdr); - /* restore missing info if needed */ - if (!httpHeaderHas(&rep->hdr, HDR_DATE)) - httpHeaderSetTime(&rep->hdr, HDR_DATE, date); - if (!httpHeaderHas(&rep->hdr, HDR_EXPIRES)) - httpHeaderSetTime(&rep->hdr, HDR_EXPIRES, expires); - if (!httpHeaderHas(&rep->hdr, HDR_LAST_MODIFIED)) - httpHeaderSetTime(&rep->hdr, HDR_LAST_MODIFIED, lmt); + /* clean cache */ + httpReplyHdrCacheClean(rep); + /* update raw headers */ + httpHeaderUpdate(&rep->header, &freshRep->header); + /* init cache */ + httpReplyHdrCacheInit(rep); } -int -httpReplyContentLen(const HttpReply * rep) -{ - assert(rep); - return httpHeaderGetInt(&rep->hdr, HDR_CONTENT_LENGTH); -} -/* should we return "" or NULL if no content-type? Return NULL for now @?@ */ -const char * -httpReplyContentType(const HttpReply * rep) -{ - assert(rep); - return httpHeaderGetStr(&rep->hdr, HDR_CONTENT_TYPE); -} +/* internal routines */ -time_t -httpReplyExpires(const HttpReply * rep) +/* internal function used by Destroy and Absorb */ +static void +httpReplyDoDestroy(HttpReply * rep) { - HttpHdrCc *cc; - time_t exp = -1; - assert(rep); - /* The max-age directive takes priority over Expires, check it first */ - cc = httpHeaderGetCc(&rep->hdr); - if (cc) - exp = cc->max_age; - if (exp < 0) - exp = httpHeaderGetTime(&rep->hdr, HDR_EXPIRES); - return exp; + memFree(MEM_HTTP_REPLY, rep); } -int -httpReplyHasCc(const HttpReply * rep, http_hdr_cc_type type) +/* sync this routine when you update HttpReply struct */ +static void +httpReplyHdrCacheInit(HttpReply * rep) { - HttpHdrCc *cc; - assert(rep); - assert(type >= 0 && type < CC_ENUM_END); - - cc = httpHeaderGetCc(&rep->hdr); - return cc && /* scc header is present */ - EBIT_TEST(cc->mask, type); + const HttpHeader *hdr = &rep->header; + const char *str; + rep->content_length = httpHeaderGetInt(hdr, HDR_CONTENT_LENGTH); + rep->date = httpHeaderGetTime(hdr, HDR_DATE); + rep->last_modified = httpHeaderGetTime(hdr, HDR_LAST_MODIFIED); + rep->expires = httpHeaderGetTime(hdr, HDR_EXPIRES); + str = httpHeaderGetStr(hdr, HDR_CONTENT_TYPE); + if (str) + stringLimitInit(&rep->content_type, str, strcspn(str, ";\t ")); + else + rep->content_type = StringNull; + rep->cache_control = httpHeaderGetCc(hdr); + rep->content_range = httpHeaderGetContRange(hdr); + str = httpHeaderGetStr(hdr, HDR_PROXY_CONNECTION); + rep->pconn_keep_alive = str && strcasecmp(str, "Keep-Alive"); + /* final adjustments */ + /* The max-age directive takes priority over Expires, check it first */ + if (rep->cache_control && rep->cache_control->max_age >= 0) + rep->expires = squid_curtime + rep->cache_control->max_age; + else + /* + * The HTTP/1.0 specs says that robust implementations should consider bad + * or malformed Expires header as equivalent to "expires immediately." + */ + if (rep->expires < 0 && httpHeaderHas(hdr, HDR_EXPIRES)) + rep->expires = squid_curtime; } - -/* internal routines */ - -/* internal function used by Destroy and Absorb */ +/* sync this routine when you update HttpReply struct */ static void -httpReplyDoDestroy(HttpReply * rep) +httpReplyHdrCacheClean(HttpReply * rep) { - memFree(MEM_HTTPREPLY, rep); + stringClean(&rep->content_type); + if (rep->cache_control) + httpHdrCcDestroy(rep->cache_control); + if (rep->content_range) + httpHdrContRangeDestroy(rep->content_range); } /* @@ -351,9 +329,11 @@ httpReplyParseStep(HttpReply * rep, const char *buf, int atEnd) blk_start = parse_start, blk_end = blk_start + strlen(blk_start); else return 0; - if (!httpHeaderParse(&rep->hdr, blk_start, blk_end)) + if (!httpHeaderParse(&rep->header, blk_start, blk_end)) return httpReplyParseError(rep); + httpReplyHdrCacheInit(rep); + *parse_end_ptr = parse_start; rep->hdr_sz = *parse_end_ptr - buf; rep->pstate++; diff --git a/src/Makefile.in b/src/Makefile.in index 6b82491478..95a8ca7234 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,7 +1,7 @@ # # Makefile for the Squid Object Cache server # -# $Id: Makefile.in,v 1.133 1998/03/20 05:51:04 wessels Exp $ +# $Id: Makefile.in,v 1.134 1998/03/20 18:06:40 rousskov Exp $ # # Uncomment and customize the following to suit your needs: # @@ -90,7 +90,6 @@ OBJS = \ http.o \ http-anon.o \ HttpStatusLine.o \ - HttpHdrExtField.o \ HttpHdrCc.o \ HttpHdrRange.o \ HttpHdrContRange.o \ diff --git a/src/cache_manager.cc b/src/cache_manager.cc index 140be685c5..424af6a94b 100644 --- a/src/cache_manager.cc +++ b/src/cache_manager.cc @@ -1,6 +1,6 @@ /* - * $Id: cache_manager.cc,v 1.9 1998/03/16 23:50:04 wessels Exp $ + * $Id: cache_manager.cc,v 1.10 1998/03/20 18:06:41 rousskov Exp $ * * DEBUG: section 16 Cache Manager Objects * AUTHOR: Duane Wessels @@ -224,7 +224,7 @@ cachemgrStart(int fd, request_t * request, StoreEntry * entry) * add Authenticate header, use 'action' as a realm because * password depends on action */ - httpHeaderSetAuth(&rep->hdr, "Basic", mgr->action); + httpHeaderPutAuth(&rep->header, "Basic", mgr->action); /* move info to the mem_obj->reply */ httpReplyAbsorb(entry->mem_obj->reply, rep); /* store the reply */ diff --git a/src/defines.h b/src/defines.h index 02ca2430a5..f3c95c9f4e 100644 --- a/src/defines.h +++ b/src/defines.h @@ -134,9 +134,16 @@ #define SM_PAGE_SIZE 4096 #define DISK_PAGE_SIZE 8192 -#define EBIT_SET(flag, bit) ((void)((flag) |= ((1<>3] +#define CBIT_SET(mask, bit) ((void)(CBIT_BIN(mask, bit) |= CBIT_BIT(bit))) +#define CBIT_CLR(mask, bit) ((void)(CBIT_BIN(mask, bit) &= ~CBIT_BIT(bit))) +#define CBIT_TEST(mask, bit) (CBIT_BIN(mask, bit) & CBIT_BIT(bit)) #define MAX_FILES_PER_DIR (1<<20) diff --git a/src/enums.h b/src/enums.h index f052a84bf9..d4418d7933 100644 --- a/src/enums.h +++ b/src/enums.h @@ -46,9 +46,10 @@ typedef enum { ERR_CACHE_ACCESS_DENIED, ERR_CACHE_MGR_ACCESS_DENIED, ERR_SQUID_SIGNATURE, /* not really an error */ - ERR_FTP_PUT_CREATED, /* !error,a note that the file was created */ + ERR_FTP_PUT_CREATED, /* !error,a note that the file was created */ ERR_FTP_PUT_MODIFIED, /* modified, !created */ ERR_FTP_PUT_ERROR, + ERR_ONLY_IF_CACHED_MISS, /* failure to satisfy only-if-cached request */ ERR_MAX } err_type; @@ -170,6 +171,9 @@ typedef enum { /* recognized or "known" header fields; @?@ add more! */ typedef enum { HDR_ACCEPT, + HDR_ACCEPT_CHARSET, + HDR_ACCEPT_ENCODING, + HDR_ACCEPT_LANGUAGE, HDR_ACCEPT_RANGES, HDR_AGE, HDR_CACHE_CONTROL, @@ -187,6 +191,7 @@ typedef enum { HDR_LAST_MODIFIED, HDR_LOCATION, HDR_MAX_FORWARDS, + HDR_MIME_VERSION, HDR_PROXY_AUTHENTICATE, HDR_PUBLIC, HDR_RANGE, @@ -197,7 +202,7 @@ typedef enum { HDR_WARNING, HDR_WWW_AUTHENTICATE, HDR_X_CACHE, - HDR_PROXY_KEEPALIVE, + HDR_PROXY_CONNECTION, HDR_OTHER, HDR_ENUM_END } http_hdr_type; @@ -212,6 +217,8 @@ typedef enum { CC_MUST_REVALIDATE, CC_PROXY_REVALIDATE, CC_MAX_AGE, + CC_ONLY_IF_CACHED, + CC_OTHER, CC_ENUM_END } http_hdr_cc_type; @@ -224,7 +231,6 @@ typedef enum { ftPCc, ftPRange, ftPContRange, - ftPExtField } field_type; typedef enum { @@ -479,7 +485,8 @@ typedef enum { MEM_FQDNCACHE_PENDING, MEM_HASH_LINK, MEM_HASH_TABLE, - MEM_HTTPREPLY, + MEM_HTTP_REPLY, + MEM_HTTP_HDR_ENTRY, MEM_HTTP_HDR_CC, MEM_HTTP_HDR_RANGE_SPEC, MEM_HTTP_HDR_RANGE, diff --git a/src/ftp.cc b/src/ftp.cc index 268ae31d8f..b7d6047203 100644 --- a/src/ftp.cc +++ b/src/ftp.cc @@ -1,6 +1,6 @@ /* - * $Id: ftp.cc,v 1.208 1998/03/16 21:59:58 wessels Exp $ + * $Id: ftp.cc,v 1.209 1998/03/20 18:06:43 rousskov Exp $ * * DEBUG: section 9 File Transfer Protocol (FTP) * AUTHOR: Harvest Derived @@ -2095,7 +2095,7 @@ ftpAppendSuccessHeader(FtpStateData * ftpState) mime_type, ftpState->size, ftpState->mdtm, -2); /* additional info */ if (mime_enc) - httpHeaderSetStr(&reply->hdr, HDR_CONTENT_ENCODING, mime_enc); + httpHeaderPutStr(&reply->header, HDR_CONTENT_ENCODING, mime_enc); httpReplySwapOut(reply, e); storeBufferFlush(e); reply->hdr_sz = e->mem_obj->inmem_hi; @@ -2124,7 +2124,7 @@ ftpAuthRequired(HttpReply * old_reply, request_t * request, const char *realm) rep = errorBuildReply(err); errorStateFree(err); /* add Authenticate header */ - httpHeaderSetAuth(&rep->hdr, "Basic", realm); + httpHeaderPutAuth(&rep->header, "Basic", realm); /* move new reply to the old one */ httpReplyAbsorb(old_reply, rep); } diff --git a/src/http.cc b/src/http.cc index e4fe0bc0a1..58341b4b03 100644 --- a/src/http.cc +++ b/src/http.cc @@ -1,6 +1,6 @@ /* - * $Id: http.cc,v 1.256 1998/03/17 04:00:13 wessels Exp $ + * $Id: http.cc,v 1.257 1998/03/20 18:06:44 rousskov Exp $ * * DEBUG: section 11 Hypertext Transfer Protocol (HTTP) * AUTHOR: Harvest Derived @@ -219,9 +219,9 @@ httpCacheNegatively(StoreEntry * entry) static int httpCachableReply(HttpStateData * httpState) { - HttpHeader *hdr = &httpState->entry->mem_obj->reply->hdr; - const HttpHdrCc *cc = httpHeaderGetCc(hdr); - const int cc_mask = (cc) ? cc->mask : 0; + HttpReply *rep = httpState->entry->mem_obj->reply; + HttpHeader *hdr = &rep->header; + const int cc_mask = (rep->cache_control) ? rep->cache_control->mask : 0; if (EBIT_TEST(cc_mask, CC_PRIVATE)) return 0; if (EBIT_TEST(cc_mask, CC_NO_CACHE)) @@ -247,13 +247,14 @@ httpCachableReply(HttpStateData * httpState) case 410: /* Gone */ /* don't cache objects from peers w/o LMT, Date, or Expires */ /* check that is it enough to check headers @?@ */ - if (httpHeaderHas(hdr, HDR_DATE)) + if (rep->date > -1) return 1; - else if (httpHeaderHas(hdr, HDR_LAST_MODIFIED)) + else if (rep->last_modified > -1) return 1; else if (!httpState->peer) return 1; - else if (httpHeaderHas(hdr, HDR_EXPIRES)) + /* @?@ (here and 302): invalid expires header compiles to squid_curtime */ + else if (rep->expires > -1) return 1; else return 0; @@ -261,7 +262,7 @@ httpCachableReply(HttpStateData * httpState) break; /* Responses that only are cacheable if the server says so */ case 302: /* Moved temporarily */ - if (httpHeaderHas(hdr, HDR_EXPIRES)) + if (rep->expires > -1) return 1; else return 0; @@ -357,12 +358,12 @@ httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size) assert(0); break; } - if (httpReplyHasCc(reply, CC_PROXY_REVALIDATE)) + if (reply->cache_control && EBIT_TEST(reply->cache_control->mask, CC_PROXY_REVALIDATE)) EBIT_SET(entry->flag, ENTRY_REVALIDATE); if (EBIT_TEST(httpState->flags, HTTP_KEEPALIVE)) if (httpState->peer) httpState->peer->stats.n_keepalives_sent++; - if (httpHeaderHas(&reply->hdr, HDR_PROXY_KEEPALIVE)) + if (reply->pconn_keep_alive) if (httpState->peer) httpState->peer->stats.n_keepalives_recv++; ctx_exit(ctx); @@ -383,7 +384,7 @@ httpPconnTransferDone(HttpStateData * httpState) if (!EBIT_TEST(httpState->flags, HTTP_KEEPALIVE)) return 0; debug(11, 5) ("httpPconnTransferDone: content_length=%d\n", - httpReplyContentLen(reply)); + reply->content_length); /* * Deal with gross HTTP stuff * - If we haven't seen the end of the reply headers, we can't @@ -412,9 +413,9 @@ httpPconnTransferDone(HttpStateData * httpState) * persistent. If there is a content length, then we must * wait until we've seen the end of the body. */ - if (httpReplyContentLen(reply) < 0) + if (reply->content_length < 0) return 0; - else if (mem->inmem_hi < httpReplyContentLen(reply) + reply->hdr_sz) + else if (mem->inmem_hi < reply->content_length + reply->hdr_sz) return 0; else return 1; diff --git a/src/mem.cc b/src/mem.cc index f711e3ff0c..66fe4ab105 100644 --- a/src/mem.cc +++ b/src/mem.cc @@ -1,6 +1,6 @@ /* - * $Id: mem.cc,v 1.18 1998/03/17 05:38:52 wessels Exp $ + * $Id: mem.cc,v 1.19 1998/03/20 18:06:45 rousskov Exp $ * * DEBUG: section 13 High Level Memory Pool Management * AUTHOR: Harvest Derived @@ -216,7 +216,8 @@ memInit(void) memDataInit(MEM_HIERARCHYLOGENTRY, "HierarchyLogEntry", sizeof(HierarchyLogEntry), 0); memDataInit(MEM_HTTP_STATE_DATA, "HttpStateData", sizeof(HttpStateData), 0); - memDataInit(MEM_HTTPREPLY, "http_reply", sizeof(http_reply), 0); + memDataInit(MEM_HTTP_REPLY, "HttpReply", sizeof(HttpReply), 0); + memDataInit(MEM_HTTP_HDR_ENTRY, "HttpHeaderEntry", sizeof(HttpHeaderEntry), 0); memDataInit(MEM_HTTP_HDR_CC, "HttpHdrCc", sizeof(HttpHdrCc), 0); memDataInit(MEM_HTTP_HDR_RANGE_SPEC, "HttpHdrRangeSpec", sizeof(HttpHdrRangeSpec), 0); memDataInit(MEM_HTTP_HDR_RANGE, "HttpHdrRange", sizeof(HttpHdrRange), 0); diff --git a/src/protos.h b/src/protos.h index d9cd77c922..0c7b9d4b2f 100644 --- a/src/protos.h +++ b/src/protos.h @@ -258,12 +258,6 @@ extern void httpBodySet(HttpBody * body, const char *content, int size, /* pack */ extern void httpBodyPackInto(const HttpBody * body, Packer * p); -/* Http Extention Header Field */ -extern HttpHdrExtField *httpHdrExtFieldCreate(const char *name, const char *value); -extern HttpHdrExtField *httpHdrExtFieldParseCreate(const char *field_start, const char *field_end); -extern void httpHdrExtFieldDestroy(HttpHdrExtField * f); -extern HttpHdrExtField *httpHdrExtFieldDup(HttpHdrExtField * f); - /* Http Cache Control Header Field */ extern void httpHdrCcInitModule(); extern void httpHdrCcCleanModule(); @@ -297,33 +291,31 @@ extern void httpHdrContRangePackInto(const HttpHdrContRange * crange, Packer * p /* Http Header Tools */ extern HttpHeaderFieldInfo *httpHeaderBuildFieldsInfo(const HttpHeaderFieldAttrs * attrs, int count); extern void httpHeaderDestroyFieldsInfo(HttpHeaderFieldInfo * info, int count); -extern int httpHeaderIdByName(const char *name, int name_len, const HttpHeaderFieldInfo * attrs, int end, int mask); -extern int httpHeaderCalcMask(const int *enums, int count); +extern int httpHeaderIdByName(const char *name, int name_len, const HttpHeaderFieldInfo * attrs, int end); +extern void httpHeaderMaskInit(HttpHeaderMask *mask); +extern void httpHeaderCalcMask(HttpHeaderMask *mask, const int *enums, int count); extern int strListGetItem(const char *str, char del, const char **item, int *ilen, const char **pos); -extern const char *getStringPrefix(const char *str); +extern const char *getStringPrefix(const char *str, const char *end); extern int httpHeaderParseInt(const char *start, int *val); extern int httpHeaderParseSize(const char *start, size_t * sz); /* Http Header */ extern void httpHeaderInitModule(); extern void httpHeaderCleanModule(); -/* create/init/clean/destroy */ -extern HttpHeader *httpHeaderCreate(); +/* init/clean */ extern void httpHeaderInit(HttpHeader * hdr); extern void httpHeaderClean(HttpHeader * hdr); -extern void httpHeaderDestroy(HttpHeader * hdr); /* clone */ -void httpHeaderCopy(HttpHeader * dest, const HttpHeader * src); +extern void httpHeaderUpdate(HttpHeader *old, const HttpHeader *fresh); /* parse/pack */ extern int httpHeaderParse(HttpHeader * hdr, const char *header_start, const char *header_end); extern void httpHeaderPackInto(const HttpHeader * hdr, Packer * p); /* field manipulation */ extern int httpHeaderHas(const HttpHeader * hdr, http_hdr_type type); -extern HttpHeaderEntry *httpHeaderFindEntry(const HttpHeader * hdr, http_hdr_type id, HttpHeaderPos * pos); -extern void httpHeaderSetInt(HttpHeader * hdr, http_hdr_type type, int number); -extern void httpHeaderSetTime(HttpHeader * hdr, http_hdr_type type, time_t time); -extern void httpHeaderSetStr(HttpHeader * hdr, http_hdr_type type, const char *str); -extern void httpHeaderSetAuth(HttpHeader * hdr, const char *authScheme, const char *realm); +extern void httpHeaderPutInt(HttpHeader * hdr, http_hdr_type type, int number); +extern void httpHeaderPutTime(HttpHeader * hdr, http_hdr_type type, time_t time); +extern void httpHeaderPutStr(HttpHeader * hdr, http_hdr_type type, const char *str); +extern void httpHeaderPutAuth(HttpHeader * hdr, const char *authScheme, const char *realm); extern void httpHeaderAddExt(HttpHeader * hdr, const char *name, const char *value); extern int httpHeaderGetInt(const HttpHeader * hdr, http_hdr_type id); extern time_t httpHeaderGetTime(const HttpHeader * hdr, http_hdr_type id); @@ -331,8 +323,9 @@ extern HttpHdrCc *httpHeaderGetCc(const HttpHeader * hdr); extern HttpHdrRange *httpHeaderGetRange(const HttpHeader * hdr); extern HttpHdrContRange *httpHeaderGetContRange(const HttpHeader * hdr); extern const char *httpHeaderGetStr(const HttpHeader * hdr, http_hdr_type id); +extern int httpHeaderDelByName(HttpHeader * hdr, const char *name); +extern HttpHeaderEntry *httpHeaderFindEntry(const HttpHeader * hdr, http_hdr_type id); extern void httpHeaderEntryPackInto(const HttpHeaderEntry * e, Packer * p); -int httpHeaderDelFields(HttpHeader * hdr, const char *name); /* store report about current header usage and other stats */ extern void httpHeaderStoreReport(StoreEntry * e); @@ -557,7 +550,8 @@ void statHistLogInit(StatHist * H, int capacity, double min, double max); void statHistEnumInit(StatHist * H, int last_enum); /* MemMeter */ -#define memMeterCheckHWater(m) { if ((m).hwater < (m).level) (m).hwater = (m).level; } +extern void memMeterSyncHWater(MemMeter *m); +#define memMeterCheckHWater(m) { if ((m).hwater_level < (m).level) memMeterSyncHWater(&(m)); } #define memMeterInc(m) { (m).level++; memMeterCheckHWater(m); } #define memMeterDec(m) { (m).level--; } #define memMeterAdd(m, sz) { (m).level += (sz); memMeterCheckHWater(m); } @@ -590,6 +584,8 @@ extern size_t memPoolInUseSize(const MemPool * pool); extern int memPoolUsedCount(const MemPool * pool); extern void memPoolDescribe(const MemPool * pool); extern void memPoolReport(const MemPool * pool, StoreEntry * e); + +/* Mem */ extern void memReport(StoreEntry * e); extern size_t memTotalAllocated(void); diff --git a/src/store.cc b/src/store.cc index 2b40ddfbc0..e01b0f8df7 100644 --- a/src/store.cc +++ b/src/store.cc @@ -1,6 +1,6 @@ /* - * $Id: store.cc,v 1.395 1998/03/19 07:13:33 wessels Exp $ + * $Id: store.cc,v 1.396 1998/03/20 18:06:47 rousskov Exp $ * * DEBUG: section 20 Storeage Manager * AUTHOR: Harvest Derived @@ -750,19 +750,17 @@ static int storeEntryValidLength(const StoreEntry * e) { int diff; - http_reply *reply; - int clen; + const HttpReply *reply; assert(e->mem_obj != NULL); reply = e->mem_obj->reply; - clen = httpReplyContentLen(reply); debug(20, 3) ("storeEntryValidLength: Checking '%s'\n", storeKeyText(e->key)); debug(20, 5) ("storeEntryValidLength: object_len = %d\n", objectLen(e)); debug(20, 5) ("storeEntryValidLength: hdr_sz = %d\n", reply->hdr_sz); debug(20, 5) ("storeEntryValidLength: content_length = %d\n", - clen); - if (clen < 0) { + reply->content_length); + if (reply->content_length < 0) { debug(20, 5) ("storeEntryValidLength: Unspecified content length: %s\n", storeKeyText(e->key)); return 1; @@ -781,7 +779,7 @@ storeEntryValidLength(const StoreEntry * e) return 1; if (reply->sline.status == HTTP_NO_CONTENT) return 1; - diff = reply->hdr_sz + clen - objectLen(e); + diff = reply->hdr_sz + reply->content_length - objectLen(e); if (diff == 0) return 1; debug(20, 3) ("storeEntryValidLength: %d bytes too %s; '%s'\n", @@ -972,11 +970,11 @@ storeTimestampsSet(StoreEntry * entry) { time_t served_date = -1; HttpReply *reply = entry->mem_obj->reply; - served_date = httpHeaderGetTime(&reply->hdr, HDR_DATE); + served_date = reply->date; if (served_date < 0) served_date = squid_curtime; - entry->expires = httpReplyExpires(reply); - entry->lastmod = httpHeaderGetTime(&reply->hdr, HDR_LAST_MODIFIED); + entry->expires = reply->expires; + entry->lastmod = reply->last_modified; if (entry->lastmod < 0) entry->lastmod = served_date; entry->timestamp = served_date; diff --git a/src/store_log.cc b/src/store_log.cc index 9a9210e0da..a2bf404e40 100644 --- a/src/store_log.cc +++ b/src/store_log.cc @@ -17,7 +17,6 @@ storeLog(int tag, const StoreEntry * e) LOCAL_ARRAY(char, logmsg, MAX_URL << 1); MemObject *mem = e->mem_obj; HttpReply *reply; - const char *ctype; if (storelog_fd < 0) return; if (mem == NULL) @@ -28,18 +27,17 @@ storeLog(int tag, const StoreEntry * e) mem->log_url = xstrdup(mem->url); } reply = mem->reply; - ctype = httpHeaderGetStr(&reply->hdr, HDR_CONTENT_TYPE); snprintf(logmsg, MAX_URL << 1, "%9d.%03d %-7s %08X %4d %9d %9d %9d %s %d/%d %s %s\n", (int) current_time.tv_sec, (int) current_time.tv_usec / 1000, storeLogTags[tag], e->swap_file_number, reply->sline.status, - (int) httpHeaderGetTime(&reply->hdr, HDR_DATE), - (int) httpHeaderGetTime(&reply->hdr, HDR_LAST_MODIFIED), - (int) httpReplyExpires(reply), - ctype ? ctype : "unknown", - httpReplyContentLen(reply), + (int) reply->date, + (int) reply->last_modified, + (int) reply->expires, + strBuf(reply->content_type) ? strBuf(reply->content_type) : "unknown", + reply->content_length, (int) (mem->inmem_hi - mem->reply->hdr_sz), RequestMethodStr[mem->method], mem->log_url); diff --git a/src/structs.h b/src/structs.h index d12cdf1028..847e21ccc6 100644 --- a/src/structs.h +++ b/src/structs.h @@ -481,7 +481,7 @@ struct _HttpHdrExtField { /* http cache control header field */ struct _HttpHdrCc { int mask; - time_t max_age; + int max_age; }; /* http byte-range-spec */ @@ -505,20 +505,10 @@ struct _HttpHdrContRange { }; -/* a storage for an entry of one of possible types (for lower level routines) */ -union _field_store { - int v_int; - time_t v_time; - String v_str; - const String *v_cpstr; - HttpHdrCc *v_pcc; - HttpHdrRange *v_prange; - HttpHdrContRange *v_pcont_range; -}; - /* per field statistics */ struct _HttpHeaderFieldStat { int aliveCount; /* created but not destroyed (count) */ + int seenCount; /* #fields we've seen */ int parsCount; /* #parsing attempts */ int errCount; /* #pasring errors */ int repCount; /* #repetitons */ @@ -531,7 +521,7 @@ struct _HttpHeaderFieldAttrs { field_type type; }; -/* compiled version HttpHeaderFieldAttrs plus stats */ +/* compiled version of HttpHeaderFieldAttrs plus stats */ struct _HttpHeaderFieldInfo { http_hdr_type id; String name; @@ -539,28 +529,39 @@ struct _HttpHeaderFieldInfo { HttpHeaderFieldStat stat; }; -struct _HttpHeader { - /* public, read only */ - int emask; /* bits set for present entries */ +struct _HttpHeaderEntry { + http_hdr_type id; + String name; + String value; +}; +struct _HttpHeader { /* protected, do not use these, use interface functions instead */ - int capacity; /* max #entries before we have to grow */ - int ucount; /* #entries used, including holes */ - HttpHeaderEntry *entries; + Array entries; /* parsed fields in raw format */ + HttpHeaderMask mask; /* bit set <=> entry present */ }; - struct _HttpReply { /* unsupported, writable, may disappear/change in the future */ int hdr_sz; /* sums _stored_ status-line, headers, and */ + /* public, readable; never update these or their .hdr equivalents directly */ + int content_length; + time_t date; + time_t last_modified; + time_t expires; + String content_type; + HttpHdrCc *cache_control; + HttpHdrContRange *content_range; + short int pconn_keep_alive; + /* public, readable */ HttpMsgParseState pstate; /* the current parsing state */ /* public, writable, but use httpReply* interfaces when possible */ HttpStatusLine sline; - HttpHeader hdr; - HttpBody body; /* used for small constant memory-resident text bodies only */ + HttpHeader header; + HttpBody body; /* for small constant memory-resident text bodies only */ }; @@ -1009,6 +1010,7 @@ struct _request_t { String urlpath; int link_count; /* free when zero */ int flags; + HttpHdrCc *cache_control; /* not used yet */ time_t max_age; float http_ver; time_t ims; @@ -1154,7 +1156,8 @@ struct _storeSwapLogData { /* object to track per-action memory usage (e.g. #idle objects) */ struct _MemMeter { size_t level; /* current level (count or volume) */ - size_t hwater; /* high water mark */ + size_t hwater_level; /* high water mark */ + time_t hwater_stamp; /* timestamp of last high water mark change */ }; /* object to track per-pool memory usage (alloc = inuse+idle) */ diff --git a/src/typedefs.h b/src/typedefs.h index 15271990e8..45e33f0b2f 100644 --- a/src/typedefs.h +++ b/src/typedefs.h @@ -58,10 +58,8 @@ typedef struct _HttpHdrCc HttpHdrCc; typedef struct _HttpHdrRangeSpec HttpHdrRangeSpec; typedef struct _HttpHdrRange HttpHdrRange; typedef struct _HttpHdrContRange HttpHdrContRange; -typedef struct _HttpHdrExtField HttpHdrExtField; typedef struct _HttpHeaderEntry HttpHeaderEntry; typedef struct _HttpHeaderFieldStat HttpHeaderFieldStat; -typedef union _field_store field_store; typedef struct _HttpBody HttpBody; typedef struct _HttpReply HttpReply; typedef struct _HttpStateData HttpStateData; @@ -168,3 +166,6 @@ typedef int HttpHdrRangePos; /*iteration for headers; use HttpHeaderPos as opaque type, do not interpret */ typedef ssize_t HttpHeaderPos; + +/* big mask for http headers */ +typedef char HttpHeaderMask[8]; diff --git a/src/urn.cc b/src/urn.cc index d21ff2472d..5ba1dd581e 100644 --- a/src/urn.cc +++ b/src/urn.cc @@ -251,7 +251,7 @@ urnHandleReply(void *data, char *buf, ssize_t size) if (EBIT_TEST(urnState->flags, URN_FORCE_MENU)) { debug(51, 3) ("urnHandleReply: forcing menu\n"); } else if (min_w) { - httpHeaderSetStr(&rep->hdr, HDR_LOCATION, min_w->key); + httpHeaderPutStr(&rep->header, HDR_LOCATION, min_w->key); } httpBodySet(&rep->body, mb.buf, mb.size+1, memBufFreeFunc(&mb)); httpReplySwapOut(rep, e);