]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
- Separated raw HTTP headers from their "compiled" values. Squid is now
authorrousskov <>
Sat, 21 Mar 1998 01:06:37 +0000 (01:06 +0000)
committerrousskov <>
Sat, 21 Mar 1998 01:06:37 +0000 (01:06 +0000)
  forwarding headers even it cannot "compile" them. Virtually no changes to
  common format headers are done. Compiled values are stored in Reply/Request
  objects.

17 files changed:
src/HttpHdrCc.cc
src/HttpHeader.cc
src/HttpHeaderTools.cc
src/HttpReply.cc
src/Makefile.in
src/cache_manager.cc
src/defines.h
src/enums.h
src/ftp.cc
src/http.cc
src/mem.cc
src/protos.h
src/store.cc
src/store_log.cc
src/structs.h
src/typedefs.h
src/urn.cc

index 30abe23600b6f36382328abf4e1d20224b141dac..0f6ab9414e85c5a3bf7b58d57b4b84c5afb9c805 100644 (file)
@@ -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++;
        }
index 471ffa6e965c1aeae0b0a86974b2e77a918a452c..593d5ac96843d4311b20b1d0f03c3ec8e23d3bfa 100644 (file)
@@ -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
  * 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 "<name>:[ws]<value>" lines delimited by <CRLF> */
     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 <CRLF> */
-       /*
-        * 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, "<h3>Number of fields per header distribution (init size: %d)</h3>\n",
-       INIT_FIELDS_PER_HEADER);
+    storeAppendPrintf(e, "<h3>Number of fields per header distribution</h3>\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);
index 8fea8ce578994fc69785b6e947f32ef0c8dec077..ed56a5d5900456411b73a23e5314113f98f9a2da 100644 (file)
@@ -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);
index 585ad09749e0bd10eda9b681b0359fc0de287d1e..a10bd7ee05202626cf6e9a6e52a56fdbb8c2feab 100644 (file)
@@ -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++;
index 6b824914781fceaf2259e80d4d2c57a2cfe4fe2e..95a8ca723485d5b8845a1513964973047bffcc59 100644 (file)
@@ -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 \
index 140be685c505878dd70645104234b9355bf0b4cb..424af6a94b6b75521276dc3f0b816bd509b27114 100644 (file)
@@ -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 */
index 02ca2430a5434f01321cfe54f5d40abdefa4760f..f3c95c9f4e2fa450d8d1735055558679022b2f16 100644 (file)
 #define SM_PAGE_SIZE 4096
 #define DISK_PAGE_SIZE  8192
 
-#define EBIT_SET(flag, bit)    ((void)((flag) |= ((1<<bit))))
-#define EBIT_CLR(flag, bit)    ((void)((flag) &= ~((1<<bit))))
-#define EBIT_TEST(flag, bit)   ((flag) & ((1<<bit)))
+#define EBIT_SET(flag, bit)    ((void)((flag) |= ((1<<(bit)))))
+#define EBIT_CLR(flag, bit)    ((void)((flag) &= ~((1<<(bit)))))
+#define EBIT_TEST(flag, bit)   ((flag) & ((1<<(bit))))
+
+/* bit opearations on a char[] mask of unlimited length */
+#define CBIT_BIT(bit)           (1<<((bit)%8))
+#define CBIT_BIN(mask, bit)     (mask)[(bit)>>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)
 
index f052a84bf9be951fb8a6c0db9b9aff3394c58728..d4418d793335b404dec54c7e4960a8a6976f29b2 100644 (file)
@@ -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,
index 268ae31d8f640dd7aa14a648dbc1965ff63a93a3..b7d604720359e1cec914c7c5653df5882474c3f9 100644 (file)
@@ -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);
 }
index e4fe0bc0a1b24b353c24a9b96bc21b0a5b61c453..58341b4b033794bc180a4fc84ce56045c9bd3d3c 100644 (file)
@@ -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;
index f711e3ff0c256cff30d941aecdc8a8551cf396a5..66fe4ab1050f4184423ebf4c038efbee4bd61105 100644 (file)
@@ -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);
index d9cd77c922f922ebd854f5600bd26cce705f6469..0c7b9d4b2f7d4a9f5718dc227106f97722affaef 100644 (file)
@@ -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);
 
index 2b40ddfbc0433f59d9cbfb4b364a30a760c3543a..e01b0f8df7cfea4113961f23de4c3d8dbad422b7 100644 (file)
@@ -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;
index 9a9210e0da84470d5c6ece73eb2b630fa0537a5e..a2bf404e40251e94d6157a4e7890b6f3f8010275 100644 (file)
@@ -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);
index d12cdf1028a0f6773fc2ea819e5ece04859c177b..847e21ccc6f34a8cb168010005d9aafaf39d5823 100644 (file)
@@ -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 <CRLF> */
 
+    /* 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) */
index 15271990e8d6ffa1e2758a8e9c004ded6e47e884..45e33f0b2fe1e7c4651a077030a1d5bebf5acaa3 100644 (file)
@@ -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];
index d21ff2472d77724bd0c3d26520474ea7be6865a6..5ba1dd581efe8e8a9f3e1fd3d6b11c912ec7a0cd 100644 (file)
@@ -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);