]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Refactor HttpHeader into gperf-generated perfect hash
authorFrancesco Chemolli <kinkie@squid-cache.org>
Sat, 5 Sep 2015 18:52:17 +0000 (20:52 +0200)
committerFrancesco Chemolli <kinkie@squid-cache.org>
Sat, 5 Sep 2015 18:52:17 +0000 (20:52 +0200)
23 files changed:
src/HttpHeader.cc
src/HttpHeader.h
src/HttpHeaderStat.h
src/HttpHeaderTools.cc
src/HttpHeaderTools.h
src/HttpReply.cc
src/ICP.h
src/Makefile.am
src/acl/HttpHeaderData.cc
src/acl/HttpHeaderData.h
src/adaptation/icap/ModXact.cc
src/auth/UserRequest.cc
src/base/LookupTable.h
src/cache_cf.cc
src/client_side_reply.cc
src/external_acl.cc
src/htcp.cc
src/http.cc
src/http/Makefile.am
src/http/RegisteredHeaders.cc
src/http/RegisteredHeaders.h
src/http/RegisteredHeadersHash.cci [new file with mode: 0644]
src/http/RegisteredHeadersHash.gperf [new file with mode: 0644]

index 368253fe208bc6df06f65e69bfb34ccb277f3157..9db818baecc5e2ee5e56ece4c8b18683326a6756 100644 (file)
@@ -9,7 +9,7 @@
 /* DEBUG: section 55    HTTP Header */
 
 #include "squid.h"
-//#include "base/LookupTable.h" // pulled by HttpHdrCc.h
+#include "base/EnumIterator.h"
 #include "base64.h"
 #include "globals.h"
 #include "HttpHdrCc.h"
  */
 
 // statistics counters for headers. clients must not allow Http::HdrType::BAD_HDR to be counted
-std::vector<HttpHeaderFieldStat> headerStatsTable(Http::HdrType::ENUM_END);
+std::vector<HttpHeaderFieldStat> headerStatsTable(Http::HdrType::enumEnd_);
 
-/*
- * headers with field values defined as #(values) in HTTP/1.1
- * Headers that are currently not recognized, are commented out.
- */
-static HttpHeaderMask ListHeadersMask;  /* set run-time using  ListHeadersArr */
-static Http::HdrType ListHeadersArr[] = {
-    Http::HdrType::ACCEPT,
-    Http::HdrType::ACCEPT_CHARSET,
-    Http::HdrType::ACCEPT_ENCODING,
-    Http::HdrType::ACCEPT_LANGUAGE,
-    Http::HdrType::ACCEPT_RANGES,
-    Http::HdrType::ALLOW,
-    Http::HdrType::CACHE_CONTROL,
-    Http::HdrType::CONTENT_ENCODING,
-    Http::HdrType::CONTENT_LANGUAGE,
-    Http::HdrType::CONNECTION,
-    Http::HdrType::EXPECT,
-    Http::HdrType::IF_MATCH,
-    Http::HdrType::IF_NONE_MATCH,
-    Http::HdrType::KEY,
-    Http::HdrType::LINK,
-    Http::HdrType::PRAGMA,
-    Http::HdrType::PROXY_CONNECTION,
-    Http::HdrType::PROXY_SUPPORT,
-    Http::HdrType::TRANSFER_ENCODING,
-    Http::HdrType::UPGRADE,
-    Http::HdrType::VARY,
-    Http::HdrType::VIA,
-    Http::HdrType::WARNING,
-    Http::HdrType::WWW_AUTHENTICATE,
-    Http::HdrType::AUTHENTICATION_INFO,
-    Http::HdrType::PROXY_AUTHENTICATION_INFO,
-    /* Http::HdrType::TE, Http::HdrType::TRAILER */
-#if X_ACCELERATOR_VARY
-    Http::HdrType::HDR_X_ACCELERATOR_VARY,
-#endif
-#if USE_ADAPTATION
-    Http::HdrType::X_NEXT_SERVICES,
-#endif
-    Http::HdrType::SURROGATE_CAPABILITY,
-    Http::HdrType::SURROGATE_CONTROL,
-    Http::HdrType::FORWARDED,
-    Http::HdrType::X_FORWARDED_FOR
-};
-
-/* general-headers */
-static Http::HdrType GeneralHeadersArr[] = {
-    Http::HdrType::CACHE_CONTROL,
-    Http::HdrType::CONNECTION,
-    Http::HdrType::DATE,
-    Http::HdrType::FORWARDED,
-    Http::HdrType::X_FORWARDED_FOR,
-    Http::HdrType::MIME_VERSION,
-    Http::HdrType::PRAGMA,
-    Http::HdrType::PROXY_CONNECTION,
-    Http::HdrType::TRANSFER_ENCODING,
-    Http::HdrType::UPGRADE,
-    /* Http::HdrType::TRAILER, */
-    Http::HdrType::VIA,
-};
-
-/* entity-headers */
-static Http::HdrType EntityHeadersArr[] = {
-    Http::HdrType::ALLOW,
-    Http::HdrType::CONTENT_BASE,
-    Http::HdrType::CONTENT_ENCODING,
-    Http::HdrType::CONTENT_LANGUAGE,
-    Http::HdrType::CONTENT_LENGTH,
-    Http::HdrType::CONTENT_LOCATION,
-    Http::HdrType::CONTENT_MD5,
-    Http::HdrType::CONTENT_RANGE,
-    Http::HdrType::CONTENT_TYPE,
-    Http::HdrType::ETAG,
-    Http::HdrType::EXPIRES,
-    Http::HdrType::LAST_MODIFIED,
-    Http::HdrType::LINK,
-    Http::HdrType::OTHER
-};
-
-/* request-only headers */
+/* request-only headers. Used for cachemgr */
 static HttpHeaderMask RequestHeadersMask;   /* set run-time using RequestHeaders */
-static Http::HdrType RequestHeadersArr[] = {
-    Http::HdrType::ACCEPT,
-    Http::HdrType::ACCEPT_CHARSET,
-    Http::HdrType::ACCEPT_ENCODING,
-    Http::HdrType::ACCEPT_LANGUAGE,
-    Http::HdrType::AUTHORIZATION,
-    Http::HdrType::EXPECT,
-    Http::HdrType::FROM,
-    Http::HdrType::HOST,
-    Http::HdrType::HTTP2_SETTINGS,
-    Http::HdrType::IF_MATCH,
-    Http::HdrType::IF_MODIFIED_SINCE,
-    Http::HdrType::IF_NONE_MATCH,
-    Http::HdrType::IF_RANGE,
-    Http::HdrType::IF_UNMODIFIED_SINCE,
-    Http::HdrType::MAX_FORWARDS,
-    Http::HdrType::ORIGIN,
-    Http::HdrType::PROXY_AUTHORIZATION,
-    Http::HdrType::RANGE,
-    Http::HdrType::REFERER,
-    Http::HdrType::REQUEST_RANGE,
-    Http::HdrType::TE,
-    Http::HdrType::USER_AGENT,
-    Http::HdrType::SURROGATE_CAPABILITY
-};
 
-/* reply-only headers */
+/* reply-only headers. Used for cachemgr */
 static HttpHeaderMask ReplyHeadersMask;     /* set run-time using ReplyHeaders */
-static Http::HdrType ReplyHeadersArr[] = {
-    Http::HdrType::ACCEPT_ENCODING,
-    Http::HdrType::ACCEPT_RANGES,
-    Http::HdrType::AGE,
-    Http::HdrType::KEY,
-    Http::HdrType::LOCATION,
-    Http::HdrType::PROXY_AUTHENTICATE,
-    Http::HdrType::PUBLIC,
-    Http::HdrType::RETRY_AFTER,
-    Http::HdrType::SERVER,
-    Http::HdrType::SET_COOKIE,
-    Http::HdrType::SET_COOKIE2,
-    Http::HdrType::VARY,
-    Http::HdrType::WARNING,
-    Http::HdrType::WWW_AUTHENTICATE,
-    Http::HdrType::X_CACHE,
-    Http::HdrType::X_CACHE_LOOKUP,
-    Http::HdrType::X_REQUEST_URI,
-#if X_ACCELERATOR_VARY
-    Http::HdrType::HDR_X_ACCELERATOR_VARY,
-#endif
-#if USE_ADAPTATION
-    Http::HdrType::X_NEXT_SERVICES,
-#endif
-    Http::HdrType::X_SQUID_ERROR,
-    Http::HdrType::SURROGATE_CONTROL
-};
-
-/* hop-by-hop headers */
-static HttpHeaderMask HopByHopHeadersMask;
-static Http::HdrType HopByHopHeadersArr[] = {
-    Http::HdrType::ALTERNATE_PROTOCOL,
-    Http::HdrType::CONNECTION,
-    Http::HdrType::HTTP2_SETTINGS,
-    Http::HdrType::KEEP_ALIVE,
-    /*Http::HdrType::PROXY_AUTHENTICATE, // removal handled specially for peer login */
-    Http::HdrType::PROXY_AUTHORIZATION,
-    Http::HdrType::TE,
-    Http::HdrType::TRAILER,
-    Http::HdrType::TRANSFER_ENCODING,
-    Http::HdrType::UPGRADE,
-    Http::HdrType::PROXY_CONNECTION
-};
 
 /* header accounting */
 // NP: keep in sync with enum http_hdr_owner_type
@@ -240,7 +93,9 @@ static int HeaderEntryParsedCount = 0;
 
 class StoreEntry;
 
-static void httpHeaderNoteParsedEntry(Http::HdrType id, String const &value, int error);
+// update parse statistics for header id; if error is true also account
+// for errors and write to debug log what happened
+static void httpHeaderNoteParsedEntry(Http::HdrType id, String const &value, bool error);
 static void httpHeaderStatDump(const HttpHeaderStat * hs, StoreEntry * e);
 /** store report about current header usage and other stats */
 static void httpHeaderStoreReport(StoreEntry * e);
@@ -261,28 +116,15 @@ void
 httpHeaderInitModule(void)
 {
     /* check that we have enough space for masks */
-    assert(8 * sizeof(HttpHeaderMask) >= Http::HdrType::ENUM_END);
-
-    // check invariant: for each index in headerTable, (int)headerTable[index] = index
-    for (int i = 0; Http::HeaderTable[i].name; ++i)
-        assert(Http::HeaderTable[i].id == i);
-
-    /* create masks. XXX: migrate to std::vector<bool>? */
-    httpHeaderMaskInit(&ListHeadersMask, 0);
-    httpHeaderCalcMask(&ListHeadersMask, ListHeadersArr, countof(ListHeadersArr));
-
-    httpHeaderMaskInit(&ReplyHeadersMask, 0);
-    httpHeaderCalcMask(&ReplyHeadersMask, ReplyHeadersArr, countof(ReplyHeadersArr));
-    httpHeaderCalcMask(&ReplyHeadersMask, GeneralHeadersArr, countof(GeneralHeadersArr));
-    httpHeaderCalcMask(&ReplyHeadersMask, EntityHeadersArr, countof(EntityHeadersArr));
-
-    httpHeaderMaskInit(&RequestHeadersMask, 0);
-    httpHeaderCalcMask(&RequestHeadersMask, RequestHeadersArr, countof(RequestHeadersArr));
-    httpHeaderCalcMask(&RequestHeadersMask, GeneralHeadersArr, countof(GeneralHeadersArr));
-    httpHeaderCalcMask(&RequestHeadersMask, EntityHeadersArr, countof(EntityHeadersArr));
-
-    httpHeaderMaskInit(&HopByHopHeadersMask, 0);
-    httpHeaderCalcMask(&HopByHopHeadersMask, HopByHopHeadersArr, countof(HopByHopHeadersArr));
+    assert(8 * sizeof(HttpHeaderMask) >= Http::HdrType::enumEnd_);
+
+    // masks are needed for stats page still
+    for (auto h : WholeEnum<Http::HdrType>()) {
+        if (Http::HeaderLookupTable.lookup(h).request)
+            CBIT_SET(RequestHeadersMask,h);
+        if (Http::HeaderLookupTable.lookup(h).reply)
+            CBIT_SET(ReplyHeadersMask,h);
+    }
 
     /* header stats initialized by class constructor */
     assert(HttpHeaderStatCount == hoReply + 1);
@@ -363,7 +205,7 @@ HttpHeader::clean()
         HttpHeaderStats[owner].busyDestroyedCount += entries.size() > 0;
     } // if (owner <= hoReply)
 
-    for(HttpHeaderEntry *e : entries) {
+    for (HttpHeaderEntry *e : entries) {
         if (e == nullptr)
             continue;
         if (!Http::any_valid_header(e->id)) {
@@ -386,25 +228,16 @@ HttpHeader::clean()
 void
 HttpHeader::append(const HttpHeader * src)
 {
-    const HttpHeaderEntry *e;
-    HttpHeaderPos pos = HttpHeaderInitPos;
     assert(src);
     assert(src != this);
     debugs(55, 7, "appending hdr: " << this << " += " << src);
 
-    while ((e = src->getEntry(&pos))) {
-        addEntry(e->clone());
+    for (auto e : src->entries) {
+        if (e)
+            addEntry(e->clone());
     }
 }
 
-/* use fresh entries to replace old ones */
-void
-httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask * denied_mask)
-{
-    assert (old);
-    old->update (fresh, denied_mask);
-}
-
 void
 HttpHeader::update (HttpHeader const *fresh, HttpHeaderMask const *denied_mask)
 {
@@ -432,20 +265,12 @@ HttpHeader::update (HttpHeader const *fresh, HttpHeaderMask const *denied_mask)
         if (denied_mask && CBIT_TEST(*denied_mask, e->id))
             continue;
 
-        debugs(55, 7, "Updating header '" << Http::HeaderTable[e->id].name << "' in cached entry");
+        debugs(55, 7, "Updating header '" << Http::HeaderLookupTable.lookup(e->id).name << "' in cached entry");
 
         addEntry(e->clone());
     }
 }
 
-/* just handy in parsing: resets and returns false */
-int
-HttpHeader::reset()
-{
-    clean();
-    return 0;
-}
-
 int
 HttpHeader::parse(const char *header_start, size_t hdrLen)
 {
@@ -465,7 +290,8 @@ HttpHeader::parse(const char *header_start, size_t hdrLen)
         debugs(55, DBG_IMPORTANT, "WARNING: HTTP header contains NULL characters {" <<
                getStringPrefix(header_start, nulpos-header_start) << "}\nNULL\n{" << getStringPrefix(nulpos+1, hdrLen-(nulpos-header_start)-1));
         PROF_stop(HttpHeaderParse);
-        return reset();
+        clean();
+        return 0;
     }
 
     /* common format headers are "<name>:[ws]<value>" lines delimited by <CRLF>.
@@ -481,7 +307,8 @@ HttpHeader::parse(const char *header_start, size_t hdrLen)
             if (!field_ptr) {
                 // missing <LF>
                 PROF_stop(HttpHeaderParse);
-                return reset();
+                clean();
+                return 0;
             }
 
             field_end = field_ptr;
@@ -502,7 +329,8 @@ HttpHeader::parse(const char *header_start, size_t hdrLen)
                                "header field to prevent request smuggling attacks: {" <<
                                getStringPrefix(header_start, hdrLen) << "}");
                         PROF_stop(HttpHeaderParse);
-                        return reset();
+                        clean();
+                        return 0;
                     }
                 }
             }
@@ -521,7 +349,8 @@ HttpHeader::parse(const char *header_start, size_t hdrLen)
                     }
                 } else {
                     PROF_stop(HttpHeaderParse);
-                    return reset();
+                    clean();
+                    return 0;
                 }
             }
 
@@ -529,7 +358,8 @@ HttpHeader::parse(const char *header_start, size_t hdrLen)
                 debugs(55, warnOnError, "WARNING: Blank continuation line in HTTP header {" <<
                        getStringPrefix(header_start, hdrLen) << "}");
                 PROF_stop(HttpHeaderParse);
-                return reset();
+                clean();
+                return 0;
             }
         } while (field_ptr < header_end && (*field_ptr == ' ' || *field_ptr == '\t'));
 
@@ -538,7 +368,8 @@ HttpHeader::parse(const char *header_start, size_t hdrLen)
                 debugs(55, warnOnError, "WARNING: unparseable HTTP header field near {" <<
                        getStringPrefix(field_start, hdrLen-(field_start-header_start)) << "}");
                 PROF_stop(HttpHeaderParse);
-                return reset();
+                clean();
+                return 0;
             }
 
             break;      /* terminating blank line */
@@ -553,7 +384,8 @@ HttpHeader::parse(const char *header_start, size_t hdrLen)
                 continue;
 
             PROF_stop(HttpHeaderParse);
-            return reset();
+            clean();
+            return 0;
         }
 
         // XXX: RFC 7230 Section 3.3.3 item #4 requires sending a 502 error in
@@ -567,7 +399,8 @@ HttpHeader::parse(const char *header_start, size_t hdrLen)
                 if (!Config.onoff.relaxed_header_parser) {
                     delete e;
                     PROF_stop(HttpHeaderParse);
-                    return reset();
+                    clean();
+                    return 0;
                 }
 
                 if (!httpHeaderParseOffset(e->value.termedBuf(), &l1)) {
@@ -591,7 +424,8 @@ HttpHeader::parse(const char *header_start, size_t hdrLen)
                     continue;
 
                 PROF_stop(HttpHeaderParse);
-                return reset();
+                clean();
+                return 0;
             }
         }
 
@@ -602,7 +436,8 @@ HttpHeader::parse(const char *header_start, size_t hdrLen)
             if (!Config.onoff.relaxed_header_parser) {
                 delete e;
                 PROF_stop(HttpHeaderParse);
-                return reset();
+                clean();
+                return 0;
             }
         }
 
@@ -690,10 +525,8 @@ HttpHeader::getEntry(HttpHeaderPos * pos) const
 HttpHeaderEntry *
 HttpHeader::findEntry(Http::HdrType id) const
 {
-    HttpHeaderPos pos = HttpHeaderInitPos;
-    HttpHeaderEntry *e;
     assert(any_registered_header(id));
-    assert(!CBIT_TEST(ListHeadersMask, id));
+    assert(!Http::HeaderLookupTable.lookup(id).list);
 
     /* check mask first */
 
@@ -701,15 +534,14 @@ HttpHeader::findEntry(Http::HdrType id) const
         return NULL;
 
     /* looks like we must have it, do linear search */
-    while ((e = getEntry(&pos))) {
-        if (e->id == id)
+    for (auto e : entries) {
+        if (e && e->id == id)
             return e;
     }
 
     /* hm.. we thought it was there, but it was not found */
-    assert(0);
-
-    return NULL;        /* not reached */
+    assert(false);
+    return nullptr;        /* not reached */
 }
 
 /*
@@ -718,25 +550,21 @@ HttpHeader::findEntry(Http::HdrType id) const
 HttpHeaderEntry *
 HttpHeader::findLastEntry(Http::HdrType id) const
 {
-    HttpHeaderPos pos = HttpHeaderInitPos;
-    HttpHeaderEntry *e;
-    HttpHeaderEntry *result = NULL;
     assert(any_registered_header(id));
-    assert(!CBIT_TEST(ListHeadersMask, id));
+    assert(!Http::HeaderLookupTable.lookup(id).list);
 
     /* check mask first */
-
     if (!CBIT_TEST(mask, id))
         return NULL;
 
-    /* looks like we must have it, do linear search */
-    while ((e = getEntry(&pos))) {
-        if (e->id == id)
-            result = e;
+    for (auto e = entries.rbegin(); e != entries.rend(); ++e) {
+        if (*e && (*e)->id == id)
+            return *e;
     }
 
-    assert(result);     /* must be there! */
-    return result;
+    /* hm.. we thought it was there, but it was not found */
+    assert(false);
+    return nullptr; /* not reached */
 }
 
 /*
@@ -765,19 +593,23 @@ HttpHeader::delByName(const char *name)
 int
 HttpHeader::delById(Http::HdrType id)
 {
-    int count = 0;
-    HttpHeaderPos pos = HttpHeaderInitPos;
-    HttpHeaderEntry *e;
     debugs(55, 8, this << " del-by-id " << id);
     assert(any_registered_header(id));
+    int count=0;
 
     if (!CBIT_TEST(mask, id))
         return 0;
 
-    while ((e = getEntry(&pos))) {
-        if (e->id == id)
-            delAt(pos, count);
-    }
+    //replace matching items with nil and count them
+    std::replace_if(entries.begin(), entries.end(),
+        [&](const HttpHeaderEntry *e) {
+            if (e && e->id == id) {
+                ++count;
+                return true;
+            }
+            return false;
+        },
+        nullptr);
 
     CBIT_CLR(mask, id);
     assert(count);
@@ -811,9 +643,8 @@ void
 HttpHeader::compact()
 {
     // TODO: optimize removal, or possibly make it so that's not needed.
-    std::vector<HttpHeaderEntry *>::iterator newend;
-    newend = std::remove(entries.begin(), entries.end(), static_cast<HttpHeaderEntry *>(NULL));
-    entries.resize(newend-entries.begin());
+    entries.erase( std::remove(entries.begin(), entries.end(), nullptr),
+                   entries.end());
 }
 
 /*
@@ -824,9 +655,9 @@ HttpHeader::refreshMask()
 {
     httpHeaderMaskInit(&mask, 0);
     debugs(55, 7, "refreshing the mask in hdr " << this);
-    HttpHeaderPos pos = HttpHeaderInitPos;
-    while (HttpHeaderEntry *e = getEntry(&pos)) {
-        CBIT_SET(mask, e->id);
+    for (auto e : entries) {
+        if (e)
+            CBIT_SET(mask, e->id);
     }
 }
 
@@ -883,17 +714,15 @@ HttpHeader::insertEntry(HttpHeaderEntry * e)
 bool
 HttpHeader::getList(Http::HdrType id, String *s) const
 {
-    HttpHeaderEntry *e;
-    HttpHeaderPos pos = HttpHeaderInitPos;
     debugs(55, 9, this << " joining for id " << id);
     /* only fields from ListHeaders array can be "listed" */
-    assert(CBIT_TEST(ListHeadersMask, id));
+    assert(Http::HeaderLookupTable.lookup(id).list);
 
     if (!CBIT_TEST(mask, id))
         return false;
 
-    while ((e = getEntry(&pos))) {
-        if (e->id == id)
+    for (auto e: entries) {
+        if (e && e->id == id)
             strListAdd(s, e->value.termedBuf(), ',');
     }
 
@@ -904,7 +733,7 @@ HttpHeader::getList(Http::HdrType id, String *s) const
      */
     /* temporary warning: remove it? (Is it useful for diagnostics ?) */
     if (!s->size())
-        debugs(55, 3, "empty list header: " << Http::HeaderTable[id].name << "(" << id << ")");
+        debugs(55, 3, "empty list header: " << Http::HeaderLookupTable.lookup(id).name << "(" << id << ")");
     else
         debugs(55, 6, this << ": joined for id " << id << ": " << s);
 
@@ -919,7 +748,7 @@ HttpHeader::getList(Http::HdrType id) const
     HttpHeaderPos pos = HttpHeaderInitPos;
     debugs(55, 9, this << "joining for id " << id);
     /* only fields from ListHeaders array can be "listed" */
-    assert(CBIT_TEST(ListHeadersMask, id));
+    assert(Http::HeaderLookupTable.lookup(id).list);
 
     if (!CBIT_TEST(mask, id))
         return String();
@@ -938,7 +767,7 @@ HttpHeader::getList(Http::HdrType id) const
      */
     /* temporary warning: remove it? (Is it useful for diagnostics ?) */
     if (!s.size())
-        debugs(55, 3, "empty list header: " << Http::HeaderTable[id].name << "(" << id << ")");
+        debugs(55, 3, "empty list header: " << Http::HeaderLookupTable.lookup(id).name << "(" << id << ")");
     else
         debugs(55, 6, this << ": joined for id " << id << ": " << s);
 
@@ -951,7 +780,7 @@ HttpHeader::getStrOrList(Http::HdrType id) const
 {
     HttpHeaderEntry *e;
 
-    if (CBIT_TEST(ListHeadersMask, id))
+    if (Http::HeaderLookupTable.lookup(id).list)
         return getList(id);
 
     if ((e = findEntry(id)))
@@ -965,6 +794,15 @@ HttpHeader::getStrOrList(Http::HdrType id) const
  */
 String
 HttpHeader::getByName(const char *name) const
+{
+    String result;
+    // ignore presence: return undefined string if an empty header is present
+    (void)getByNameIfPresent(name, strlen(name), result);
+    return result;
+}
+
+String
+HttpHeader::getByName(const SBuf &name) const
 {
     String result;
     // ignore presence: return undefined string if an empty header is present
@@ -972,8 +810,33 @@ HttpHeader::getByName(const char *name) const
     return result;
 }
 
+String
+HttpHeader::getById(Http::HdrType id) const
+{
+    String result;
+    (void)getByIdIfPresent(id,result);
+    return result;
+}
+
+bool
+HttpHeader::getByNameIfPresent(const SBuf &s, String &result) const
+{
+    return getByNameIfPresent(s.rawContent(), s.length(), result);
+}
+
+bool
+HttpHeader::getByIdIfPresent(Http::HdrType id, String &result) const
+{
+    if (id == Http::HdrType::BAD_HDR)
+        return false;
+    if (!has(id))
+        return false;
+    result = getStrOrList(id);
+    return true;
+}
+
 bool
-HttpHeader::getByNameIfPresent(const char *name, String &result) const
+HttpHeader::getByNameIfPresent(const char *name, int namelen, String &result) const
 {
     Http::HdrType id;
     HttpHeaderPos pos = HttpHeaderInitPos;
@@ -982,13 +845,11 @@ HttpHeader::getByNameIfPresent(const char *name, String &result) const
     assert(name);
 
     /* First try the quick path */
-    id = Http::HeaderLookupTable.lookup(SBuf(name));
+    id = Http::HeaderLookupTable.lookup(name,namelen).id;
 
     if (id != Http::HdrType::BAD_HDR) {
-        if (!has(id))
-            return false;
-        result = getStrOrList(id);
-        return true;
+        if (getByIdIfPresent(id, result))
+            return true;
     }
 
     /* Sorry, an unknown header name. Do linear search */
@@ -1072,7 +933,7 @@ void
 HttpHeader::putInt(Http::HdrType id, int number)
 {
     assert(any_registered_header(id));
-    assert(Http::HeaderTable[id].type == Http::HdrFieldType::ftInt);  /* must be of an appropriate type */
+    assert(Http::HeaderLookupTable.lookup(id).type == Http::HdrFieldType::ftInt);  /* must be of an appropriate type */
     assert(number >= 0);
     addEntry(new HttpHeaderEntry(id, NULL, xitoa(number)));
 }
@@ -1081,7 +942,7 @@ void
 HttpHeader::putInt64(Http::HdrType id, int64_t number)
 {
     assert(any_registered_header(id));
-    assert(Http::HeaderTable[id].type == Http::HdrFieldType::ftInt64);    /* must be of an appropriate type */
+    assert(Http::HeaderLookupTable.lookup(id).type == Http::HdrFieldType::ftInt64);    /* must be of an appropriate type */
     assert(number >= 0);
     addEntry(new HttpHeaderEntry(id, NULL, xint64toa(number)));
 }
@@ -1090,25 +951,16 @@ void
 HttpHeader::putTime(Http::HdrType id, time_t htime)
 {
     assert(any_registered_header(id));
-    assert(Http::HeaderTable[id].type == Http::HdrFieldType::ftDate_1123);    /* must be of an appropriate type */
+    assert(Http::HeaderLookupTable.lookup(id).type == Http::HdrFieldType::ftDate_1123);    /* must be of an appropriate type */
     assert(htime >= 0);
     addEntry(new HttpHeaderEntry(id, NULL, mkrfc1123(htime)));
 }
 
-void
-HttpHeader::insertTime(Http::HdrType id, time_t htime)
-{
-    assert(any_registered_header(id));
-    assert(Http::HeaderTable[id].type == Http::HdrFieldType::ftDate_1123);    /* must be of an appropriate type */
-    assert(htime >= 0);
-    insertEntry(new HttpHeaderEntry(id, NULL, mkrfc1123(htime)));
-}
-
 void
 HttpHeader::putStr(Http::HdrType id, const char *str)
 {
     assert(any_registered_header(id));
-    assert(Http::HeaderTable[id].type == Http::HdrFieldType::ftStr);  /* must be of an appropriate type */
+    assert(Http::HeaderLookupTable.lookup(id).type == Http::HdrFieldType::ftStr);  /* must be of an appropriate type */
     assert(str);
     addEntry(new HttpHeaderEntry(id, NULL, str));
 }
@@ -1205,7 +1057,7 @@ int
 HttpHeader::getInt(Http::HdrType id) const
 {
     assert(any_registered_header(id));
-    assert(Http::HeaderTable[id].type == Http::HdrFieldType::ftInt);  /* must be of an appropriate type */
+    assert(Http::HeaderLookupTable.lookup(id).type == Http::HdrFieldType::ftInt);  /* must be of an appropriate type */
     HttpHeaderEntry *e;
 
     if ((e = findEntry(id)))
@@ -1218,7 +1070,7 @@ int64_t
 HttpHeader::getInt64(Http::HdrType id) const
 {
     assert(any_registered_header(id));
-    assert(Http::HeaderTable[id].type == Http::HdrFieldType::ftInt64);    /* must be of an appropriate type */
+    assert(Http::HeaderLookupTable.lookup(id).type == Http::HdrFieldType::ftInt64);    /* must be of an appropriate type */
     HttpHeaderEntry *e;
 
     if ((e = findEntry(id)))
@@ -1233,7 +1085,7 @@ HttpHeader::getTime(Http::HdrType id) const
     HttpHeaderEntry *e;
     time_t value = -1;
     assert(any_registered_header(id));
-    assert(Http::HeaderTable[id].type == Http::HdrFieldType::ftDate_1123);    /* must be of an appropriate type */
+    assert(Http::HeaderLookupTable.lookup(id).type == Http::HdrFieldType::ftDate_1123);    /* must be of an appropriate type */
 
     if ((e = findEntry(id))) {
         value = parse_rfc1123(e->value.termedBuf());
@@ -1249,10 +1101,10 @@ HttpHeader::getStr(Http::HdrType id) const
 {
     HttpHeaderEntry *e;
     assert(any_registered_header(id));
-    assert(Http::HeaderTable[id].type == Http::HdrFieldType::ftStr);  /* must be of an appropriate type */
+    assert(Http::HeaderLookupTable.lookup(id).type == Http::HdrFieldType::ftStr);  /* must be of an appropriate type */
 
     if ((e = findEntry(id))) {
-        httpHeaderNoteParsedEntry(e->id, e->value, 0);  /* no errors are possible */
+        httpHeaderNoteParsedEntry(e->id, e->value, false);  /* no errors are possible */
         return e->value.termedBuf();
     }
 
@@ -1265,10 +1117,10 @@ HttpHeader::getLastStr(Http::HdrType id) const
 {
     HttpHeaderEntry *e;
     assert(any_registered_header(id));
-    assert(Http::HeaderTable[id].type == Http::HdrFieldType::ftStr);  /* must be of an appropriate type */
+    assert(Http::HeaderLookupTable.lookup(id).type == Http::HdrFieldType::ftStr);  /* must be of an appropriate type */
 
     if ((e = findLastEntry(id))) {
-        httpHeaderNoteParsedEntry(e->id, e->value, 0);  /* no errors are possible */
+        httpHeaderNoteParsedEntry(e->id, e->value, false);  /* no errors are possible */
         return e->value.termedBuf();
     }
 
@@ -1403,7 +1255,7 @@ HttpHeader::getETag(Http::HdrType id) const
 {
     ETag etag = {NULL, -1};
     HttpHeaderEntry *e;
-    assert(Http::HeaderTable[id].type == Http::HdrFieldType::ftETag);     /* must be of an appropriate type */
+    assert(Http::HeaderLookupTable.lookup(id).type == Http::HdrFieldType::ftETag);     /* must be of an appropriate type */
 
     if ((e = findEntry(id)))
         etagParseInit(&etag, e->value.termedBuf());
@@ -1416,7 +1268,7 @@ HttpHeader::getTimeOrTag(Http::HdrType id) const
 {
     TimeOrTag tot;
     HttpHeaderEntry *e;
-    assert(Http::HeaderTable[id].type == Http::HdrFieldType::ftDate_1123_or_ETag);    /* must be of an appropriate type */
+    assert(Http::HeaderLookupTable.lookup(id).type == Http::HdrFieldType::ftDate_1123_or_ETag);    /* must be of an appropriate type */
     memset(&tot, 0, sizeof(tot));
 
     if ((e = findEntry(id))) {
@@ -1448,7 +1300,7 @@ HttpHeaderEntry::HttpHeaderEntry(Http::HdrType anId, const char *aName, const ch
     id = anId;
 
     if (id != Http::HdrType::OTHER)
-        name = Http::HeaderTable[id].name;
+        name = Http::HeaderLookupTable.lookup(id).name;
     else
         name = aName;
 
@@ -1511,7 +1363,7 @@ HttpHeaderEntry::parse(const char *field_start, const char *field_end)
     debugs(55, 9, "parsing HttpHeaderEntry: near '" <<  getStringPrefix(field_start, field_end-field_start) << "'");
 
     /* is it a "known" field? */
-    Http::HdrType id = Http::HeaderLookupTable.lookup(SBuf(field_start,name_len));
+    Http::HdrType id = Http::HeaderLookupTable.lookup(field_start,name_len).id;
     debugs(55, 9, "got hdr-id=" << id);
 
     String name;
@@ -1525,7 +1377,7 @@ HttpHeaderEntry::parse(const char *field_start, const char *field_end)
     if (id == Http::HdrType::OTHER)
         name.limitInit(field_start, name_len);
     else
-        name = Http::HeaderTable[id].name;
+        name = Http::HeaderLookupTable.lookup(id).name;
 
     /* trim field value */
     while (value_start < field_end && xisspace(*value_start))
@@ -1576,7 +1428,7 @@ HttpHeaderEntry::getInt() const
 {
     int val = -1;
     int ok = httpHeaderParseInt(value.termedBuf(), &val);
-    httpHeaderNoteParsedEntry(id, value, !ok);
+    httpHeaderNoteParsedEntry(id, value, ok == 0);
     /* XXX: Should we check ok - ie
      * return ok ? -1 : value;
      */
@@ -1588,7 +1440,7 @@ HttpHeaderEntry::getInt64() const
 {
     int64_t val = -1;
     int ok = httpHeaderParseOffset(value.termedBuf(), &val);
-    httpHeaderNoteParsedEntry(id, value, !ok);
+    httpHeaderNoteParsedEntry(id, value, ok == 0);
     /* XXX: Should we check ok - ie
      * return ok ? -1 : value;
      */
@@ -1596,7 +1448,7 @@ HttpHeaderEntry::getInt64() const
 }
 
 static void
-httpHeaderNoteParsedEntry(Http::HdrType id, String const &context, int error)
+httpHeaderNoteParsedEntry(Http::HdrType id, String const &context, bool error)
 {
     if (id != Http::HdrType::BAD_HDR)
         ++ headerStatsTable[id].parsCount;
@@ -1604,7 +1456,7 @@ httpHeaderNoteParsedEntry(Http::HdrType id, String const &context, int error)
     if (error) {
         if (id != Http::HdrType::BAD_HDR)
             ++ headerStatsTable[id].errCount;
-        debugs(55, 2, "cannot parse hdr field: '" << Http::HeaderTable[id].name << ": " << context << "'");
+        debugs(55, 2, "cannot parse hdr field: '" << Http::HeaderLookupTable.lookup(id).name << ": " << context << "'");
     }
 }
 
@@ -1621,7 +1473,7 @@ httpHeaderFieldStatDumper(StoreEntry * sentry, int, double val, double, int coun
 {
     const int id = static_cast<int>(val);
     const bool valid_id = Http::any_valid_header(static_cast<Http::HdrType>(id));
-    const char *name = valid_id ? Http::HeaderTable[id].name : "INVALID";
+    const char *name = valid_id ? Http::HeaderLookupTable.lookup(static_cast<Http::HdrType>(id)).name : "INVALID";
     int visible = count > 0;
     /* for entries with zero count, list only those that belong to current type of message */
 
@@ -1696,11 +1548,11 @@ httpHeaderStoreReport(StoreEntry * e)
                       "id", "name", "#alive", "%err", "%repeat");
 
     // scan heaaderTable and output
-    for (int j = 0; Http::HeaderTable[j].name != nullptr; ++j) {
-        auto stats = headerStatsTable[j];
+    for (auto h : WholeEnum<Http::HdrType>()) {
+        auto stats = headerStatsTable[h];
         storeAppendPrintf(e, "%2d\t %-25s\t %5d\t %6.3f\t %6.3f\n",
-                          Http::HeaderTable[j].id,
-                          Http::HeaderTable[j].name,
+                          Http::HeaderLookupTable.lookup(h).id,
+                          Http::HeaderLookupTable.lookup(h).name,
                           stats.aliveCount,
                           xpercent(stats.errCount, stats.parsCount),
                           xpercent(stats.repCount, stats.seenCount));
@@ -1771,7 +1623,7 @@ HttpHeader::removeHopByHopEntries()
     int headers_deleted = 0;
     while ((e = getEntry(&pos))) {
         Http::HdrType id = e->id;
-        if (CBIT_TEST(HopByHopHeadersMask, id)) {
+        if (Http::HeaderLookupTable.lookup(id).hopbyhop) {
             delAt(pos, headers_deleted);
             CBIT_CLR(mask, id);
         }
index c7a6eb6912436b8fe3ef23465afdd62dee94dc94..e65fcaebbfcd641cdf708c153f558089f43c0944 100644 (file)
@@ -83,7 +83,6 @@ public:
     void append(const HttpHeader * src);
     void update (HttpHeader const *fresh, HttpHeaderMask const *denied_mask);
     void compact();
-    int reset();
     int parse(const char *header_start, size_t len);
     void packInto(Packable * p, bool mask_sensitive_info=false) const;
     HttpHeaderEntry *getEntry(HttpHeaderPos * pos) const;
@@ -98,16 +97,20 @@ public:
     bool getList(Http::HdrType id, String *s) const;
     bool conflictingContentLength() const { return conflictingContentLength_; }
     String getStrOrList(Http::HdrType id) const;
+    String getByName(const SBuf &name) const;
     String getByName(const char *name) const;
+    String getById(Http::HdrType id) const;
+    /// sets value and returns true iff a [possibly empty] field identified by id is there
+    bool getByIdIfPresent(Http::HdrType id, String &result) const;
     /// sets value and returns true iff a [possibly empty] named field is there
-    bool getByNameIfPresent(const char *name, String &value) const;
+    bool getByNameIfPresent(const SBuf &s, String &value) const;
+    bool getByNameIfPresent(const char *name, int namelen, String &value) const;
     String getByNameListMember(const char *name, const char *member, const char separator) const;
     String getListMember(Http::HdrType id, const char *member, const char separator) const;
     int has(Http::HdrType id) const;
     void putInt(Http::HdrType id, int number);
     void putInt64(Http::HdrType id, int64_t number);
     void putTime(Http::HdrType id, time_t htime);
-    void insertTime(Http::HdrType id, time_t htime);
     void putStr(Http::HdrType id, const char *str);
     void putAuth(const char *auth_scheme, const char *realm);
     void putCc(const HttpHdrCc * cc);
@@ -153,8 +156,6 @@ int httpHeaderParseQuotedString(const char *start, const int len, String *val);
 /// quotes string using RFC 7230 quoted-string rules
 SBuf httpHeaderQuoteString(const char *raw);
 
-int httpHeaderHasByNameListMember(const HttpHeader * hdr, const char *name, const char *member, const char separator);
-void httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask * denied_mask);
 void httpHeaderCalcMask(HttpHeaderMask * mask, Http::HdrType http_hdr_type_enums[], size_t count);
 
 inline bool
index 6610c7c9a42198d33a191d5cc3071c18bd098831..eaad3c8880a269c5f05ce6608534de76f869ebf9 100644 (file)
@@ -27,7 +27,7 @@ public:
         busyDestroyedCount(0)
     {
         hdrUCountDistr.enumInit(32);    /* not a real enum */
-        fieldTypeDistr.enumInit(Http::HdrType::ENUM_END);
+        fieldTypeDistr.enumInit(Http::HdrType::enumEnd_);
         ccTypeDistr.enumInit(HttpHdrCcType::CC_ENUM_END);
         scTypeDistr.enumInit(SC_ENUM_END);
     }
@@ -43,7 +43,7 @@ public:
     {
         assert(label);
         hdrUCountDistr.enumInit(32);    /* not a real enum */
-        fieldTypeDistr.enumInit(Http::HdrType::ENUM_END);
+        fieldTypeDistr.enumInit(Http::HdrType::enumEnd_);
         ccTypeDistr.enumInit(HttpHdrCcType::CC_ENUM_END);
         scTypeDistr.enumInit(SC_ENUM_END);
     }
index a8d6ac7dfa84731615c1008deef7a9a8be3cca9f..6a352a0062708c868530c97132b5b7f50d3fc6e2 100644 (file)
@@ -11,6 +11,7 @@
 #include "squid.h"
 #include "acl/FilledChecklist.h"
 #include "acl/Gadgets.h"
+#include "base/EnumIterator.h"
 #include "client_side.h"
 #include "client_side_request.h"
 #include "comm/Connection.h"
@@ -45,21 +46,6 @@ httpHeaderMaskInit(HttpHeaderMask * mask, int value)
     memset(mask, value, sizeof(*mask));
 }
 
-/** calculates a bit mask of a given array; does not reset mask! */
-void
-httpHeaderCalcMask(HttpHeaderMask * mask, Http::HdrType http_hdr_type_enums[], size_t count)
-{
-    size_t i;
-    const int * enums = (const int *) http_hdr_type_enums;
-    assert(mask && enums);
-    assert(count < sizeof(*mask) * 8);  /* check for overflow */
-
-    for (i = 0; i < count; ++i) {
-        assert(!CBIT_TEST(*mask, enums[i]));    /* check for duplicates */
-        CBIT_SET(*mask, enums[i]);
-    }
-}
-
 /* same as httpHeaderPutStr, but formats the string using snprintf first */
 void
 httpHeaderPutStrf(HttpHeader * hdr, Http::HdrType id, const char *fmt,...)
@@ -155,9 +141,12 @@ httpHeaderParseOffset(const char *start, int64_t * value)
 {
     errno = 0;
     int64_t res = strtoll(start, NULL, 10);
-    if (!res && EINVAL == errno)    /* maybe not portable? */
+    if (!res && EINVAL == errno) {   /* maybe not portable? */
+        debugs(66, 7, "failed to parse offset in " << start);
         return 0;
+    }
     *value = res;
+    debugs(66, 7, "offset " << start << " parsed as " << res);
     return 1;
 }
 
@@ -295,13 +284,16 @@ httpHdrMangle(HttpHeaderEntry * e, HttpRequest * request, int req_or_rep)
     }
 
     /* manglers are not configured for this message kind */
-    if (!hms)
+    if (!hms) {
+        debugs(66, 7, "no manglers configured for message kind " << req_or_rep);
         return 1;
+    }
 
     const headerMangler *hm = hms->find(*e);
 
     /* mangler or checklist went away. default allow */
     if (!hm || !hm->access_list) {
+        debugs(66, 7, "couldn't find mangler or access list. Allowing");
         return 1;
     }
 
@@ -309,15 +301,18 @@ httpHdrMangle(HttpHeaderEntry * e, HttpRequest * request, int req_or_rep)
 
     if (checklist.fastCheck() == ACCESS_ALLOWED) {
         /* aclCheckFast returns true for allow. */
+        debugs(66, 7, "checklist for mangler is positive. Mangle");
         retval = 1;
     } else if (NULL == hm->replacement) {
         /* It was denied, and we don't have any replacement */
+        debugs(66, 7, "checklist denied, we have no replacement. Pass");
         retval = 0;
     } else {
         /* It was denied, but we have a replacement. Replace the
          * header on the fly, and return that the new header
          * is allowed.
          */
+        debugs(66, 7, "checklist denied but we have replacement. Replace");
         e->value = hm->replacement;
         retval = 1;
     }
@@ -374,12 +369,11 @@ HeaderManglers::HeaderManglers()
 
 HeaderManglers::~HeaderManglers()
 {
-    for (int i = 0; i < Http::HdrType::ENUM_END; ++i)
+    for (auto i : WholeEnum<Http::HdrType>())
         header_mangler_clean(known[i]);
 
-    typedef ManglersByName::iterator MBNI;
-    for (MBNI i = custom.begin(); i != custom.end(); ++i)
-        header_mangler_clean(i->second);
+    for (auto i : custom)
+        header_mangler_clean(i.second);
 
     header_mangler_clean(all);
 }
@@ -387,13 +381,11 @@ HeaderManglers::~HeaderManglers()
 void
 HeaderManglers::dumpAccess(StoreEntry * entry, const char *name) const
 {
-    for (int i = 0; Http::HeaderTable[i].name != nullptr; ++i) {
-        header_mangler_dump_access(entry, name, known[i], Http::HeaderTable[i].name);
-    }
+    for (auto id : WholeEnum<Http::HdrType>())
+        header_mangler_dump_access(entry, name, known[id], Http::HeaderLookupTable.lookup(id).name);
 
-    typedef ManglersByName::const_iterator MBNCI;
-    for (MBNCI i = custom.begin(); i != custom.end(); ++i)
-        header_mangler_dump_access(entry, name, i->second, i->first.c_str());
+    for (auto i : custom)
+        header_mangler_dump_access(entry, name, i.second, i.first.c_str());
 
     header_mangler_dump_access(entry, name, all, "All");
 }
@@ -401,14 +393,12 @@ HeaderManglers::dumpAccess(StoreEntry * entry, const char *name) const
 void
 HeaderManglers::dumpReplacement(StoreEntry * entry, const char *name) const
 {
-    for (int i = 0; Http::HeaderTable[i].name != nullptr; ++i) {
-        header_mangler_dump_replacement(entry, name, known[i],Http::HeaderTable[i].name);
+    for (auto id : WholeEnum<Http::HdrType>()) {
+        header_mangler_dump_replacement(entry, name, known[id], Http::HeaderLookupTable.lookup(id).name);
     }
 
-    typedef ManglersByName::const_iterator MBNCI;
-    for (MBNCI i = custom.begin(); i != custom.end(); ++i) {
-        header_mangler_dump_replacement(entry, name, i->second,
-                                        i->first.c_str());
+    for (auto i: custom) {
+        header_mangler_dump_replacement(entry, name, i.second, i.first.c_str());
     }
 
     header_mangler_dump_replacement(entry, name, all, "All");
@@ -417,26 +407,18 @@ HeaderManglers::dumpReplacement(StoreEntry * entry, const char *name) const
 headerMangler *
 HeaderManglers::track(const char *name)
 {
-    Http::HdrType id = Http::HeaderLookupTable.lookup(SBuf(name));
+    if (strcmp(name, "All") == 0)
+        return &all;
 
-    if (id == Http::HdrType::BAD_HDR) { // special keyword or a custom header
-        if (strcmp(name, "All") == 0)
-            id = Http::HdrType::ENUM_END;
-        else if (strcmp(name, "Other") == 0)
-            id = Http::HdrType::OTHER;
-    }
+    const Http::HdrType id = Http::HeaderLookupTable.lookup(SBuf(name)).id;
 
-    headerMangler *m = NULL;
-    if (id == Http::HdrType::ENUM_END) {
-        m = &all;
-    } else if (id == Http::HdrType::BAD_HDR) {
-        m = &custom[name];
-    } else {
-        m = &known[id]; // including Http::HdrType::OTHER
-    }
+    if (id != Http::HdrType::BAD_HDR)
+        return &known[id];
+
+    if (strcmp(name, "Other") == 0)
+        return &known[Http::HdrType::OTHER];
 
-    assert(m);
-    return m;
+    return &custom[name];
 }
 
 void
index fd1940dcbb88e1b34b609090574905bfb98bfac2..69375748e502d89ab229ded5967125a92951b4a5 100644 (file)
@@ -73,7 +73,7 @@ private:
     typedef std::map<std::string, headerMangler, NoCaseLessThan> ManglersByName;
 
     /// one mangler for each known header
-    headerMangler known[static_cast<int>(Http::HdrType::ENUM_END)];
+    headerMangler known[static_cast<int>(Http::HdrType::enumEnd_)];
 
     /// one mangler for each custom header
     ManglersByName custom;
index bfeaedf847bd9f0b0fa8a73440eca26f49a1050e..dfd64d29e6e596a17d06adb57f6f909ab15d8998 100644 (file)
@@ -11,6 +11,7 @@
 #include "squid.h"
 #include "acl/AclSizeLimit.h"
 #include "acl/FilledChecklist.h"
+#include "base/EnumIterator.h"
 #include "globals.h"
 #include "HttpBody.h"
 #include "HttpHdrCc.h"
  * The list of headers we don't update is made up of:
  *     all hop-by-hop headers
  *     all entity-headers except Expires and Content-Location
+ *
+ * These headers are now stored in RegisteredHeadersHash.gperf and accessible
+ * as Http::HeaderLookupTable.lookup(id).denied304
  */
 static HttpHeaderMask Denied304HeadersMask;
-static Http::HdrType Denied304HeadersArr[] = {
-    // hop-by-hop headers
-    Http::HdrType::CONNECTION, Http::HdrType::KEEP_ALIVE, Http::HdrType::PROXY_AUTHENTICATE, Http::HdrType::PROXY_AUTHORIZATION,
-    Http::HdrType::TE, Http::HdrType::TRAILER, Http::HdrType::TRANSFER_ENCODING, Http::HdrType::UPGRADE,
-    // entity headers
-    Http::HdrType::ALLOW, Http::HdrType::CONTENT_ENCODING, Http::HdrType::CONTENT_LANGUAGE, Http::HdrType::CONTENT_LENGTH,
-    Http::HdrType::CONTENT_MD5, Http::HdrType::CONTENT_RANGE, Http::HdrType::CONTENT_TYPE, Http::HdrType::LAST_MODIFIED
-};
 
 /* module initialization */
 void
@@ -55,7 +51,11 @@ httpReplyInitModule(void)
 {
     assert(Http::scNone == 0); // HttpReply::parse() interface assumes that
     httpHeaderMaskInit(&Denied304HeadersMask, 0);
-    httpHeaderCalcMask(&Denied304HeadersMask, Denied304HeadersArr, countof(Denied304HeadersArr));
+
+    for (auto id : WholeEnum<Http::HdrType>()) {
+        if (Http::HeaderLookupTable.lookup(id).denied304)
+            CBIT_SET(Denied304HeadersMask, id);
+    }
 }
 
 HttpReply::HttpReply() : HttpMsg(hoReply), date (0), last_modified (0),
@@ -151,9 +151,10 @@ HttpReply::make304() const
     /* rv->keep_alive */
     rv->sline.set(Http::ProtocolVersion(), Http::scNotModified, NULL);
 
-    for (t = 0; ImsEntries[t] != Http::HdrType::OTHER; ++t)
+    for (t = 0; ImsEntries[t] != Http::HdrType::OTHER; ++t) {
         if ((e = header.findEntry(ImsEntries[t])))
             rv->header.addEntry(e->clone());
+    }
 
     /* rv->body */
     return rv;
index 06658734c9f5c763966d5766d01660e068fced68..e9734d4cb748cde0e42a39ace860c00d376966d8 100644 (file)
--- a/src/ICP.h
+++ b/src/ICP.h
@@ -60,14 +60,6 @@ typedef struct _icp_common_t icp_common_t;
 
 #ifdef __cplusplus
 
-/// \ingroup ServerProtocolICPAPI
-inline icp_opcode & operator++ (icp_opcode & aCode)
-{
-    int tmp = (int) aCode;
-    aCode = (icp_opcode) (++tmp);
-    return aCode;
-}
-
 /**
  \ingroup ServerProtocolICPAPI
  \todo mempool this
index 8593d17efa70690c22b404c2867f0d009292c1fd..eb67da24d6eb18832e7343866964e929081c0fd0 100644 (file)
@@ -421,6 +421,8 @@ squid_SOURCES = \
        send-announce.h \
        send-announce.cc \
        $(SBUF_SOURCE) \
+       SBufAlgos.h \
+       SBufAlgos.cc \
        SBufDetailedStats.h \
        SBufDetailedStats.cc \
        SBufStatsAction.h \
@@ -944,6 +946,7 @@ TESTS += $(check_PROGRAMS)
 #      X.h \
 #      X.cc
 #nodist_tests_testX_SOURCES=\
+#   tests/stubs_as_needed.cc\
 #      $(TESTSOURCES)
 #tests_testX_LDFLAGS = $(LIBADD_DL)
 #tests_testX_LDADD=\
@@ -996,6 +999,8 @@ tests_testHttpReply_SOURCES=\
        SquidString.h \
        SquidTime.h \
        $(SBUF_SOURCE) \
+       SBufAlgos.h \
+       SBufAlgos.cc \
        SBufDetailedStats.h \
        tests/stub_SBufDetailedStats.cc \
        String.cc \
@@ -1108,6 +1113,8 @@ tests_testACLMaxUserIP_SOURCES= \
        tests/stub_StatHist.cc \
        stmem.cc \
        $(SBUF_SOURCE) \
+       SBufAlgos.h \
+       SBufAlgos.cc \
        SBufDetailedStats.h \
        tests/stub_SBufDetailedStats.cc \
        String.cc \
@@ -1377,6 +1384,8 @@ tests_testCacheManager_SOURCES = \
        refresh.cc \
        RemovalPolicy.cc \
        $(SBUF_SOURCE) \
+       SBufAlgos.h \
+       SBufAlgos.cc \
        SBufDetailedStats.h \
        tests/stub_SBufDetailedStats.cc \
        $(SNMP_SOURCE) \
@@ -1549,6 +1558,8 @@ tests_testDiskIO_SOURCES = \
        tests/stub_StatHist.cc \
        stmem.cc \
        $(SBUF_SOURCE) \
+       SBufAlgos.h \
+       SBufAlgos.cc \
        SBufDetailedStats.h \
        tests/stub_SBufDetailedStats.cc \
        StoreFileSystem.cc \
@@ -1814,6 +1825,8 @@ tests_testEvent_SOURCES = \
        StrList.h \
        StrList.cc \
        $(SBUF_SOURCE) \
+       SBufAlgos.h \
+       SBufAlgos.cc \
        SBufDetailedStats.h \
        tests/stub_SBufDetailedStats.cc \
        $(SNMP_SOURCE) \
@@ -2055,6 +2068,8 @@ tests_testEventLoop_SOURCES = \
        refresh.h \
        refresh.cc \
        $(SBUF_SOURCE) \
+       SBufAlgos.h \
+       SBufAlgos.cc \
        SBufDetailedStats.h \
        tests/stub_SBufDetailedStats.cc \
        $(SNMP_SOURCE) \
@@ -2294,6 +2309,8 @@ tests_test_http_range_SOURCES = \
        refresh.cc \
        RemovalPolicy.cc \
        $(SBUF_SOURCE) \
+       SBufAlgos.h \
+       SBufAlgos.cc \
        SBufDetailedStats.h \
        tests/stub_SBufDetailedStats.cc \
        $(SNMP_SOURCE) \
@@ -2440,6 +2457,8 @@ tests_testHttp1Parser_SOURCES = \
        cache_cf.h \
        YesNoNone.h \
        $(SBUF_SOURCE) \
+       SBufAlgos.h \
+       SBufAlgos.cc \
        tests/stub_SBufDetailedStats.cc \
        tests/stub_cache_cf.cc \
        tests/stub_cache_manager.cc \
@@ -2617,6 +2636,8 @@ tests_testHttpRequest_SOURCES = \
        refresh.cc \
        RemovalPolicy.cc \
        $(SBUF_SOURCE) \
+       SBufAlgos.h \
+       SBufAlgos.cc \
        SBufDetailedStats.h \
        tests/stub_SBufDetailedStats.cc \
        $(SNMP_SOURCE) \
@@ -2828,6 +2849,8 @@ tests_testStore_SOURCES= \
        store_key_md5.h \
        store_key_md5.cc \
        $(SBUF_SOURCE) \
+       SBufAlgos.h \
+       SBufAlgos.cc \
        SBufDetailedStats.h \
        tests/stub_SBufDetailedStats.cc \
        String.cc \
@@ -3073,6 +3096,8 @@ tests_testUfs_SOURCES = \
        tests/stub_helper.cc \
        cbdata.cc \
        $(SBUF_SOURCE) \
+       SBufAlgos.h \
+       SBufAlgos.cc \
        SBufDetailedStats.h \
        tests/stub_SBufDetailedStats.cc \
        String.cc \
@@ -3251,6 +3276,8 @@ tests_testRock_SOURCES = \
        store_swapmeta.cc \
        store_swapout.cc \
        $(SBUF_SOURCE) \
+       SBufAlgos.h \
+       SBufAlgos.cc \
        SBufDetailedStats.h \
        tests/stub_SBufDetailedStats.cc \
        String.cc \
@@ -3468,6 +3495,8 @@ tests_testURL_SOURCES = \
        refresh.cc \
        RemovalPolicy.cc \
        $(SBUF_SOURCE) \
+       SBufAlgos.h \
+       SBufAlgos.cc \
        SBufDetailedStats.h \
        tests/stub_SBufDetailedStats.cc \
        $(SNMP_SOURCE) \
@@ -3762,7 +3791,9 @@ tests_testLookupTable_SOURCES = \
        tests/stub_SBufDetailedStats.cc \
        base/LookupTable.h \
        String.cc \
-       $(SBUF_SOURCE)
+       $(SBUF_SOURCE) \
+       SBufAlgos.h \
+       SBufAlgos.cc
 nodist_tests_testLookupTable_SOURCES = $(TESTSOURCES)
 tests_testLookupTable_LDFLAGS = $(LIBADD_DL)
 tests_testLookupTable_LDADD = \
index 632b461ca3ea36bd2a80e54a8ff4f98f3e211342..4660d5d1a322b8d447edeb91c246307a74bea6f6 100644 (file)
@@ -47,7 +47,7 @@ ACLHTTPHeaderData::match(HttpHeader* hdr)
             return false;
         value = hdr->getStrOrList(hdrId);
     } else {
-        if (!hdr->getByNameIfPresent(hdrName.termedBuf(), value))
+        if (!hdr->getByNameIfPresent(hdrName, value))
             return false;
     }
 
@@ -76,14 +76,14 @@ ACLHTTPHeaderData::parse()
     char* t = ConfigParser::strtokFile();
     assert (t != NULL);
     hdrName = t;
-    hdrId = Http::HeaderLookupTable.lookup(SBuf(hdrName));
+    hdrId = Http::HeaderLookupTable.lookup(hdrName).id;
     regex_rule->parse();
 }
 
 bool
 ACLHTTPHeaderData::empty() const
 {
-    return (hdrId == Http::HdrType::BAD_HDR && hdrName.size()==0) || regex_rule->empty();
+    return (hdrId == Http::HdrType::BAD_HDR && hdrName.isEmpty()) || regex_rule->empty();
 }
 
 ACLData<HttpHeader*> *
index b41be27ffabc34b58c0d11bdb7b8450e1dbd5069..2f049a77dc55fb8732556d574c2238aef3a91fbe 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "acl/Data.h"
 #include "HttpHeader.h"
+#include "SBuf.h"
 #include "SquidString.h"
 
 class ACLHTTPHeaderData : public ACLData<HttpHeader*>
@@ -27,8 +28,8 @@ public:
     virtual ACLData<HttpHeader*> *clone() const;
 
 private:
-    Http::HdrType hdrId;                /**< set if header is known */
-    String hdrName;                     /**< always set */
+    Http::HdrType hdrId;            /**< set if header is known */
+    SBuf hdrName;                   /**< always set */
     ACLData<char const *> * regex_rule;
 };
 
index 1bba4837ddb9ef1437c4f43ed0a57ae40626e106..5ea70551ec38b6ae4a9dd88f7fb06ccd79b7a779 100644 (file)
@@ -1342,12 +1342,12 @@ void Adaptation::Icap::ModXact::makeRequestHeaders(MemBuf &buf)
     // we must forward "Proxy-Authenticate" and "Proxy-Authorization"
     // as ICAP headers.
     if (virgin.header->header.has(Http::HdrType::PROXY_AUTHENTICATE)) {
-        String vh=virgin.header->header.getByName("Proxy-Authenticate");
+        String vh=virgin.header->header.getById(Http::HdrType::PROXY_AUTHENTICATE);
         buf.appendf("Proxy-Authenticate: " SQUIDSTRINGPH "\r\n",SQUIDSTRINGPRINT(vh));
     }
 
     if (virgin.header->header.has(Http::HdrType::PROXY_AUTHORIZATION)) {
-        String vh=virgin.header->header.getByName("Proxy-Authorization");
+        String vh=virgin.header->header.getById(Http::HdrType::PROXY_AUTHORIZATION);
         buf.appendf("Proxy-Authorization: " SQUIDSTRINGPH "\r\n", SQUIDSTRINGPRINT(vh));
     } else if (request->extacl_user.size() > 0 && request->extacl_passwd.size() > 0) {
         struct base64_encode_ctx ctx;
index 871b24ee700d9332f8640bcae435d030691e3099..1ded1096ccd1fba6f2665cbaa24aef0ca1a38040 100644 (file)
@@ -481,11 +481,11 @@ Auth::UserRequest::addReplyAuthHeader(HttpReply * rep, Auth::UserRequest::Pointe
     default:
         /* Keep GCC happy */
         /* some other HTTP status */
-        type = Http::HdrType::ENUM_END;
+        type = Http::HdrType::BAD_HDR;
         break;
     }
 
-    debugs(29, 9, HERE << "headertype:" << type << " authuser:" << auth_user_request);
+    debugs(29, 9, "headertype:" << type << " authuser:" << auth_user_request);
 
     if (((rep->sline.status() == Http::scProxyAuthenticationRequired)
             || (rep->sline.status() == Http::scUnauthorized)) && internal)
index 4803644be028c7879c6c40c210e60a0133140afd..a4be0f23b96e8eddba3d311f78477a651abbec18 100644 (file)
@@ -10,8 +10,9 @@
 #define SQUID_LOOKUPTABLE_H_
 
 #include "SBuf.h"
+#include "SBufAlgos.h"
 
-#include <map>
+#include <unordered_map>
 
 /**
  * a record in the initializer list for a LookupTable
@@ -53,7 +54,7 @@ public:
     }
 };
 
-template<typename EnumType, typename RecordType = LookupTableRecord<EnumType> >
+template<typename EnumType, typename RecordType = LookupTableRecord<EnumType>, typename Hasher = CaseInsensitiveSBufHash >
 class LookupTable
 {
 public:
@@ -76,7 +77,7 @@ public:
     }
 
 private:
-    typedef std::map<const SBuf, EnumType, SBufCaseInsensitiveLess> lookupTable_t;
+    typedef std::unordered_map<const SBuf, EnumType, Hasher> lookupTable_t;
     lookupTable_t lookupTable;
     EnumType invalidValue;
 };
index 3b870684ee11ab8cc969df2462fab18ffba630bb..1dc49886cf83b80af61d865fb1c48e82e76074b0 100644 (file)
@@ -4609,7 +4609,7 @@ static void parse_HeaderWithAclList(HeaderWithAclList **headers)
     }
     HeaderWithAcl hwa;
     hwa.fieldName = fn;
-    hwa.fieldId = Http::HeaderLookupTable.lookup(SBuf(fn));
+    hwa.fieldId = Http::HeaderLookupTable.lookup(hwa.fieldName).id;
     if (hwa.fieldId == Http::HdrType::BAD_HDR)
         hwa.fieldId = Http::HdrType::OTHER;
 
index c90f16ba8d794b28758fd4acdce5c9f75f8d290e..723e4f231c55577109cd2948f51e432e9fc400a6 100644 (file)
@@ -1353,19 +1353,19 @@ clientReplyContext::buildReplyHeader()
          */
         if (EBIT_TEST(http->storeEntry()->flags, ENTRY_SPECIAL)) {
             hdr->delById(Http::HdrType::DATE);
-            hdr->insertTime(Http::HdrType::DATE, squid_curtime);
+            hdr->putTime(Http::HdrType::DATE, squid_curtime);
         } else if (http->getConn() && http->getConn()->port->actAsOrigin) {
             // Swap the Date: header to current time if we are simulating an origin
             HttpHeaderEntry *h = hdr->findEntry(Http::HdrType::DATE);
             if (h)
                 hdr->putExt("X-Origin-Date", h->value.termedBuf());
             hdr->delById(Http::HdrType::DATE);
-            hdr->insertTime(Http::HdrType::DATE, squid_curtime);
+            hdr->putTime(Http::HdrType::DATE, squid_curtime);
             h = hdr->findEntry(Http::HdrType::EXPIRES);
             if (h && http->storeEntry()->expires >= 0) {
                 hdr->putExt("X-Origin-Expires", h->value.termedBuf());
                 hdr->delById(Http::HdrType::EXPIRES);
-                hdr->insertTime(Http::HdrType::EXPIRES, squid_curtime + http->storeEntry()->expires - http->storeEntry()->timestamp);
+                hdr->putTime(Http::HdrType::EXPIRES, squid_curtime + http->storeEntry()->expires - http->storeEntry()->timestamp);
             }
             if (http->storeEntry()->timestamp <= squid_curtime) {
                 // put X-Cache-Age: instead of Age:
@@ -1404,9 +1404,9 @@ clientReplyContext::buildReplyHeader()
      */
     if ( !hdr->has(Http::HdrType::DATE) ) {
         if (!http->storeEntry())
-            hdr->insertTime(Http::HdrType::DATE, squid_curtime);
+            hdr->putTime(Http::HdrType::DATE, squid_curtime);
         else if (http->storeEntry()->timestamp > 0)
-            hdr->insertTime(Http::HdrType::DATE, http->storeEntry()->timestamp);
+            hdr->putTime(Http::HdrType::DATE, http->storeEntry()->timestamp);
         else {
             debugs(88,DBG_IMPORTANT,"BUG 3279: HTTP reply without Date:");
             /* dump something useful about the problem */
index 70fbd6f247bd884f6823d87a2cec398259590fc2..db22c204b3b1a50edfcb519c552b48a0451e4921 100644 (file)
@@ -250,7 +250,7 @@ parse_header_token(external_acl_format::Pointer format, char *header, const Form
     }
 
     format->header = xstrdup(header);
-    format->header_id = Http::HeaderLookupTable.lookup(SBuf(header));
+    format->header_id = Http::HeaderLookupTable.lookup(SBuf(header)).id;
 }
 
 void
index df6eecbc4c3be3ec5577eb8112641db536d879eb..26a50f82d7c6a8a02c9b1f15a73135d0fb96db0b 100644 (file)
@@ -853,7 +853,7 @@ htcpTstReply(htcpDataHeader * dhdr, StoreEntry * e, htcpSpecifier * spec, Ip::Ad
         stuff.D.respHdrsSz = mb.contentSize();
         debugs(31, 3, "htcpTstReply: resp_hdrs = {" << stuff.D.resp_hdrs << "}");
         mb.reset();
-        hdr.reset();
+        hdr.clean();
 
         if (e && e->expires > -1)
             hdr.putTime(Http::HdrType::EXPIRES, e->expires);
@@ -869,8 +869,7 @@ htcpTstReply(htcpDataHeader * dhdr, StoreEntry * e, htcpSpecifier * spec, Ip::Ad
         debugs(31, 3, "htcpTstReply: entity_hdrs = {" << stuff.D.entity_hdrs << "}");
 
         mb.reset();
-
-        hdr.reset();
+        hdr.clean();
 
 #if USE_ICMP
         if (char *host = urlHostname(spec->uri)) {
index 33ea69a3346d7009d19f8ba9843f3bc21a36bd05..912bb467687d34f110973be6f77b3ee0e91e9a80 100644 (file)
@@ -589,22 +589,16 @@ httpMakeVaryMark(HttpRequest * request, HttpReply const * reply)
     vary = reply->header.getList(Http::HdrType::VARY);
 
     while (strListGetItem(&vary, ',', &item, &ilen, &pos)) {
-        char *name = (char *)xmalloc(ilen + 1);
-        xstrncpy(name, item, ilen + 1);
-        Tolower(name);
-
-        if (strcmp(name, "*") == 0) {
-            /* Can not handle "Vary: *" withtout ETag support */
-            safe_free(name);
+        static const SBuf asterisk("*");
+        SBuf name(item, ilen);
+        if (name == asterisk) {
             vstr.clean();
             break;
         }
-
-        strListAdd(&vstr, name, ',');
+        name.toLower();
+        strListAdd(&vstr, name.c_str(), ',');
         hdr = request->header.getByName(name);
-        safe_free(name);
         value = hdr.termedBuf();
-
         if (value) {
             value = rfc1738_escape_part(value);
             vstr.append("=\"", 2);
index 6561ef67ca43def3d59fc20c123b302d271c58f6..03cff1ef68f2879115b19fbac2125c9eef30578d 100644 (file)
@@ -20,6 +20,8 @@ libsquid_http_la_SOURCES = \
        ProtocolVersion.h \
        RegisteredHeaders.h \
        RegisteredHeaders.cc \
+       RegisteredHeadersHash.cci \
+       RegisteredHeadersHash.gperf \
        RequestMethod.cc \
        RequestMethod.h \
        StatusCode.cc \
@@ -33,4 +35,7 @@ MethodType.cc: MethodType.h $(top_srcdir)/src/mk-string-arrays.awk
        ($(AWK) -f $(top_srcdir)/src/mk-string-arrays.awk sbuf=1 < $(srcdir)/MethodType.h | \
                sed -e 's%METHOD_%%' -e 's%_C%-C%' >$@) || ($(RM) -f $@ && exit 1)
 
+RegisteredHeadersHash.cci: RegisteredHeadersHash.gperf
+       gperf --output-file=$@ -m 100000 $<
+
 CLEANFILES += MethodType.cc
index e8f220f607da85434f90fbb04d87837e3fe64ed8..349f3337312abb47b55e7cfd26622a545f653735 100644 (file)
 #include "RegisteredHeaders.h"
 
 #include <ostream>
+#include <vector>
 
 namespace Http
 {
-/*
- * A table with major attributes for every known field.
- *
- * Invariant on this table:
- * for each index in HeaderTable, (int)HeaderTable[index] = index
- *
- * To be kept in sync with Http::HdrType
- */
-const HeaderTableRecord HeaderTable[] = {
-    {"Accept", Http::HdrType::ACCEPT, Http::HdrFieldType::ftStr},
-    {"Accept-Charset", Http::HdrType::ACCEPT_CHARSET, Http::HdrFieldType::ftStr},
-    {"Accept-Encoding", Http::HdrType::ACCEPT_ENCODING, Http::HdrFieldType::ftStr},
-    {"Accept-Language", Http::HdrType::ACCEPT_LANGUAGE, Http::HdrFieldType::ftStr},
-    {"Accept-Ranges", Http::HdrType::ACCEPT_RANGES, Http::HdrFieldType::ftStr},
-    {"Age", Http::HdrType::AGE, Http::HdrFieldType::ftInt},
-    {"Allow", Http::HdrType::ALLOW, Http::HdrFieldType::ftStr},
-    {"Alternate-Protocol", Http::HdrType::ALTERNATE_PROTOCOL, Http::HdrFieldType::ftStr},
-    {"Authentication-Info", Http::HdrType::AUTHENTICATION_INFO, Http::HdrFieldType::ftStr},
-    {"Authorization", Http::HdrType::AUTHORIZATION, Http::HdrFieldType::ftStr},    /* for now */
-    {"Cache-Control", Http::HdrType::CACHE_CONTROL, Http::HdrFieldType::ftPCc},
-    {"Connection", Http::HdrType::CONNECTION, Http::HdrFieldType::ftStr},
-    {"Content-Base", Http::HdrType::CONTENT_BASE, Http::HdrFieldType::ftStr},
-    {"Content-Disposition", Http::HdrType::CONTENT_DISPOSITION, Http::HdrFieldType::ftStr},  /* for now */
-    {"Content-Encoding", Http::HdrType::CONTENT_ENCODING, Http::HdrFieldType::ftStr},
-    {"Content-Language", Http::HdrType::CONTENT_LANGUAGE, Http::HdrFieldType::ftStr},
-    {"Content-Length", Http::HdrType::CONTENT_LENGTH, Http::HdrFieldType::ftInt64},
-    {"Content-Location", Http::HdrType::CONTENT_LOCATION, Http::HdrFieldType::ftStr},
-    {"Content-MD5", Http::HdrType::CONTENT_MD5, Http::HdrFieldType::ftStr},    /* for now */
-    {"Content-Range", Http::HdrType::CONTENT_RANGE, Http::HdrFieldType::ftPContRange},
-    {"Content-Type", Http::HdrType::CONTENT_TYPE, Http::HdrFieldType::ftStr},
-    {"Cookie", Http::HdrType::COOKIE, Http::HdrFieldType::ftStr},
-    {"Cookie2", Http::HdrType::COOKIE2, Http::HdrFieldType::ftStr},
-    {"Date", Http::HdrType::DATE, Http::HdrFieldType::ftDate_1123},
-    {"ETag", Http::HdrType::ETAG, Http::HdrFieldType::ftETag},
-    {"Expect", Http::HdrType::EXPECT, Http::HdrFieldType::ftStr},
-    {"Expires", Http::HdrType::EXPIRES, Http::HdrFieldType::ftDate_1123},
-    {"Forwarded", Http::HdrType::FORWARDED, Http::HdrFieldType::ftStr},
-    {"From", Http::HdrType::FROM, Http::HdrFieldType::ftStr},
-    {"Host", Http::HdrType::HOST, Http::HdrFieldType::ftStr},
-    {"HTTP2-Settings", Http::HdrType::HTTP2_SETTINGS, Http::HdrFieldType::ftStr}, /* for now */
-    {"If-Match", Http::HdrType::IF_MATCH, Http::HdrFieldType::ftStr},  /* for now */
-    {"If-Modified-Since", Http::HdrType::IF_MODIFIED_SINCE, Http::HdrFieldType::ftDate_1123},
-    {"If-None-Match", Http::HdrType::IF_NONE_MATCH, Http::HdrFieldType::ftStr},    /* for now */
-    {"If-Range", Http::HdrType::IF_RANGE, Http::HdrFieldType::ftDate_1123_or_ETag},
-    {"If-Unmodified-Since", Http::HdrType::IF_UNMODIFIED_SINCE, Http::HdrFieldType::ftDate_1123},
-    {"Keep-Alive", Http::HdrType::KEEP_ALIVE, Http::HdrFieldType::ftStr},
-    {"Key", Http::HdrType::KEY, Http::HdrFieldType::ftStr},
-    {"Last-Modified", Http::HdrType::LAST_MODIFIED, Http::HdrFieldType::ftDate_1123},
-    {"Link", Http::HdrType::LINK, Http::HdrFieldType::ftStr},
-    {"Location", Http::HdrType::LOCATION, Http::HdrFieldType::ftStr},
-    {"Max-Forwards", Http::HdrType::MAX_FORWARDS, Http::HdrFieldType::ftInt64},
-    {"Mime-Version", Http::HdrType::MIME_VERSION, Http::HdrFieldType::ftStr},  /* for now */
-    {"Negotiate", Http::HdrType::NEGOTIATE, Http::HdrFieldType::ftStr},
-    {"Origin", Http::HdrType::ORIGIN, Http::HdrFieldType::ftStr},
-    {"Pragma", Http::HdrType::PRAGMA, Http::HdrFieldType::ftStr},
-    {"Proxy-Authenticate", Http::HdrType::PROXY_AUTHENTICATE, Http::HdrFieldType::ftStr},
-    {"Proxy-Authentication-Info", Http::HdrType::PROXY_AUTHENTICATION_INFO, Http::HdrFieldType::ftStr},
-    {"Proxy-Authorization", Http::HdrType::PROXY_AUTHORIZATION, Http::HdrFieldType::ftStr},
-    {"Proxy-Connection", Http::HdrType::PROXY_CONNECTION, Http::HdrFieldType::ftStr},
-    {"Proxy-support", Http::HdrType::PROXY_SUPPORT, Http::HdrFieldType::ftStr},
-    {"Public", Http::HdrType::PUBLIC, Http::HdrFieldType::ftStr},
-    {"Range", Http::HdrType::RANGE, Http::HdrFieldType::ftPRange},
-    {"Referer", Http::HdrType::REFERER, Http::HdrFieldType::ftStr},
-    {"Request-Range", Http::HdrType::REQUEST_RANGE, Http::HdrFieldType::ftPRange}, /* usually matches Http::HdrType::RANGE */
-    {"Retry-After", Http::HdrType::RETRY_AFTER, Http::HdrFieldType::ftStr},    /* for now (Http::HdrFieldType::ftDate_1123 or Http::HdrFieldType::ftInt!} */
-    {"Server", Http::HdrType::SERVER, Http::HdrFieldType::ftStr},
-    {"Set-Cookie", Http::HdrType::SET_COOKIE, Http::HdrFieldType::ftStr},
-    {"Set-Cookie2", Http::HdrType::SET_COOKIE2, Http::HdrFieldType::ftStr},
-    {"TE", Http::HdrType::TE, Http::HdrFieldType::ftStr},
-    {"Title", Http::HdrType::TITLE, Http::HdrFieldType::ftStr},
-    {"Trailer", Http::HdrType::TRAILER, Http::HdrFieldType::ftStr},
-    {"Transfer-Encoding", Http::HdrType::TRANSFER_ENCODING, Http::HdrFieldType::ftStr},
-    {"Translate", Http::HdrType::TRANSLATE, Http::HdrFieldType::ftStr},    /* for now. may need to crop */
-    {"Unless-Modified-Since", Http::HdrType::UNLESS_MODIFIED_SINCE, Http::HdrFieldType::ftStr},  /* for now ignore. may need to crop */
-    {"Upgrade", Http::HdrType::UPGRADE, Http::HdrFieldType::ftStr},    /* for now */
-    {"User-Agent", Http::HdrType::USER_AGENT, Http::HdrFieldType::ftStr},
-    {"Vary", Http::HdrType::VARY, Http::HdrFieldType::ftStr},  /* for now */
-    {"Via", Http::HdrType::VIA, Http::HdrFieldType::ftStr},    /* for now */
-    {"Warning", Http::HdrType::WARNING, Http::HdrFieldType::ftStr},    /* for now */
-    {"WWW-Authenticate", Http::HdrType::WWW_AUTHENTICATE, Http::HdrFieldType::ftStr},
-    {"X-Cache", Http::HdrType::X_CACHE, Http::HdrFieldType::ftStr},
-    {"X-Cache-Lookup", Http::HdrType::X_CACHE_LOOKUP, Http::HdrFieldType::ftStr},
-    {"X-Forwarded-For", Http::HdrType::X_FORWARDED_FOR, Http::HdrFieldType::ftStr},
-    {"X-Request-URI", Http::HdrType::X_REQUEST_URI, Http::HdrFieldType::ftStr},
-    {"X-Squid-Error", Http::HdrType::X_SQUID_ERROR, Http::HdrFieldType::ftStr},
-#if X_ACCELERATOR_VARY
-    {"X-Accelerator-Vary", Http::HdrType::HDR_X_ACCELERATOR_VARY, Http::HdrFieldType::ftStr},
-#endif
-#if USE_ADAPTATION
-    {"X-Next-Services", Http::HdrType::X_NEXT_SERVICES, Http::HdrFieldType::ftStr},
-#endif
-    {"Surrogate-Capability", Http::HdrType::SURROGATE_CAPABILITY, Http::HdrFieldType::ftStr},
-    {"Surrogate-Control", Http::HdrType::SURROGATE_CONTROL, Http::HdrFieldType::ftPSc},
-    {"Front-End-Https", Http::HdrType::FRONT_END_HTTPS, Http::HdrFieldType::ftStr},
-    {"FTP-Command", Http::HdrType::FTP_COMMAND, Http::HdrFieldType::ftStr},
-    {"FTP-Arguments", Http::HdrType::FTP_ARGUMENTS, Http::HdrFieldType::ftStr},
-    {"FTP-Pre", Http::HdrType::FTP_PRE, Http::HdrFieldType::ftStr},
-    {"FTP-Status", Http::HdrType::FTP_STATUS, Http::HdrFieldType::ftInt},
-    {"FTP-Reason", Http::HdrType::FTP_REASON, Http::HdrFieldType::ftStr},
-    {"Other:", Http::HdrType::OTHER, Http::HdrFieldType::ftStr},    /* ':' will not allow matches */
-    {"*INVALID*:", Http::HdrType::BAD_HDR, Http::HdrFieldType::ftInvalid}, /* ':' will not allow matches */
-    {nullptr, Http::HdrType::ENUM_END, Http::HdrFieldType::ftInvalid}    /* end of table */
-};
+/* glue to code generated by gperf */
+#include "http/RegisteredHeadersHash.cci"
+
+HeaderTableRecord::HeaderTableRecord() :
+    name(""), id(HdrType::BAD_HDR),type(HdrFieldType::ftInvalid),
+    list(false), request(false), reply(false), hopbyhop(false)
+{}
+
+HeaderTableRecord::HeaderTableRecord(const char *n) :
+    name(n), id(HdrType::BAD_HDR), type(HdrFieldType::ftInvalid),
+    list(false), request(false), reply(false), hopbyhop(false)
+{}
+
+HeaderTableRecord::HeaderTableRecord(const char *n, HdrType theId, HdrFieldType theType, int theKind) :
+    name(n), id(theId), type(theType),
+    list(theKind & HdrKind::ListHeader), request(theKind & HdrKind::RequestHeader),
+    reply(theKind & HdrKind::ReplyHeader), hopbyhop(theKind & HdrKind::HopByHopHeader),
+    denied304(theKind & HdrKind::Denied304Header)
+{}
 
-const LookupTable<Http::HdrType, HeaderTableRecord> HeaderLookupTable(Http::HdrType::BAD_HDR, HeaderTable);
+const HeaderTableRecord&
+HeaderLookupTable_t::lookup (const char *buf, const std::size_t len) const {
+    const HeaderTableRecord *r = HttpHeaderHashTable::lookup(buf, len);
+    if (!r)
+        return BadHdr;
+    return *r;
+}
+const HeaderTableRecord HeaderLookupTable_t::BadHdr {"*INVALID*:", Http::HdrType::BAD_HDR, Http::HdrFieldType::ftInvalid, HdrKind::None};
+
+HeaderLookupTable_t::HeaderLookupTable_t()
+{
+    initCache();
+}
+
+void
+HeaderLookupTable_t::initCache()
+{
+    idCache.resize(TOTAL_KEYWORDS);
+    for (int j = MIN_HASH_VALUE; j <= MAX_HASH_VALUE; ++j) { //MAX_HASH_VALUE is exported by gperf
+        if (HttpHeaderDefinitionsTable[j].name[0] != '\0') { //some slots are empty
+            idCache[static_cast<int>(HttpHeaderDefinitionsTable[j].id)] =
+                & HttpHeaderDefinitionsTable[j];
+        }
+    }
+    //check after the fact. The cache array must be full
+    for (auto e : idCache) {
+        assert(e->name);
+    }
+}
+const HeaderLookupTable_t HeaderLookupTable;
 
 }; /* namespace Http */
 
@@ -125,7 +71,7 @@ std::ostream&
 operator<< (std::ostream &s, Http::HdrType id)
 {
     if (Http::any_HdrType_enum_value(id))
-        s << Http::HeaderTable[id].name << '[' << static_cast<int>(id) << ']';
+        s << Http::HeaderLookupTable.lookup(id).name << '[' << static_cast<int>(id) << ']';
     else
         s << "Invalid-Header[" << static_cast<int>(id) << ']';
     return s;
index 3c4f2febdedf5f29710979733e1e44ed10247a62..5bab8ce780a4d632398a262ea49521d7fbb644d6 100644 (file)
@@ -17,7 +17,8 @@ namespace Http
 /// recognized or "known" header fields; and the RFC which defines them (or not)
 /// http://www.iana.org/assignments/message-headers/message-headers.xhtml
 enum HdrType {
-    ACCEPT = 0,                     /**< RFC 7231 */ /* MUST BE FIRST */
+    enumBegin_ = 0,                 // service value for WholeEnum iteration
+    ACCEPT = enumBegin_,            /**< RFC 7231 */ /* MUST BE FIRST */
     ACCEPT_CHARSET,                 /**< RFC 7231 */
     ACCEPT_ENCODING,                /**< RFC 7231 */
     /*ACCEPT_FEATURES,*/            /* RFC 2295 */
@@ -105,12 +106,8 @@ enum HdrType {
     X_FORWARDED_FOR,                /**< obsolete Squid custom header, RFC 7239 */
     X_REQUEST_URI,                  /**< Squid custom header appended if ADD_X_REQUEST_URI is defined */
     X_SQUID_ERROR,                  /**< Squid custom header on generated error responses */
-#if X_ACCELERATOR_VARY
     HDR_X_ACCELERATOR_VARY,             /**< obsolete Squid custom header. */
-#endif
-#if USE_ADAPTATION
     X_NEXT_SERVICES,                /**< Squid custom ICAP header */
-#endif
     SURROGATE_CAPABILITY,           /**< Edge Side Includes (ESI) header */
     SURROGATE_CONTROL,              /**< Edge Side Includes (ESI) header */
     FRONT_END_HTTPS,                /**< MS Exchange custom header we may have to add */
@@ -120,8 +117,8 @@ enum HdrType {
     FTP_STATUS,                     /**< Internal header for FTP reply status */
     FTP_REASON,                     /**< Internal header for FTP reply reason */
     OTHER,                          /**< internal tag value for "unknown" headers */
-    BAD_HDR,                        /**< Invalid header. Must be after ENUM_END */
-    ENUM_END                        /**< internal tag for end-of-headers */
+    BAD_HDR,                        /**< Invalid header */
+    enumEnd_                        // internal tag for end-of-headers
 };
 
 /** possible types for http header fields */
@@ -139,31 +136,74 @@ enum class HdrFieldType {
     ftDate_1123_or_ETag
 };
 
+enum HdrKind {
+    None = 0,
+    ListHeader = 1,
+    RequestHeader = 1 << 1,
+    ReplyHeader = 1 << 2,
+    HopByHopHeader = 1 << 3,
+    Denied304Header = 1 << 4, //see comment in HttpReply.cc for meaning
+    GeneralHeader = RequestHeader | ReplyHeader,
+    EntityHeader = RequestHeader | ReplyHeader
+};
+
 /* POD for HeaderTable */
 class HeaderTableRecord {
+public:
+    HeaderTableRecord();
+    HeaderTableRecord(const char *n);
+    HeaderTableRecord(const char *, Http::HdrType, Http::HdrFieldType, int /* HdrKind */);
+
 public:
     const char *name;
     Http::HdrType id;
     Http::HdrFieldType type;
+    // flags set by constructor from HdrKind parameter
+    bool list;       ///<header with field values defined as #(values) in HTTP/1.1
+    bool request;    ///<header is a request header
+    bool reply;      ///<header is a reply header
+    bool hopbyhop;   ///<header is hop by hop
+    bool denied304;  ///<header is not to be updated on receiving a 304 in cache revalidation (see HttpReply.cc)
 };
 
-/// header ID->namelookup table.
-extern const HeaderTableRecord HeaderTable[];
-
-/** LookupTable for HTTP Header name -> Http::HdrType lookup.
+/** Class for looking up registered header definitions
  *
- * use as HeaderLookupTable.lookup(header-as-sbuf).
- * It will return Http::HdrType::HDR_BAD if the header is unknown/not registered,
- * including the case of Http::HdrType::OTHER, which will have to be handled
- * by the caller.
+ * Look up HeaderTableRecord's by name or registered header ID.
+ *
+ * Actual records are defined in file RegisteredHeadersHash.gperf, which is
+ * compiled using gperf to RegisteredHeadersHash.cci which is then included
+ * in RegisteredHeaders.cc.
  */
-extern const LookupTable<Http::HdrType, HeaderTableRecord> HeaderLookupTable;
+class HeaderLookupTable_t {
+public:
+    HeaderLookupTable_t();
+    /// look record type up by name (C-string and length)
+    const HeaderTableRecord& lookup (const char *buf, const std::size_t len) const;
+    /// look record type up by name (std::string)
+    const HeaderTableRecord& lookup (const std::string &key) const {
+        return lookup(key.data(), key.length());
+    }
+    /// look record type up by name (SBuf)
+    const HeaderTableRecord& lookup (const SBuf &key) const {
+        return lookup(key.rawContent(), key.length());
+    }
+    /// look record type up by header ID
+    const HeaderTableRecord& lookup (Http::HdrType id) const {
+        return *(idCache[static_cast<int>(id)]);
+    }
+
+private:
+    void initCache();
+    std::vector<const HeaderTableRecord *> idCache;
+    static const HeaderTableRecord BadHdr; ///<used to signal "not found" from lookups
+};
+extern const HeaderLookupTable_t HeaderLookupTable;
 
 /// match any known header type, including OTHER and BAD
 inline bool
 any_HdrType_enum_value (const Http::HdrType id)
 {
-    return (id >= Http::HdrType::ACCEPT && id < Http::HdrType::ENUM_END);
+    return (id >= Http::HdrType::enumBegin_ && id < Http::HdrType::enumEnd_);
 }
 
 /// match any valid header type, including OTHER but not BAD
diff --git a/src/http/RegisteredHeadersHash.cci b/src/http/RegisteredHeadersHash.cci
new file mode 100644 (file)
index 0000000..a7ec442
--- /dev/null
@@ -0,0 +1,381 @@
+/* C++ code produced by gperf version 3.0.4 */
+/* Command-line: gperf --output-file=RegisteredHeadersHash.cci -m 100000 RegisteredHeadersHash.gperf  */
+/* Computed positions: -k'1,9,$' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+#line 1 "RegisteredHeadersHash.gperf"
+
+/* AUTO GENERATED FROM RegisteredHeadersHash.gperf. DO NOT EDIT */
+
+/*
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+#line 24 "RegisteredHeadersHash.gperf"
+struct HeaderTableRecord;
+enum
+  {
+    TOTAL_KEYWORDS = 88,
+    MIN_WORD_LENGTH = 2,
+    MAX_WORD_LENGTH = 25,
+    MIN_HASH_VALUE = 7,
+    MAX_HASH_VALUE = 113
+  };
+
+/* maximum key range = 107, duplicates = 0 */
+
+#ifndef GPERF_DOWNCASE
+#define GPERF_DOWNCASE 1
+static unsigned char gperf_downcase[256] =
+  {
+      0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
+     15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,
+     30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,
+     45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,
+     60,  61,  62,  63,  64,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106,
+    107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
+    122,  91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104,
+    105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+    120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
+    135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+    150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
+    165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+    180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
+    195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
+    210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
+    225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+    240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
+    255
+  };
+#endif
+
+#ifndef GPERF_CASE_MEMCMP
+#define GPERF_CASE_MEMCMP 1
+static int
+gperf_case_memcmp (register const char *s1, register const char *s2, register unsigned int n)
+{
+  for (; n > 0;)
+    {
+      unsigned char c1 = gperf_downcase[(unsigned char)*s1++];
+      unsigned char c2 = gperf_downcase[(unsigned char)*s2++];
+      if (c1 == c2)
+        {
+          n--;
+          continue;
+        }
+      return (int)c1 - (int)c2;
+    }
+  return 0;
+}
+#endif
+
+class HttpHeaderHashTable
+{
+private:
+  static inline unsigned int HttpHeaderHash (const char *str, unsigned int len);
+public:
+  static const struct HeaderTableRecord *lookup (const char *str, unsigned int len);
+};
+
+inline unsigned int
+HttpHeaderHashTable::HttpHeaderHash (register const char *str, register unsigned int len)
+{
+  static const unsigned char asso_values[] =
+    {
+      114, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+      114, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+      114, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+      114, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+      114, 114,  14, 114, 114,   5, 114, 114, 114, 114,
+       64, 114, 114,  14, 114, 114, 114, 114,   1, 114,
+      114, 114, 114, 114, 114,   4,   5,  15,  29,   1,
+       17,  60,  35,  19, 114,  51,  15,  42,   8,  50,
+       11, 114,   1,  19,   7,  28,   4,  41,  33,  15,
+      114, 114, 114, 114, 114, 114, 114,   4,   5,  15,
+       29,   1,  17,  60,  35,  19, 114,  51,  15,  42,
+        8,  50,  11, 114,   1,  19,   7,  28,   4,  41,
+       33,  15, 114, 114, 114, 114, 114, 114, 114, 114,
+      114, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+      114, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+      114, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+      114, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+      114, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+      114, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+      114, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+      114, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+      114, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+      114, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+      114, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+      114, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+      114, 114, 114, 114, 114, 114
+    };
+  register int hval = len;
+
+  switch (hval)
+    {
+      default:
+        hval += asso_values[(unsigned char)str[8]];
+      /*FALLTHROUGH*/
+      case 8:
+      case 7:
+      case 6:
+      case 5:
+      case 4:
+      case 3:
+      case 2:
+      case 1:
+        hval += asso_values[(unsigned char)str[0]];
+        break;
+    }
+  return hval + asso_values[(unsigned char)str[len - 1]];
+}
+
+static const unsigned char lengthtable[] =
+  {
+     0,  0,  0,  0,  0,  0,  0,  5,  3,  7,  2,  3,  0,  5,
+     6,  7, 13,  6,  9,  9, 11,  6,  6,  4, 15,  7,  6,  7,
+     8, 13, 13,  8,  6, 12,  4, 12,  7, 18, 18, 10, 13,  7,
+    13, 16,  0, 19,  4, 16, 13, 10,  5, 13, 17, 10, 16, 20,
+    17,  6, 19, 16, 14, 11,  8,  4,  6,  4, 10, 18, 15,  3,
+     4, 19, 13, 14, 10, 14, 13, 12, 15, 14, 15, 12, 11, 10,
+     9, 10,  7, 15, 19, 17,  0, 13, 16, 25,  0,  0,  0,  0,
+     0,  0, 21,  0,  0,  0,  0,  0,  0,  0,  7, 13,  0,  0,
+     0, 11
+  };
+
+static const struct HeaderTableRecord HttpHeaderDefinitionsTable[] =
+  {
+    {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 78 "RegisteredHeadersHash.gperf"
+    {"Range", Http::HdrType::RANGE, Http::HdrFieldType::ftPRange, HdrKind::RequestHeader},
+#line 31 "RegisteredHeadersHash.gperf"
+    {"Age", Http::HdrType::AGE, Http::HdrFieldType::ftInt, HdrKind::ReplyHeader},
+#line 79 "RegisteredHeadersHash.gperf"
+    {"Referer", Http::HdrType::REFERER, Http::HdrFieldType::ftStr, HdrKind::RequestHeader},
+#line 85 "RegisteredHeadersHash.gperf"
+    {"TE", Http::HdrType::TE, Http::HdrFieldType::ftStr, HdrKind::RequestHeader|HdrKind::HopByHopHeader|HdrKind::Denied304Header},
+#line 94 "RegisteredHeadersHash.gperf"
+    {"Via", Http::HdrType::VIA, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::GeneralHeader},
+    {""},
+#line 86 "RegisteredHeadersHash.gperf"
+    {"Title", Http::HdrType::TITLE, Http::HdrFieldType::ftStr, HdrKind::None},
+#line 51 "RegisteredHeadersHash.gperf"
+    {"Expect", Http::HdrType::EXPECT, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::RequestHeader},
+#line 87 "RegisteredHeadersHash.gperf"
+    {"Trailer", Http::HdrType::TRAILER, Http::HdrFieldType::ftStr, HdrKind::HopByHopHeader|HdrKind::Denied304Header},
+#line 80 "RegisteredHeadersHash.gperf"
+    {"Request-Range", Http::HdrType::REQUEST_RANGE, Http::HdrFieldType::ftPRange, HdrKind::None},
+#line 26 "RegisteredHeadersHash.gperf"
+    {"Accept", Http::HdrType::ACCEPT, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::RequestHeader},
+#line 89 "RegisteredHeadersHash.gperf"
+    {"Translate", Http::HdrType::TRANSLATE, Http::HdrFieldType::ftStr, HdrKind::None},
+#line 69 "RegisteredHeadersHash.gperf"
+    {"Negotiate", Http::HdrType::NEGOTIATE, Http::HdrFieldType::ftStr, HdrKind::None},
+#line 81 "RegisteredHeadersHash.gperf"
+    {"Retry-After", Http::HdrType::RETRY_AFTER, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader},
+#line 71 "RegisteredHeadersHash.gperf"
+    {"Pragma", Http::HdrType::PRAGMA, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::GeneralHeader},
+#line 47 "RegisteredHeadersHash.gperf"
+    {"Cookie", Http::HdrType::COOKIE, Http::HdrFieldType::ftStr, HdrKind::None},
+#line 93 "RegisteredHeadersHash.gperf"
+    {"Vary", Http::HdrType::VARY, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::ReplyHeader},
+#line 29 "RegisteredHeadersHash.gperf"
+    {"Accept-Language", Http::HdrType::ACCEPT_LANGUAGE, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::RequestHeader},
+#line 109 "RegisteredHeadersHash.gperf"
+    {"FTP-Pre", Http::HdrType::FTP_PRE, Http::HdrFieldType::ftStr, HdrKind::None},
+#line 82 "RegisteredHeadersHash.gperf"
+    {"Server", Http::HdrType::SERVER, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader},
+#line 52 "RegisteredHeadersHash.gperf"
+    {"Expires", Http::HdrType::EXPIRES, Http::HdrFieldType::ftDate_1123, HdrKind::EntityHeader},
+#line 60 "RegisteredHeadersHash.gperf"
+    {"If-Range", Http::HdrType::IF_RANGE, Http::HdrFieldType::ftDate_1123_or_ETag, HdrKind::None},
+#line 35 "RegisteredHeadersHash.gperf"
+    {"Authorization", Http::HdrType::AUTHORIZATION, Http::HdrFieldType::ftStr, HdrKind::RequestHeader},
+#line 45 "RegisteredHeadersHash.gperf"
+    {"Content-Range", Http::HdrType::CONTENT_RANGE, Http::HdrFieldType::ftPContRange, HdrKind::EntityHeader|HdrKind::Denied304Header},
+#line 66 "RegisteredHeadersHash.gperf"
+    {"Location", Http::HdrType::LOCATION, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader},
+#line 77 "RegisteredHeadersHash.gperf"
+    {"Public", Http::HdrType::PUBLIC, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader},
+#line 38 "RegisteredHeadersHash.gperf"
+    {"Content-Base", Http::HdrType::CONTENT_BASE, Http::HdrFieldType::ftStr, HdrKind::EntityHeader},
+#line 49 "RegisteredHeadersHash.gperf"
+    {"Date", Http::HdrType::DATE, Http::HdrFieldType::ftDate_1123, HdrKind::GeneralHeader},
+#line 46 "RegisteredHeadersHash.gperf"
+    {"Content-Type", Http::HdrType::CONTENT_TYPE, Http::HdrFieldType::ftStr, HdrKind::EntityHeader|HdrKind::Denied304Header},
+#line 91 "RegisteredHeadersHash.gperf"
+    {"Upgrade", Http::HdrType::UPGRADE, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::GeneralHeader|HdrKind::HopByHopHeader|HdrKind::Denied304Header},
+#line 72 "RegisteredHeadersHash.gperf"
+    {"Proxy-Authenticate", Http::HdrType::PROXY_AUTHENTICATE, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader|HdrKind::Denied304Header},
+#line 33 "RegisteredHeadersHash.gperf"
+    {"Alternate-Protocol", Http::HdrType::ALTERNATE_PROTOCOL, Http::HdrFieldType::ftStr, HdrKind::HopByHopHeader},
+#line 113 "RegisteredHeadersHash.gperf"
+    {"*INVALID*:", Http::HdrType::BAD_HDR, Http::HdrFieldType::ftInvalid, HdrKind::None},
+#line 30 "RegisteredHeadersHash.gperf"
+    {"Accept-Ranges", Http::HdrType::ACCEPT_RANGES, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::ReplyHeader},
+#line 97 "RegisteredHeadersHash.gperf"
+    {"X-Cache", Http::HdrType::X_CACHE, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader},
+#line 76 "RegisteredHeadersHash.gperf"
+    {"Proxy-support", Http::HdrType::PROXY_SUPPORT, Http::HdrFieldType::ftStr, HdrKind::ListHeader},
+#line 75 "RegisteredHeadersHash.gperf"
+    {"Proxy-Connection", Http::HdrType::PROXY_CONNECTION, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::GeneralHeader|HdrKind::HopByHopHeader},
+    {""},
+#line 74 "RegisteredHeadersHash.gperf"
+    {"Proxy-Authorization", Http::HdrType::PROXY_AUTHORIZATION, Http::HdrFieldType::ftStr, HdrKind::RequestHeader|HdrKind::HopByHopHeader|HdrKind::Denied304Header},
+#line 55 "RegisteredHeadersHash.gperf"
+    {"Host", Http::HdrType::HOST, Http::HdrFieldType::ftStr, HdrKind::RequestHeader},
+#line 41 "RegisteredHeadersHash.gperf"
+    {"Content-Language", Http::HdrType::CONTENT_LANGUAGE, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::EntityHeader|HdrKind::Denied304Header},
+#line 101 "RegisteredHeadersHash.gperf"
+    {"X-Squid-Error", Http::HdrType::X_SQUID_ERROR, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader},
+#line 83 "RegisteredHeadersHash.gperf"
+    {"Set-Cookie", Http::HdrType::SET_COOKIE, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader},
+#line 32 "RegisteredHeadersHash.gperf"
+    {"Allow", Http::HdrType::ALLOW, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::EntityHeader|HdrKind::Denied304Header},
+#line 36 "RegisteredHeadersHash.gperf"
+    {"Cache-Control", Http::HdrType::CACHE_CONTROL, Http::HdrFieldType::ftPCc, HdrKind::ListHeader|HdrKind::GeneralHeader},
+#line 105 "RegisteredHeadersHash.gperf"
+    {"Surrogate-Control", Http::HdrType::SURROGATE_CONTROL, Http::HdrFieldType::ftPSc, HdrKind::ListHeader|HdrKind::ReplyHeader},
+#line 92 "RegisteredHeadersHash.gperf"
+    {"User-Agent", Http::HdrType::USER_AGENT, Http::HdrFieldType::ftStr, HdrKind::RequestHeader},
+#line 43 "RegisteredHeadersHash.gperf"
+    {"Content-Location", Http::HdrType::CONTENT_LOCATION, Http::HdrFieldType::ftStr, HdrKind::EntityHeader},
+#line 104 "RegisteredHeadersHash.gperf"
+    {"Surrogate-Capability", Http::HdrType::SURROGATE_CAPABILITY, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::RequestHeader},
+#line 58 "RegisteredHeadersHash.gperf"
+    {"If-Modified-Since", Http::HdrType::IF_MODIFIED_SINCE, Http::HdrFieldType::ftDate_1123, HdrKind::RequestHeader},
+#line 112 "RegisteredHeadersHash.gperf"
+    {"Other:", Http::HdrType::OTHER, Http::HdrFieldType::ftStr, HdrKind::EntityHeader},
+#line 61 "RegisteredHeadersHash.gperf"
+    {"If-Unmodified-Since", Http::HdrType::IF_UNMODIFIED_SINCE, Http::HdrFieldType::ftDate_1123, HdrKind::None},
+#line 96 "RegisteredHeadersHash.gperf"
+    {"WWW-Authenticate", Http::HdrType::WWW_AUTHENTICATE, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::ReplyHeader},
+#line 27 "RegisteredHeadersHash.gperf"
+    {"Accept-Charset", Http::HdrType::ACCEPT_CHARSET, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::RequestHeader},
+#line 107 "RegisteredHeadersHash.gperf"
+    {"FTP-Command", Http::HdrType::FTP_COMMAND, Http::HdrFieldType::ftStr, HdrKind::None},
+#line 57 "RegisteredHeadersHash.gperf"
+    {"If-Match", Http::HdrType::IF_MATCH, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::RequestHeader},
+#line 54 "RegisteredHeadersHash.gperf"
+    {"From", Http::HdrType::FROM, Http::HdrFieldType::ftStr, HdrKind::RequestHeader},
+#line 70 "RegisteredHeadersHash.gperf"
+    {"Origin", Http::HdrType::ORIGIN, Http::HdrFieldType::ftStr, HdrKind::RequestHeader},
+#line 50 "RegisteredHeadersHash.gperf"
+    {"ETag", Http::HdrType::ETAG, Http::HdrFieldType::ftETag, HdrKind::EntityHeader},
+#line 62 "RegisteredHeadersHash.gperf"
+    {"Keep-Alive", Http::HdrType::KEEP_ALIVE, Http::HdrFieldType::ftStr, HdrKind::HopByHopHeader|HdrKind::Denied304Header},
+#line 102 "RegisteredHeadersHash.gperf"
+    {"X-Accelerator-Vary", Http::HdrType::HDR_X_ACCELERATOR_VARY, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::ReplyHeader},
+#line 103 "RegisteredHeadersHash.gperf"
+    {"X-Next-Services", Http::HdrType::X_NEXT_SERVICES, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::ReplyHeader},
+#line 63 "RegisteredHeadersHash.gperf"
+    {"Key", Http::HdrType::KEY, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::ReplyHeader},
+#line 65 "RegisteredHeadersHash.gperf"
+    {"Link", Http::HdrType::LINK, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::EntityHeader},
+#line 39 "RegisteredHeadersHash.gperf"
+    {"Content-Disposition", Http::HdrType::CONTENT_DISPOSITION, Http::HdrFieldType::ftStr, HdrKind::None},
+#line 100 "RegisteredHeadersHash.gperf"
+    {"X-Request-URI", Http::HdrType::X_REQUEST_URI, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader},
+#line 98 "RegisteredHeadersHash.gperf"
+    {"X-Cache-Lookup", Http::HdrType::X_CACHE_LOOKUP, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader},
+#line 110 "RegisteredHeadersHash.gperf"
+    {"FTP-Status", Http::HdrType::FTP_STATUS, Http::HdrFieldType::ftInt, HdrKind::None},
+#line 56 "RegisteredHeadersHash.gperf"
+    {"HTTP2-Settings", Http::HdrType::HTTP2_SETTINGS, Http::HdrFieldType::ftStr, HdrKind::RequestHeader|HdrKind::HopByHopHeader},
+#line 64 "RegisteredHeadersHash.gperf"
+    {"Last-Modified", Http::HdrType::LAST_MODIFIED, Http::HdrFieldType::ftDate_1123, HdrKind::EntityHeader|HdrKind::Denied304Header},
+#line 67 "RegisteredHeadersHash.gperf"
+    {"Max-Forwards", Http::HdrType::MAX_FORWARDS, Http::HdrFieldType::ftInt64, HdrKind::RequestHeader},
+#line 99 "RegisteredHeadersHash.gperf"
+    {"X-Forwarded-For", Http::HdrType::X_FORWARDED_FOR, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::GeneralHeader},
+#line 42 "RegisteredHeadersHash.gperf"
+    {"Content-Length", Http::HdrType::CONTENT_LENGTH, Http::HdrFieldType::ftInt64, HdrKind::EntityHeader|HdrKind::Denied304Header},
+#line 106 "RegisteredHeadersHash.gperf"
+    {"Front-End-Https", Http::HdrType::FRONT_END_HTTPS, Http::HdrFieldType::ftStr, HdrKind::None},
+#line 68 "RegisteredHeadersHash.gperf"
+    {"Mime-Version", Http::HdrType::MIME_VERSION, Http::HdrFieldType::ftStr, HdrKind::GeneralHeader},
+#line 44 "RegisteredHeadersHash.gperf"
+    {"Content-MD5", Http::HdrType::CONTENT_MD5, Http::HdrFieldType::ftStr, HdrKind::EntityHeader|HdrKind::Denied304Header},
+#line 37 "RegisteredHeadersHash.gperf"
+    {"Connection", Http::HdrType::CONNECTION, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::GeneralHeader|HdrKind::HopByHopHeader|HdrKind::Denied304Header},
+#line 53 "RegisteredHeadersHash.gperf"
+    {"Forwarded", Http::HdrType::FORWARDED, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::GeneralHeader},
+#line 111 "RegisteredHeadersHash.gperf"
+    {"FTP-Reason", Http::HdrType::FTP_REASON, Http::HdrFieldType::ftStr, HdrKind::None},
+#line 48 "RegisteredHeadersHash.gperf"
+    {"Cookie2", Http::HdrType::COOKIE2, Http::HdrFieldType::ftStr, HdrKind::None},
+#line 28 "RegisteredHeadersHash.gperf"
+    {"Accept-Encoding", Http::HdrType::ACCEPT_ENCODING, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::RequestHeader|HdrKind::ReplyHeader},
+#line 34 "RegisteredHeadersHash.gperf"
+    {"Authentication-Info", Http::HdrType::AUTHENTICATION_INFO, Http::HdrFieldType::ftStr, HdrKind::ListHeader},
+#line 88 "RegisteredHeadersHash.gperf"
+    {"Transfer-Encoding", Http::HdrType::TRANSFER_ENCODING, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::GeneralHeader|HdrKind::HopByHopHeader|HdrKind::Denied304Header},
+    {""},
+#line 108 "RegisteredHeadersHash.gperf"
+    {"FTP-Arguments", Http::HdrType::FTP_ARGUMENTS, Http::HdrFieldType::ftStr, HdrKind::None},
+#line 40 "RegisteredHeadersHash.gperf"
+    {"Content-Encoding", Http::HdrType::CONTENT_ENCODING, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::EntityHeader|HdrKind::Denied304Header},
+#line 73 "RegisteredHeadersHash.gperf"
+    {"Proxy-Authentication-Info", Http::HdrType::PROXY_AUTHENTICATION_INFO, Http::HdrFieldType::ftStr, HdrKind::ListHeader},
+    {""}, {""}, {""}, {""}, {""}, {""},
+#line 90 "RegisteredHeadersHash.gperf"
+    {"Unless-Modified-Since", Http::HdrType::UNLESS_MODIFIED_SINCE, Http::HdrFieldType::ftStr, HdrKind::None},
+    {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 95 "RegisteredHeadersHash.gperf"
+    {"Warning", Http::HdrType::WARNING, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::ReplyHeader},
+#line 59 "RegisteredHeadersHash.gperf"
+    {"If-None-Match", Http::HdrType::IF_NONE_MATCH, Http::HdrFieldType::ftStr, HdrKind::ListHeader},
+    {""}, {""}, {""},
+#line 84 "RegisteredHeadersHash.gperf"
+    {"Set-Cookie2", Http::HdrType::SET_COOKIE2, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader}
+  };
+
+const struct HeaderTableRecord *
+HttpHeaderHashTable::lookup (register const char *str, register unsigned int len)
+{
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      register int key = HttpHeaderHash (str, len);
+
+      if (key <= MAX_HASH_VALUE && key >= 0)
+        if (len == lengthtable[key])
+          {
+            register const char *s = HttpHeaderDefinitionsTable[key].name;
+
+            if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_memcmp (str, s, len))
+              return &HttpHeaderDefinitionsTable[key];
+          }
+    }
+  return 0;
+}
+#line 114 "RegisteredHeadersHash.gperf"
+
diff --git a/src/http/RegisteredHeadersHash.gperf b/src/http/RegisteredHeadersHash.gperf
new file mode 100644 (file)
index 0000000..c041a5d
--- /dev/null
@@ -0,0 +1,114 @@
+%{
+/* AUTO GENERATED FROM RegisteredHeadersHash.gperf. DO NOT EDIT */
+
+/*
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+%}
+%language=C++
+%define hash-function-name HttpHeaderHash
+%define lookup-function-name lookup
+%define class-name HttpHeaderHashTable
+%define word-array-name HttpHeaderDefinitionsTable
+%compare-lengths
+%compare-strncmp
+%readonly-tables
+%enum
+%global-table
+%ignore-case
+%struct-type 
+struct HeaderTableRecord;
+%%
+Accept, Http::HdrType::ACCEPT, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::RequestHeader
+Accept-Charset, Http::HdrType::ACCEPT_CHARSET, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::RequestHeader
+Accept-Encoding, Http::HdrType::ACCEPT_ENCODING, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::RequestHeader|HdrKind::ReplyHeader
+Accept-Language, Http::HdrType::ACCEPT_LANGUAGE, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::RequestHeader
+Accept-Ranges, Http::HdrType::ACCEPT_RANGES, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::ReplyHeader
+Age, Http::HdrType::AGE, Http::HdrFieldType::ftInt, HdrKind::ReplyHeader
+Allow, Http::HdrType::ALLOW, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::EntityHeader|HdrKind::Denied304Header
+Alternate-Protocol, Http::HdrType::ALTERNATE_PROTOCOL, Http::HdrFieldType::ftStr, HdrKind::HopByHopHeader
+Authentication-Info, Http::HdrType::AUTHENTICATION_INFO, Http::HdrFieldType::ftStr, HdrKind::ListHeader
+Authorization, Http::HdrType::AUTHORIZATION, Http::HdrFieldType::ftStr, HdrKind::RequestHeader
+Cache-Control, Http::HdrType::CACHE_CONTROL, Http::HdrFieldType::ftPCc, HdrKind::ListHeader|HdrKind::GeneralHeader
+Connection, Http::HdrType::CONNECTION, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::GeneralHeader|HdrKind::HopByHopHeader|HdrKind::Denied304Header
+Content-Base, Http::HdrType::CONTENT_BASE, Http::HdrFieldType::ftStr, HdrKind::EntityHeader
+Content-Disposition, Http::HdrType::CONTENT_DISPOSITION, Http::HdrFieldType::ftStr, HdrKind::None
+Content-Encoding, Http::HdrType::CONTENT_ENCODING, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::EntityHeader|HdrKind::Denied304Header
+Content-Language, Http::HdrType::CONTENT_LANGUAGE, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::EntityHeader|HdrKind::Denied304Header
+Content-Length, Http::HdrType::CONTENT_LENGTH, Http::HdrFieldType::ftInt64, HdrKind::EntityHeader|HdrKind::Denied304Header
+Content-Location, Http::HdrType::CONTENT_LOCATION, Http::HdrFieldType::ftStr, HdrKind::EntityHeader
+Content-MD5, Http::HdrType::CONTENT_MD5, Http::HdrFieldType::ftStr, HdrKind::EntityHeader|HdrKind::Denied304Header
+Content-Range, Http::HdrType::CONTENT_RANGE, Http::HdrFieldType::ftPContRange, HdrKind::EntityHeader|HdrKind::Denied304Header
+Content-Type, Http::HdrType::CONTENT_TYPE, Http::HdrFieldType::ftStr, HdrKind::EntityHeader|HdrKind::Denied304Header
+Cookie, Http::HdrType::COOKIE, Http::HdrFieldType::ftStr, HdrKind::None
+Cookie2, Http::HdrType::COOKIE2, Http::HdrFieldType::ftStr, HdrKind::None
+Date, Http::HdrType::DATE, Http::HdrFieldType::ftDate_1123, HdrKind::GeneralHeader
+ETag, Http::HdrType::ETAG, Http::HdrFieldType::ftETag, HdrKind::EntityHeader
+Expect, Http::HdrType::EXPECT, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::RequestHeader
+Expires, Http::HdrType::EXPIRES, Http::HdrFieldType::ftDate_1123, HdrKind::EntityHeader
+Forwarded, Http::HdrType::FORWARDED, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::GeneralHeader
+From, Http::HdrType::FROM, Http::HdrFieldType::ftStr, HdrKind::RequestHeader
+Host, Http::HdrType::HOST, Http::HdrFieldType::ftStr, HdrKind::RequestHeader
+HTTP2-Settings, Http::HdrType::HTTP2_SETTINGS, Http::HdrFieldType::ftStr, HdrKind::RequestHeader|HdrKind::HopByHopHeader
+If-Match, Http::HdrType::IF_MATCH, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::RequestHeader
+If-Modified-Since, Http::HdrType::IF_MODIFIED_SINCE, Http::HdrFieldType::ftDate_1123, HdrKind::RequestHeader
+If-None-Match, Http::HdrType::IF_NONE_MATCH, Http::HdrFieldType::ftStr, HdrKind::ListHeader
+If-Range, Http::HdrType::IF_RANGE, Http::HdrFieldType::ftDate_1123_or_ETag, HdrKind::None
+If-Unmodified-Since, Http::HdrType::IF_UNMODIFIED_SINCE, Http::HdrFieldType::ftDate_1123, HdrKind::None
+Keep-Alive, Http::HdrType::KEEP_ALIVE, Http::HdrFieldType::ftStr, HdrKind::HopByHopHeader|HdrKind::Denied304Header
+Key, Http::HdrType::KEY, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::ReplyHeader
+Last-Modified, Http::HdrType::LAST_MODIFIED, Http::HdrFieldType::ftDate_1123, HdrKind::EntityHeader|HdrKind::Denied304Header
+Link, Http::HdrType::LINK, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::EntityHeader
+Location, Http::HdrType::LOCATION, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader
+Max-Forwards, Http::HdrType::MAX_FORWARDS, Http::HdrFieldType::ftInt64, HdrKind::RequestHeader
+Mime-Version, Http::HdrType::MIME_VERSION, Http::HdrFieldType::ftStr, HdrKind::GeneralHeader
+Negotiate, Http::HdrType::NEGOTIATE, Http::HdrFieldType::ftStr, HdrKind::None
+Origin, Http::HdrType::ORIGIN, Http::HdrFieldType::ftStr, HdrKind::RequestHeader
+Pragma, Http::HdrType::PRAGMA, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::GeneralHeader
+Proxy-Authenticate, Http::HdrType::PROXY_AUTHENTICATE, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader|HdrKind::Denied304Header
+Proxy-Authentication-Info, Http::HdrType::PROXY_AUTHENTICATION_INFO, Http::HdrFieldType::ftStr, HdrKind::ListHeader
+Proxy-Authorization, Http::HdrType::PROXY_AUTHORIZATION, Http::HdrFieldType::ftStr, HdrKind::RequestHeader|HdrKind::HopByHopHeader|HdrKind::Denied304Header
+Proxy-Connection, Http::HdrType::PROXY_CONNECTION, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::GeneralHeader|HdrKind::HopByHopHeader
+Proxy-support, Http::HdrType::PROXY_SUPPORT, Http::HdrFieldType::ftStr, HdrKind::ListHeader
+Public, Http::HdrType::PUBLIC, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader
+Range, Http::HdrType::RANGE, Http::HdrFieldType::ftPRange, HdrKind::RequestHeader
+Referer, Http::HdrType::REFERER, Http::HdrFieldType::ftStr, HdrKind::RequestHeader
+Request-Range, Http::HdrType::REQUEST_RANGE, Http::HdrFieldType::ftPRange, HdrKind::None
+Retry-After, Http::HdrType::RETRY_AFTER, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader
+Server, Http::HdrType::SERVER, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader
+Set-Cookie, Http::HdrType::SET_COOKIE, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader
+Set-Cookie2, Http::HdrType::SET_COOKIE2, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader
+TE, Http::HdrType::TE, Http::HdrFieldType::ftStr, HdrKind::RequestHeader|HdrKind::HopByHopHeader|HdrKind::Denied304Header
+Title, Http::HdrType::TITLE, Http::HdrFieldType::ftStr, HdrKind::None
+Trailer, Http::HdrType::TRAILER, Http::HdrFieldType::ftStr, HdrKind::HopByHopHeader|HdrKind::Denied304Header
+Transfer-Encoding, Http::HdrType::TRANSFER_ENCODING, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::GeneralHeader|HdrKind::HopByHopHeader|HdrKind::Denied304Header
+Translate, Http::HdrType::TRANSLATE, Http::HdrFieldType::ftStr, HdrKind::None
+Unless-Modified-Since, Http::HdrType::UNLESS_MODIFIED_SINCE, Http::HdrFieldType::ftStr, HdrKind::None
+Upgrade, Http::HdrType::UPGRADE, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::GeneralHeader|HdrKind::HopByHopHeader|HdrKind::Denied304Header
+User-Agent, Http::HdrType::USER_AGENT, Http::HdrFieldType::ftStr, HdrKind::RequestHeader
+Vary, Http::HdrType::VARY, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::ReplyHeader
+Via, Http::HdrType::VIA, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::GeneralHeader
+Warning, Http::HdrType::WARNING, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::ReplyHeader
+WWW-Authenticate, Http::HdrType::WWW_AUTHENTICATE, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::ReplyHeader
+X-Cache, Http::HdrType::X_CACHE, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader
+X-Cache-Lookup, Http::HdrType::X_CACHE_LOOKUP, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader
+X-Forwarded-For, Http::HdrType::X_FORWARDED_FOR, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::GeneralHeader
+X-Request-URI, Http::HdrType::X_REQUEST_URI, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader
+X-Squid-Error, Http::HdrType::X_SQUID_ERROR, Http::HdrFieldType::ftStr, HdrKind::ReplyHeader
+X-Accelerator-Vary, Http::HdrType::HDR_X_ACCELERATOR_VARY, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::ReplyHeader
+X-Next-Services, Http::HdrType::X_NEXT_SERVICES, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::ReplyHeader
+Surrogate-Capability, Http::HdrType::SURROGATE_CAPABILITY, Http::HdrFieldType::ftStr, HdrKind::ListHeader|HdrKind::RequestHeader
+Surrogate-Control, Http::HdrType::SURROGATE_CONTROL, Http::HdrFieldType::ftPSc, HdrKind::ListHeader|HdrKind::ReplyHeader
+Front-End-Https, Http::HdrType::FRONT_END_HTTPS, Http::HdrFieldType::ftStr, HdrKind::None
+FTP-Command, Http::HdrType::FTP_COMMAND, Http::HdrFieldType::ftStr, HdrKind::None
+FTP-Arguments, Http::HdrType::FTP_ARGUMENTS, Http::HdrFieldType::ftStr, HdrKind::None
+FTP-Pre, Http::HdrType::FTP_PRE, Http::HdrFieldType::ftStr, HdrKind::None
+FTP-Status, Http::HdrType::FTP_STATUS, Http::HdrFieldType::ftInt, HdrKind::None
+FTP-Reason, Http::HdrType::FTP_REASON, Http::HdrFieldType::ftStr, HdrKind::None
+Other:, Http::HdrType::OTHER, Http::HdrFieldType::ftStr, HdrKind::EntityHeader
+*INVALID*:, Http::HdrType::BAD_HDR, Http::HdrFieldType::ftInvalid, HdrKind::None
+%%