# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: kinkie@squid-cache.org-20150804110958-nbylc2flp8w7wtjq
# target_branch: file:///home/kinkie/squid/workspace/trunk/
# testament_sha1: e91daba083afe2e39b8533a8aaf432195d741d9f
# timestamp: 2015-08-04 13:11:22 +0200
# base_revision_id: squid3@treenet.co.nz-20150804053235-\
#   t8mam58ktdj02b2b
# 
# Begin patch
=== modified file 'src/HttpHdrCc.cc'
--- src/HttpHdrCc.cc	2015-03-05 06:44:43 +0000
+++ src/HttpHdrCc.cc	2015-08-03 13:56:30 +0000
@@ -9,6 +9,7 @@
 /* DEBUG: section 65    HTTP Cache Control Header */
 
 #include "squid.h"
+#include "base/LookupTable.h"
 #include "HttpHdrCc.h"
 #include "HttpHeader.h"
 #include "HttpHeaderFieldStat.h"
@@ -21,46 +22,28 @@
 #include "util.h"
 
 #include <map>
-
-/* a row in the table used for parsing cache control header and statistics */
-class HttpHeaderCcFields
-{
-public:
-    HttpHeaderCcFields() : name(NULL), id(CC_BADHDR), stat() {}
-    HttpHeaderCcFields(const char *aName, http_hdr_cc_type aTypeId) : name(aName), id(aTypeId) {}
-    HttpHeaderCcFields(const HttpHeaderCcFields &f) : name(f.name), id(f.id) {}
-    // nothing to do as name is a pointer to global static string
-    ~HttpHeaderCcFields() {}
-
-    const char *name;
-    http_hdr_cc_type id;
-    HttpHeaderFieldStat stat;
-
-private:
-    HttpHeaderCcFields &operator =(const HttpHeaderCcFields &); // not implemented
-};
-
-/* order must match that of enum http_hdr_cc_type. The constraint is verified at initialization time */
-static HttpHeaderCcFields CcAttrs[CC_ENUM_END] = {
-    HttpHeaderCcFields("public", CC_PUBLIC),
-    HttpHeaderCcFields("private", CC_PRIVATE),
-    HttpHeaderCcFields("no-cache", CC_NO_CACHE),
-    HttpHeaderCcFields("no-store", CC_NO_STORE),
-    HttpHeaderCcFields("no-transform", CC_NO_TRANSFORM),
-    HttpHeaderCcFields("must-revalidate", CC_MUST_REVALIDATE),
-    HttpHeaderCcFields("proxy-revalidate", CC_PROXY_REVALIDATE),
-    HttpHeaderCcFields("max-age", CC_MAX_AGE),
-    HttpHeaderCcFields("s-maxage", CC_S_MAXAGE),
-    HttpHeaderCcFields("max-stale", CC_MAX_STALE),
-    HttpHeaderCcFields("min-fresh", CC_MIN_FRESH),
-    HttpHeaderCcFields("only-if-cached", CC_ONLY_IF_CACHED),
-    HttpHeaderCcFields("stale-if-error", CC_STALE_IF_ERROR),
-    HttpHeaderCcFields("Other,", CC_OTHER) /* ',' will protect from matches */
-};
-
-/// Map an header name to its type, to expedite parsing
-typedef std::map<const SBuf,http_hdr_cc_type> CcNameToIdMap_t;
-static CcNameToIdMap_t CcNameToIdMap;
+#include <vector>
+
+// invariant: row[j].id == j
+static LookupTable<http_hdr_cc_type>::Record CcAttrs[] = {
+    {"public", CC_PUBLIC},
+    {"private", CC_PRIVATE},
+    {"no-cache", CC_NO_CACHE},
+    {"no-store", CC_NO_STORE},
+    {"no-transform", CC_NO_TRANSFORM},
+    {"must-revalidate", CC_MUST_REVALIDATE},
+    {"proxy-revalidate", CC_PROXY_REVALIDATE},
+    {"max-age", CC_MAX_AGE},
+    {"s-maxage", CC_S_MAXAGE},
+    {"max-stale", CC_MAX_STALE},
+    {"min-fresh", CC_MIN_FRESH},
+    {"only-if-cached", CC_ONLY_IF_CACHED},
+    {"stale-if-error", CC_STALE_IF_ERROR},
+    {"Other,", CC_OTHER}, /* ',' will protect from matches */
+    {nullptr, CC_ENUM_END}
+};
+LookupTable<http_hdr_cc_type> ccLookupTable(CC_OTHER,CcAttrs);
+std::vector<HttpHeaderFieldStat> ccHeaderStats(CC_ENUM_END);
 
 /// used to walk a table of http_header_cc_type structs
 http_hdr_cc_type &operator++ (http_hdr_cc_type &aHeader)
@@ -74,12 +57,9 @@
 void
 httpHdrCcInitModule(void)
 {
-    /* build lookup and accounting structures */
-    for (int32_t i = 0; i < CC_ENUM_END; ++i) {
-        const HttpHeaderCcFields &f=CcAttrs[i];
-        assert(i == f.id); /* verify assumption: the id is the key into the array */
-        const SBuf k(f.name);
-        CcNameToIdMap[k]=f.id;
+    // check invariant on initialization table
+    for (int j = 0; CcAttrs[j].name != nullptr; ++j) {
+        assert (CcAttrs[j].id == j);
     }
 }
 
@@ -87,7 +67,6 @@
 void
 httpHdrCcCleanModule(void)
 {
-    // HdrCcNameToIdMap is self-cleaning
 }
 
 void
@@ -102,7 +81,6 @@
     const char *item;
     const char *p;      /* '=' parameter */
     const char *pos = NULL;
-    http_hdr_cc_type type;
     int ilen;
     int nlen;
 
@@ -119,17 +97,13 @@
         }
 
         /* find type */
-        const CcNameToIdMap_t::const_iterator i=CcNameToIdMap.find(SBuf(item,nlen));
-        if (i==CcNameToIdMap.end())
-            type=CC_OTHER;
-        else
-            type=i->second;
+        const http_hdr_cc_type type = ccLookupTable.lookup(SBuf(item,nlen));
 
         // ignore known duplicate directives
         if (isSet(type)) {
             if (type != CC_OTHER) {
                 debugs(65, 2, "hdr cc: ignoring duplicate cache-directive: near '" << item << "' in '" << str << "'");
-                ++CcAttrs[type].stat.repCount;
+                ++ ccHeaderStats[type].repCount;
                 continue;
             }
         }
@@ -300,10 +274,9 @@
 void
 httpHdrCcUpdateStats(const HttpHdrCc * cc, StatHist * hist)
 {
-    http_hdr_cc_type c;
     assert(cc);
 
-    for (c = CC_PUBLIC; c < CC_ENUM_END; ++c)
+    for (http_hdr_cc_type c = CC_PUBLIC; c < CC_ENUM_END; ++c)
         if (cc->isSet(c))
             hist->count(c);
 }
@@ -312,8 +285,8 @@
 httpHdrCcStatDumper(StoreEntry * sentry, int, double val, double, int count)
 {
     extern const HttpHeaderStat *dump_stat; /* argh! */
-    const int id = (int) val;
-    const int valid_id = id >= 0 && id < CC_ENUM_END;
+    const int id = static_cast<int>(val);
+    const int valid_id = id < CC_ENUM_END;
     const char *name = valid_id ? CcAttrs[id].name : "INVALID";
 
     if (count || valid_id)

=== modified file 'src/HttpHdrSc.cc'
--- src/HttpHdrSc.cc	2015-05-26 18:12:08 +0000
+++ src/HttpHdrSc.cc	2015-08-02 19:40:58 +0000
@@ -9,9 +9,9 @@
 /* DEBUG: section 90    HTTP Cache Control Header */
 
 #include "squid.h"
+#include "base/LookupTable.h"
 #include "HttpHdrSc.h"
 #include "HttpHeader.h"
-#include "HttpHeaderFieldInfo.h"
 #include "HttpHeaderFieldStat.h"
 #include "HttpHeaderStat.h"
 #include "HttpHeaderTools.h"
@@ -20,52 +20,41 @@
 #include "util.h"
 
 #include <map>
-
-/* a row in the table used for parsing surrogate-control header and statistics */
-typedef struct {
-    const char *name;
-    http_hdr_sc_type id;
-    HttpHeaderFieldStat stat;
-} HttpHeaderScFields;
+#include <vector>
 
 /* this table is used for parsing surrogate control header */
 /* order must match that of enum http_hdr_sc_type. The constraint is verified at initialization time */
 //todo: implement constraint
-static const HttpHeaderFieldAttrs ScAttrs[SC_ENUM_END] = {
-    HttpHeaderFieldAttrs("no-store", (http_hdr_type)SC_NO_STORE),
-    HttpHeaderFieldAttrs("no-store-remote", (http_hdr_type)SC_NO_STORE_REMOTE),
-    HttpHeaderFieldAttrs("max-age", (http_hdr_type)SC_MAX_AGE),
-    HttpHeaderFieldAttrs("content", (http_hdr_type)SC_CONTENT),
-    HttpHeaderFieldAttrs("Other,", (http_hdr_type)SC_OTHER) /* ',' will protect from matches */
+static const LookupTable<http_hdr_sc_type>::Record ScAttrs[] {
+    {"no-store", SC_NO_STORE},
+    {"no-store-remote", SC_NO_STORE_REMOTE},
+    {"max-age", SC_MAX_AGE},
+    {"content", SC_CONTENT},
+    {"Other,", SC_OTHER}, /* ',' will protect from matches */
+    {nullptr, SC_ENUM_END} /* SC_ENUM_END taken as invalid value */
 };
-
-HttpHeaderFieldInfo *ScFieldsInfo = NULL;
-
+LookupTable<http_hdr_sc_type> scLookupTable(SC_ENUM_END, ScAttrs);
+std::vector<HttpHeaderFieldStat> scHeaderStats(SC_ENUM_END);
+
+// used when iterating over flags
 http_hdr_sc_type &operator++ (http_hdr_sc_type &aHeader)
 {
-    int tmp = (int)aHeader;
-    aHeader = (http_hdr_sc_type)(++tmp);
+    int tmp = static_cast<int>(aHeader);
+    aHeader = static_cast<http_hdr_sc_type>(++tmp);
     return aHeader;
 }
 
-int operator - (http_hdr_sc_type const &anSc, http_hdr_sc_type const &anSc2)
-{
-    return (int)anSc - (int)anSc2;
-}
-
-/* module initialization */
-
 void
 httpHdrScInitModule(void)
 {
-    ScFieldsInfo = httpHeaderBuildFieldsInfo(ScAttrs, SC_ENUM_END);
+    // check invariant on ScAttrs
+    for (int i = 0; ScAttrs[i].name != nullptr; ++i)
+        assert(i == ScAttrs[i].id);
 }
 
 void
 httpHdrScCleanModule(void)
 {
-    httpHeaderDestroyFieldsInfo(ScFieldsInfo, SC_ENUM_END);
-    ScFieldsInfo = NULL;
 }
 
 /* implementation */
@@ -94,7 +83,7 @@
     const char *pos = NULL;
     const char *target = NULL; /* ;foo */
     const char *temp = NULL; /* temp buffer */
-    int type;
+    http_hdr_sc_type type;
     int ilen, vlen;
     int initiallen;
     HttpHdrScTarget *sct;
@@ -120,11 +109,9 @@
         }
 
         /* find type */
-        /* TODO: use a type-safe map-based lookup */
-        type = httpHeaderIdByName(item, ilen,
-                                  ScFieldsInfo, SC_ENUM_END);
+        type = scLookupTable.lookup(SBuf(item,ilen));
 
-        if (type < 0) {
+        if (type == SC_ENUM_END) {
             debugs(90, 2, "hdr sc: unknown control-directive: near '" << item << "' in '" << str << "'");
             type = SC_OTHER;
         }
@@ -147,11 +134,11 @@
 
         safe_free (temp);
 
-        if (sct->isSet(static_cast<http_hdr_sc_type>(type))) {
+        if (sct->isSet(type)) {
             if (type != SC_OTHER)
                 debugs(90, 2, "hdr sc: ignoring duplicate control-directive: near '" << item << "' in '" << str << "'");
 
-            ++ ScFieldsInfo[type].stat.repCount;
+            ++ scHeaderStats[type].repCount;
 
             continue;
         }
@@ -245,8 +232,7 @@
         if (isSet(flag) && flag != SC_OTHER) {
 
             /* print option name */
-            p->appendf((pcount ? ", " SQUIDSTRINGPH : SQUIDSTRINGPH),
-                       SQUIDSTRINGPRINT(ScFieldsInfo[flag].name));
+            p->appendf((pcount ? ", %s" : "%s"), ScAttrs[flag].name);
 
             /* handle options with values */
 
@@ -307,8 +293,8 @@
 {
     extern const HttpHeaderStat *dump_stat;     /* argh! */
     const int id = (int) val;
-    const int valid_id = id >= 0 && id < SC_ENUM_END;
-    const char *name = valid_id ? ScFieldsInfo[id].name.termedBuf() : "INVALID";
+    const bool valid_id = id >= 0 && id < SC_ENUM_END;
+    const char *name = valid_id ? ScAttrs[id].name : "INVALID";
 
     if (count || valid_id)
         storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
@@ -320,8 +306,8 @@
 {
     extern const HttpHeaderStat *dump_stat; /* argh! */
     const int id = (int) val;
-    const int valid_id = id >= 0 && id < SC_ENUM_END;
-    const char *name = valid_id ? ScFieldsInfo[id].name.termedBuf() : "INVALID";
+    const bool valid_id = id >= 0 && id < SC_ENUM_END;
+    const char *name = valid_id ? ScAttrs[id].name : "INVALID";
 
     if (count || valid_id)
         storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",

=== modified file 'src/HttpHeader.cc'
--- src/HttpHeader.cc	2015-03-04 16:02:53 +0000
+++ src/HttpHeader.cc	2015-08-04 11:09:31 +0000
@@ -9,6 +9,7 @@
 /* DEBUG: section 55    HTTP Header */
 
 #include "squid.h"
+#include "base/LookupTable.h"
 #include "base64.h"
 #include "globals.h"
 #include "HttpHdrCc.h"
@@ -59,114 +60,10 @@
  * local constants and vars
  */
 
-/*
- * A table with major attributes for every known field.
- * We calculate name lengths and reorganize this array on start up.
- * After reorganization, field id can be used as an index to the table.
- */
-static const HttpHeaderFieldAttrs HeadersAttrs[] = {
-    HttpHeaderFieldAttrs("Accept", HDR_ACCEPT, ftStr),
-
-    HttpHeaderFieldAttrs("Accept-Charset", HDR_ACCEPT_CHARSET, ftStr),
-    HttpHeaderFieldAttrs("Accept-Encoding", HDR_ACCEPT_ENCODING, ftStr),
-    HttpHeaderFieldAttrs("Accept-Language", HDR_ACCEPT_LANGUAGE, ftStr),
-    HttpHeaderFieldAttrs("Accept-Ranges", HDR_ACCEPT_RANGES, ftStr),
-    HttpHeaderFieldAttrs("Age", HDR_AGE, ftInt),
-    HttpHeaderFieldAttrs("Allow", HDR_ALLOW, ftStr),
-    HttpHeaderFieldAttrs("Alternate-Protocol", HDR_ALTERNATE_PROTOCOL, ftStr),
-    HttpHeaderFieldAttrs("Authorization", HDR_AUTHORIZATION, ftStr),    /* for now */
-    HttpHeaderFieldAttrs("Cache-Control", HDR_CACHE_CONTROL, ftPCc),
-    HttpHeaderFieldAttrs("Connection", HDR_CONNECTION, ftStr),
-    HttpHeaderFieldAttrs("Content-Base", HDR_CONTENT_BASE, ftStr),
-    HttpHeaderFieldAttrs("Content-Disposition", HDR_CONTENT_DISPOSITION, ftStr),  /* for now */
-    HttpHeaderFieldAttrs("Content-Encoding", HDR_CONTENT_ENCODING, ftStr),
-    HttpHeaderFieldAttrs("Content-Language", HDR_CONTENT_LANGUAGE, ftStr),
-    HttpHeaderFieldAttrs("Content-Length", HDR_CONTENT_LENGTH, ftInt64),
-    HttpHeaderFieldAttrs("Content-Location", HDR_CONTENT_LOCATION, ftStr),
-    HttpHeaderFieldAttrs("Content-MD5", HDR_CONTENT_MD5, ftStr),    /* for now */
-    HttpHeaderFieldAttrs("Content-Range", HDR_CONTENT_RANGE, ftPContRange),
-    HttpHeaderFieldAttrs("Content-Type", HDR_CONTENT_TYPE, ftStr),
-    HttpHeaderFieldAttrs("Cookie", HDR_COOKIE, ftStr),
-    HttpHeaderFieldAttrs("Cookie2", HDR_COOKIE2, ftStr),
-    HttpHeaderFieldAttrs("Date", HDR_DATE, ftDate_1123),
-    HttpHeaderFieldAttrs("ETag", HDR_ETAG, ftETag),
-    HttpHeaderFieldAttrs("Expect", HDR_EXPECT, ftStr),
-    HttpHeaderFieldAttrs("Expires", HDR_EXPIRES, ftDate_1123),
-    HttpHeaderFieldAttrs("Forwarded", HDR_FORWARDED, ftStr),
-    HttpHeaderFieldAttrs("From", HDR_FROM, ftStr),
-    HttpHeaderFieldAttrs("Host", HDR_HOST, ftStr),
-    HttpHeaderFieldAttrs("HTTP2-Settings", HDR_HTTP2_SETTINGS, ftStr), /* for now */
-    HttpHeaderFieldAttrs("If-Match", HDR_IF_MATCH, ftStr),  /* for now */
-    HttpHeaderFieldAttrs("If-Modified-Since", HDR_IF_MODIFIED_SINCE, ftDate_1123),
-    HttpHeaderFieldAttrs("If-None-Match", HDR_IF_NONE_MATCH, ftStr),    /* for now */
-    HttpHeaderFieldAttrs("If-Range", HDR_IF_RANGE, ftDate_1123_or_ETag),
-    HttpHeaderFieldAttrs("If-Unmodified-Since", HDR_IF_UNMODIFIED_SINCE, ftDate_1123),
-    HttpHeaderFieldAttrs("Keep-Alive", HDR_KEEP_ALIVE, ftStr),
-    HttpHeaderFieldAttrs("Key", HDR_KEY, ftStr),
-    HttpHeaderFieldAttrs("Last-Modified", HDR_LAST_MODIFIED, ftDate_1123),
-    HttpHeaderFieldAttrs("Link", HDR_LINK, ftStr),
-    HttpHeaderFieldAttrs("Location", HDR_LOCATION, ftStr),
-    HttpHeaderFieldAttrs("Max-Forwards", HDR_MAX_FORWARDS, ftInt64),
-    HttpHeaderFieldAttrs("Mime-Version", HDR_MIME_VERSION, ftStr),  /* for now */
-    HttpHeaderFieldAttrs("Negotiate", HDR_NEGOTIATE, ftStr),
-    HttpHeaderFieldAttrs("Origin", HDR_ORIGIN, ftStr),
-    HttpHeaderFieldAttrs("Pragma", HDR_PRAGMA, ftStr),
-    HttpHeaderFieldAttrs("Proxy-Authenticate", HDR_PROXY_AUTHENTICATE, ftStr),
-    HttpHeaderFieldAttrs("Proxy-Authentication-Info", HDR_PROXY_AUTHENTICATION_INFO, ftStr),
-    HttpHeaderFieldAttrs("Proxy-Authorization", HDR_PROXY_AUTHORIZATION, ftStr),
-    HttpHeaderFieldAttrs("Proxy-Connection", HDR_PROXY_CONNECTION, ftStr),
-    HttpHeaderFieldAttrs("Proxy-support", HDR_PROXY_SUPPORT, ftStr),
-    HttpHeaderFieldAttrs("Public", HDR_PUBLIC, ftStr),
-    HttpHeaderFieldAttrs("Range", HDR_RANGE, ftPRange),
-    HttpHeaderFieldAttrs("Referer", HDR_REFERER, ftStr),
-    HttpHeaderFieldAttrs("Request-Range", HDR_REQUEST_RANGE, ftPRange), /* usually matches HDR_RANGE */
-    HttpHeaderFieldAttrs("Retry-After", HDR_RETRY_AFTER, ftStr),    /* for now (ftDate_1123 or ftInt!) */
-    HttpHeaderFieldAttrs("Server", HDR_SERVER, ftStr),
-    HttpHeaderFieldAttrs("Set-Cookie", HDR_SET_COOKIE, ftStr),
-    HttpHeaderFieldAttrs("Set-Cookie2", HDR_SET_COOKIE2, ftStr),
-    HttpHeaderFieldAttrs("TE", HDR_TE, ftStr),
-    HttpHeaderFieldAttrs("Title", HDR_TITLE, ftStr),
-    HttpHeaderFieldAttrs("Trailer", HDR_TRAILER, ftStr),
-    HttpHeaderFieldAttrs("Transfer-Encoding", HDR_TRANSFER_ENCODING, ftStr),
-    HttpHeaderFieldAttrs("Translate", HDR_TRANSLATE, ftStr),    /* for now. may need to crop */
-    HttpHeaderFieldAttrs("Unless-Modified-Since", HDR_UNLESS_MODIFIED_SINCE, ftStr),  /* for now ignore. may need to crop */
-    HttpHeaderFieldAttrs("Upgrade", HDR_UPGRADE, ftStr),    /* for now */
-    HttpHeaderFieldAttrs("User-Agent", HDR_USER_AGENT, ftStr),
-    HttpHeaderFieldAttrs("Vary", HDR_VARY, ftStr),  /* for now */
-    HttpHeaderFieldAttrs("Via", HDR_VIA, ftStr),    /* for now */
-    HttpHeaderFieldAttrs("Warning", HDR_WARNING, ftStr),    /* for now */
-    HttpHeaderFieldAttrs("WWW-Authenticate", HDR_WWW_AUTHENTICATE, ftStr),
-    HttpHeaderFieldAttrs("Authentication-Info", HDR_AUTHENTICATION_INFO, ftStr),
-    HttpHeaderFieldAttrs("X-Cache", HDR_X_CACHE, ftStr),
-    HttpHeaderFieldAttrs("X-Cache-Lookup", HDR_X_CACHE_LOOKUP, ftStr),
-    HttpHeaderFieldAttrs("X-Forwarded-For", HDR_X_FORWARDED_FOR, ftStr),
-    HttpHeaderFieldAttrs("X-Request-URI", HDR_X_REQUEST_URI, ftStr),
-    HttpHeaderFieldAttrs("X-Squid-Error", HDR_X_SQUID_ERROR, ftStr),
-#if X_ACCELERATOR_VARY
-    HttpHeaderFieldAttrs("X-Accelerator-Vary", HDR_X_ACCELERATOR_VARY, ftStr),
-#endif
-#if USE_ADAPTATION
-    HttpHeaderFieldAttrs("X-Next-Services", HDR_X_NEXT_SERVICES, ftStr),
-#endif
-    HttpHeaderFieldAttrs("Surrogate-Capability", HDR_SURROGATE_CAPABILITY, ftStr),
-    HttpHeaderFieldAttrs("Surrogate-Control", HDR_SURROGATE_CONTROL, ftPSc),
-    HttpHeaderFieldAttrs("Front-End-Https", HDR_FRONT_END_HTTPS, ftStr),
-    HttpHeaderFieldAttrs("FTP-Command", HDR_FTP_COMMAND, ftStr),
-    HttpHeaderFieldAttrs("FTP-Arguments", HDR_FTP_ARGUMENTS, ftStr),
-    HttpHeaderFieldAttrs("FTP-Pre", HDR_FTP_PRE, ftStr),
-    HttpHeaderFieldAttrs("FTP-Status", HDR_FTP_STATUS, ftInt),
-    HttpHeaderFieldAttrs("FTP-Reason", HDR_FTP_REASON, ftStr),
-    HttpHeaderFieldAttrs("Other:", HDR_OTHER, ftStr)    /* ':' will not allow matches */
-};
-
-static HttpHeaderFieldInfo *Headers = NULL;
-
-http_hdr_type &operator++ (http_hdr_type &aHeader)
-{
-    int tmp = (int)aHeader;
-    aHeader = (http_hdr_type)(++tmp);
-    return aHeader;
-}
+const LookupTable<http_hdr_type, HeaderTableRecord> headerLookupTable(HDR_BAD_HDR, headerTable);
+
+// statistics counters for headers. clients must not allow HDR_BAD_HDR to be counted
+std::vector<HttpHeaderFieldStat> headerStatsTable(HDR_ENUM_END);
 
 /*
  * headers with field values defined as #(values) in HTTP/1.1
@@ -344,12 +241,23 @@
  */
 
 class StoreEntry;
-#define assert_eid(id) assert((id) >= 0 && (id) < HDR_ENUM_END)
+
+static inline
+bool
+any_registered_header (const http_hdr_type id)
+{
+    return (id == HDR_BAD_HDR || (id >= HDR_ACCEPT && id < HDR_ENUM_END));
+}
+
+static inline
+bool
+any_valid_header (const http_hdr_type id)
+{
+    return (id >= HDR_ACCEPT && id < HDR_ENUM_END);
+}
 
 static void httpHeaderNoteParsedEntry(http_hdr_type id, String const &value, int error);
-
 static void httpHeaderStatDump(const HttpHeaderStat * hs, StoreEntry * e);
-
 /** store report about current header usage and other stats */
 static void httpHeaderStoreReport(StoreEntry * e);
 
@@ -370,13 +278,12 @@
 {
     /* check that we have enough space for masks */
     assert(8 * sizeof(HttpHeaderMask) >= HDR_ENUM_END);
-    /* all headers must be described */
-    assert(countof(HeadersAttrs) == HDR_ENUM_END);
-
-    if (!Headers)
-        Headers = httpHeaderBuildFieldsInfo(HeadersAttrs, HDR_ENUM_END);
-
-    /* create masks */
+
+    // check invariant: for each index in headerTable, (int)headerTable[index] = index
+    for (int i = 0; headerTable[i].name; ++i)
+        assert(headerTable[i].id == i);
+
+    /* create masks. XXX: migrate to std::vector<bool>? */
     httpHeaderMaskInit(&ListHeadersMask, 0);
     httpHeaderCalcMask(&ListHeadersMask, ListHeadersArr, countof(ListHeadersArr));
 
@@ -406,8 +313,6 @@
 void
 httpHeaderCleanModule(void)
 {
-    httpHeaderDestroyFieldsInfo(Headers, HDR_ENUM_END);
-    Headers = NULL;
     httpHdrCcCleanModule();
     httpHdrScCleanModule();
 }
@@ -484,7 +389,7 @@
         HttpHeaderEntry *e = *i;
         if (e == NULL)
             continue;
-        if (e->id < 0 || e->id >= HDR_ENUM_END) {
+        if (e->id >= HDR_ENUM_END) {
             debugs(55, DBG_CRITICAL, "BUG: invalid entry (" << e->id << "). Ignored.");
         } else {
             if (owner <= hoReply)
@@ -549,7 +454,7 @@
         if (denied_mask && CBIT_TEST(*denied_mask, e->id))
             continue;
 
-        debugs(55, 7, "Updating header '" << HeadersAttrs[e->id].name << "' in cached entry");
+        debugs(55, 7, "Updating header '" << headerTable[e->id].name << "' in cached entry");
 
         addEntry(e->clone());
     }
@@ -802,7 +707,7 @@
 {
     HttpHeaderPos pos = HttpHeaderInitPos;
     HttpHeaderEntry *e;
-    assert_eid(id);
+    assert(any_valid_header(id));
     assert(!CBIT_TEST(ListHeadersMask, id));
 
     /* check mask first */
@@ -831,7 +736,7 @@
     HttpHeaderPos pos = HttpHeaderInitPos;
     HttpHeaderEntry *e;
     HttpHeaderEntry *result = NULL;
-    assert_eid(id);
+    assert(any_valid_header(id));
     assert(!CBIT_TEST(ListHeadersMask, id));
 
     /* check mask first */
@@ -879,7 +784,7 @@
     HttpHeaderPos pos = HttpHeaderInitPos;
     HttpHeaderEntry *e;
     debugs(55, 8, this << " del-by-id " << id);
-    assert_eid(id);
+    assert(any_valid_header(id));
     assert(id != HDR_OTHER);        /* does not make sense */
 
     if (!CBIT_TEST(mask, id))
@@ -948,15 +853,18 @@
 HttpHeader::addEntry(HttpHeaderEntry * e)
 {
     assert(e);
-    assert_eid(e->id);
+    assert(any_registered_header(e->id));
     assert(e->name.size());
 
     debugs(55, 7, this << " adding entry: " << e->id << " at " << entries.size());
 
-    if (CBIT_TEST(mask, e->id))
-        ++ Headers[e->id].stat.repCount;
-    else
-        CBIT_SET(mask, e->id);
+    if (e->id != HDR_BAD_HDR) {
+        if (CBIT_TEST(mask, e->id)) {
+            ++ headerStatsTable[e->id].repCount;
+        } else {
+            CBIT_SET(mask, e->id);
+        }
+    }
 
     entries.push_back(e);
 
@@ -971,14 +879,16 @@
 HttpHeader::insertEntry(HttpHeaderEntry * e)
 {
     assert(e);
-    assert_eid(e->id);
+    assert(any_valid_header(e->id));
 
     debugs(55, 7, this << " adding entry: " << e->id << " at " << entries.size());
 
-    if (CBIT_TEST(mask, e->id))
-        ++ Headers[e->id].stat.repCount;
-    else
+    // HDR_BAD_HDR is filtered out by assert_any_valid_header
+    if (CBIT_TEST(mask, e->id)) {
+        ++ headerStatsTable[e->id].repCount;
+    } else {
         CBIT_SET(mask, e->id);
+    }
 
     entries.insert(entries.begin(),e);
 
@@ -1010,7 +920,7 @@
      */
     /* temporary warning: remove it? (Is it useful for diagnostics ?) */
     if (!s->size())
-        debugs(55, 3, "empty list header: " << Headers[id].name << "(" << id << ")");
+        debugs(55, 3, "empty list header: " << headerTable[id].name << "(" << id << ")");
     else
         debugs(55, 6, this << ": joined for id " << id << ": " << s);
 
@@ -1044,7 +954,7 @@
      */
     /* temporary warning: remove it? (Is it useful for diagnostics ?) */
     if (!s.size())
-        debugs(55, 3, "empty list header: " << Headers[id].name << "(" << id << ")");
+        debugs(55, 3, "empty list header: " << headerTable[id].name << "(" << id << ")");
     else
         debugs(55, 6, this << ": joined for id " << id << ": " << s);
 
@@ -1088,9 +998,9 @@
     assert(name);
 
     /* First try the quick path */
-    id = httpHeaderIdByNameDef(name, strlen(name));
+    id = headerLookupTable.lookup(SBuf(name));
 
-    if (id != -1) {
+    if (id != HDR_BAD_HDR) {
         if (!has(id))
             return false;
         result = getStrOrList(id);
@@ -1149,7 +1059,7 @@
     int ilen;
     int mlen = strlen(member);
 
-    assert(id >= 0);
+    assert(any_valid_header(id));
 
     header = getStrOrList(id);
     String result;
@@ -1169,7 +1079,7 @@
 int
 HttpHeader::has(http_hdr_type id) const
 {
-    assert_eid(id);
+    assert(any_valid_header(id));
     assert(id != HDR_OTHER);
     debugs(55, 9, this << " lookup for " << id);
     return CBIT_TEST(mask, id);
@@ -1178,8 +1088,8 @@
 void
 HttpHeader::putInt(http_hdr_type id, int number)
 {
-    assert_eid(id);
-    assert(Headers[id].type == ftInt);  /* must be of an appropriate type */
+    assert(any_valid_header(id));
+    assert(headerTable[id].type == field_type::ftInt);  /* must be of an appropriate type */
     assert(number >= 0);
     addEntry(new HttpHeaderEntry(id, NULL, xitoa(number)));
 }
@@ -1187,8 +1097,8 @@
 void
 HttpHeader::putInt64(http_hdr_type id, int64_t number)
 {
-    assert_eid(id);
-    assert(Headers[id].type == ftInt64);    /* must be of an appropriate type */
+    assert(any_valid_header(id));
+    assert(headerTable[id].type == field_type::ftInt64);    /* must be of an appropriate type */
     assert(number >= 0);
     addEntry(new HttpHeaderEntry(id, NULL, xint64toa(number)));
 }
@@ -1196,8 +1106,8 @@
 void
 HttpHeader::putTime(http_hdr_type id, time_t htime)
 {
-    assert_eid(id);
-    assert(Headers[id].type == ftDate_1123);    /* must be of an appropriate type */
+    assert(any_valid_header(id));
+    assert(headerTable[id].type == field_type::ftDate_1123);    /* must be of an appropriate type */
     assert(htime >= 0);
     addEntry(new HttpHeaderEntry(id, NULL, mkrfc1123(htime)));
 }
@@ -1205,8 +1115,8 @@
 void
 HttpHeader::insertTime(http_hdr_type id, time_t htime)
 {
-    assert_eid(id);
-    assert(Headers[id].type == ftDate_1123);    /* must be of an appropriate type */
+    assert(any_valid_header(id));
+    assert(headerTable[id].type == field_type::ftDate_1123);    /* must be of an appropriate type */
     assert(htime >= 0);
     insertEntry(new HttpHeaderEntry(id, NULL, mkrfc1123(htime)));
 }
@@ -1214,8 +1124,8 @@
 void
 HttpHeader::putStr(http_hdr_type id, const char *str)
 {
-    assert_eid(id);
-    assert(Headers[id].type == ftStr);  /* must be of an appropriate type */
+    assert(any_valid_header(id));
+    assert(headerTable[id].type == field_type::ftStr);  /* must be of an appropriate type */
     assert(str);
     addEntry(new HttpHeaderEntry(id, NULL, str));
 }
@@ -1311,8 +1221,8 @@
 int
 HttpHeader::getInt(http_hdr_type id) const
 {
-    assert_eid(id);
-    assert(Headers[id].type == ftInt);  /* must be of an appropriate type */
+    assert(any_valid_header(id));
+    assert(headerTable[id].type == field_type::ftInt);  /* must be of an appropriate type */
     HttpHeaderEntry *e;
 
     if ((e = findEntry(id)))
@@ -1324,8 +1234,8 @@
 int64_t
 HttpHeader::getInt64(http_hdr_type id) const
 {
-    assert_eid(id);
-    assert(Headers[id].type == ftInt64);    /* must be of an appropriate type */
+    assert(any_valid_header(id));
+    assert(headerTable[id].type == field_type::ftInt64);    /* must be of an appropriate type */
     HttpHeaderEntry *e;
 
     if ((e = findEntry(id)))
@@ -1339,8 +1249,8 @@
 {
     HttpHeaderEntry *e;
     time_t value = -1;
-    assert_eid(id);
-    assert(Headers[id].type == ftDate_1123);    /* must be of an appropriate type */
+    assert(any_valid_header(id));
+    assert(headerTable[id].type == field_type::ftDate_1123);    /* must be of an appropriate type */
 
     if ((e = findEntry(id))) {
         value = parse_rfc1123(e->value.termedBuf());
@@ -1355,8 +1265,8 @@
 HttpHeader::getStr(http_hdr_type id) const
 {
     HttpHeaderEntry *e;
-    assert_eid(id);
-    assert(Headers[id].type == ftStr);  /* must be of an appropriate type */
+    assert(any_valid_header(id));
+    assert(headerTable[id].type == field_type::ftStr);  /* must be of an appropriate type */
 
     if ((e = findEntry(id))) {
         httpHeaderNoteParsedEntry(e->id, e->value, 0);  /* no errors are possible */
@@ -1371,8 +1281,8 @@
 HttpHeader::getLastStr(http_hdr_type id) const
 {
     HttpHeaderEntry *e;
-    assert_eid(id);
-    assert(Headers[id].type == ftStr);  /* must be of an appropriate type */
+    assert(any_valid_header(id));
+    assert(headerTable[id].type == field_type::ftStr);  /* must be of an appropriate type */
 
     if ((e = findLastEntry(id))) {
         httpHeaderNoteParsedEntry(e->id, e->value, 0);  /* no errors are possible */
@@ -1510,7 +1420,7 @@
 {
     ETag etag = {NULL, -1};
     HttpHeaderEntry *e;
-    assert(Headers[id].type == ftETag);     /* must be of an appropriate type */
+    assert(headerTable[id].type == field_type::ftETag);     /* must be of an appropriate type */
 
     if ((e = findEntry(id)))
         etagParseInit(&etag, e->value.termedBuf());
@@ -1523,7 +1433,7 @@
 {
     TimeOrTag tot;
     HttpHeaderEntry *e;
-    assert(Headers[id].type == ftDate_1123_or_ETag);    /* must be of an appropriate type */
+    assert(headerTable[id].type == field_type::ftDate_1123_or_ETag);    /* must be of an appropriate type */
     memset(&tot, 0, sizeof(tot));
 
     if ((e = findEntry(id))) {
@@ -1551,35 +1461,30 @@
 
 HttpHeaderEntry::HttpHeaderEntry(http_hdr_type anId, const char *aName, const char *aValue)
 {
-    assert_eid(anId);
+    assert(any_registered_header(anId));
     id = anId;
 
     if (id != HDR_OTHER)
-        name = Headers[id].name;
+        name = headerTable[id].name;
     else
         name = aName;
 
     value = aValue;
 
-    ++ Headers[id].stat.aliveCount;
+    if (anId != HDR_BAD_HDR)
+        ++ headerStatsTable[id].aliveCount;
 
     debugs(55, 9, "created HttpHeaderEntry " << this << ": '" << name << " : " << value );
 }
 
 HttpHeaderEntry::~HttpHeaderEntry()
 {
-    assert_eid(id);
+    assert(any_valid_header(id));
     debugs(55, 9, "destroying entry " << this << ": '" << name << ": " << value << "'");
-    /* clean name if needed */
-
-    if (id == HDR_OTHER)
-        name.clean();
-
-    value.clean();
-
-    assert(Headers[id].stat.aliveCount);
-
-    -- Headers[id].stat.aliveCount;
+
+    // HDR_BAD_HDR is filtered out by assert_any_valid_header
+    assert(headerStatsTable[id].aliveCount); // is this really needed?
+    -- headerStatsTable[id].aliveCount;
 
     id = HDR_BAD_HDR;
 }
@@ -1623,22 +1528,23 @@
     debugs(55, 9, "parsing HttpHeaderEntry: near '" <<  getStringPrefix(field_start, field_end-field_start) << "'");
 
     /* is it a "known" field? */
-    http_hdr_type id = httpHeaderIdByName(field_start, name_len, Headers, HDR_ENUM_END);
+    http_hdr_type id = headerLookupTable.lookup(SBuf(field_start,name_len));
+    debugs(55, 9, "got hdr id hdr: " << id);
 
     String name;
 
     String value;
 
-    if (id < 0)
+    if (id == HDR_BAD_HDR)
         id = HDR_OTHER;
 
-    assert_eid(id);
+    assert(any_valid_header(id));
 
     /* set field name */
     if (id == HDR_OTHER)
         name.limitInit(field_start, name_len);
     else
-        name = Headers[id].name;
+        name = headerTable[id].name;
 
     /* trim field value */
     while (value_start < field_end && xisspace(*value_start))
@@ -1660,7 +1566,8 @@
     /* set field value */
     value.limitInit(value_start, field_end - value_start);
 
-    ++ Headers[id].stat.seenCount;
+    if (id != HDR_BAD_HDR)
+        ++ headerStatsTable[id].seenCount;
 
     debugs(55, 9, "parsed HttpHeaderEntry: '" << name << ": " << value << "'");
 
@@ -1686,8 +1593,7 @@
 int
 HttpHeaderEntry::getInt() const
 {
-    assert_eid (id);
-    assert (Headers[id].type == ftInt);
+    assert(any_valid_header(id));
     int val = -1;
     int ok = httpHeaderParseInt(value.termedBuf(), &val);
     httpHeaderNoteParsedEntry(id, value, !ok);
@@ -1700,8 +1606,7 @@
 int64_t
 HttpHeaderEntry::getInt64() const
 {
-    assert_eid (id);
-    assert (Headers[id].type == ftInt64);
+    assert(any_valid_header(id));
     int64_t val = -1;
     int ok = httpHeaderParseOffset(value.termedBuf(), &val);
     httpHeaderNoteParsedEntry(id, value, !ok);
@@ -1714,11 +1619,13 @@
 static void
 httpHeaderNoteParsedEntry(http_hdr_type id, String const &context, int error)
 {
-    ++ Headers[id].stat.parsCount;
+    if (id != HDR_BAD_HDR)
+        ++ headerStatsTable[id].parsCount;
 
     if (error) {
-        ++ Headers[id].stat.errCount;
-        debugs(55, 2, "cannot parse hdr field: '" << Headers[id].name << ": " << context << "'");
+        if (id != HDR_BAD_HDR)
+            ++ headerStatsTable[id].errCount;
+        debugs(55, 2, "cannot parse hdr field: '" << headerTable[id].name << ": " << context << "'");
     }
 }
 
@@ -1734,8 +1641,8 @@
 httpHeaderFieldStatDumper(StoreEntry * sentry, int, double val, double, int count)
 {
     const int id = (int) val;
-    const int valid_id = id >= 0 && id < HDR_ENUM_END;
-    const char *name = valid_id ? Headers[id].name.termedBuf() : "INVALID";
+    const int valid_id = id < HDR_ENUM_END;
+    const char *name = valid_id ? headerTable[id].name : "INVALID";
     int visible = count > 0;
     /* for entries with zero count, list only those that belong to current type of message */
 
@@ -1759,7 +1666,8 @@
 static void
 httpHeaderStatDump(const HttpHeaderStat * hs, StoreEntry * e)
 {
-    assert(hs && e);
+    assert(hs);
+    assert(e);
 
     dump_stat = hs;
     storeAppendPrintf(e, "\nHeader Stats: %s\n", hs->label);
@@ -1787,7 +1695,6 @@
 httpHeaderStoreReport(StoreEntry * e)
 {
     int i;
-    http_hdr_type ht;
     assert(e);
 
     HttpHeaderStats[0].parsedCount =
@@ -1809,12 +1716,13 @@
     storeAppendPrintf(e, "%2s\t %-25s\t %5s\t %6s\t %6s\n",
                       "id", "name", "#alive", "%err", "%repeat");
 
-    for (ht = (http_hdr_type)0; ht < HDR_ENUM_END; ++ht) {
-        HttpHeaderFieldInfo *f = Headers + ht;
+    // scan heaaderTable and output
+    for (int j = 0; headerTable[j].name != nullptr; ++j) {
+        auto stats = headerStatsTable[j];
         storeAppendPrintf(e, "%2d\t %-25s\t %5d\t %6.3f\t %6.3f\n",
-                          f->id, f->name.termedBuf(), f->stat.aliveCount,
-                          xpercent(f->stat.errCount, f->stat.parsCount),
-                          xpercent(f->stat.repCount, f->stat.seenCount));
+                          headerTable[j].id, headerTable[j].name, stats.aliveCount,
+                          xpercent(stats.errCount, stats.parsCount),
+                          xpercent(stats.repCount, stats.seenCount));
     }
 
     storeAppendPrintf(e, "Headers Parsed: %d + %d = %d\n",
@@ -1824,42 +1732,6 @@
     storeAppendPrintf(e, "Hdr Fields Parsed: %d\n", HeaderEntryParsedCount);
 }
 
-http_hdr_type
-httpHeaderIdByName(const char *name, size_t name_len, const HttpHeaderFieldInfo * info, int end)
-{
-    if (name_len > 0) {
-        for (int i = 0; i < end; ++i) {
-            if (name_len != info[i].name.size())
-                continue;
-
-            if (!strncasecmp(name, info[i].name.rawBuf(), name_len))
-                return info[i].id;
-        }
-    }
-
-    return HDR_BAD_HDR;
-}
-
-http_hdr_type
-httpHeaderIdByNameDef(const char *name, int name_len)
-{
-    if (!Headers)
-        Headers = httpHeaderBuildFieldsInfo(HeadersAttrs, HDR_ENUM_END);
-
-    return httpHeaderIdByName(name, name_len, Headers, HDR_ENUM_END);
-}
-
-const char *
-httpHeaderNameById(int id)
-{
-    if (!Headers)
-        Headers = httpHeaderBuildFieldsInfo(HeadersAttrs, HDR_ENUM_END);
-
-    assert(id >= 0 && id < HDR_ENUM_END);
-
-    return Headers[id].name.termedBuf();
-}
-
 int
 HttpHeader::hasListMember(http_hdr_type id, const char *member, const char separator) const
 {
@@ -1869,7 +1741,7 @@
     int ilen;
     int mlen = strlen(member);
 
-    assert(id >= 0);
+    assert(any_valid_header(id));
 
     String header (getStrOrList(id));
 

=== modified file 'src/HttpHeader.h'
--- src/HttpHeader.h	2015-03-03 11:43:26 +0000
+++ src/HttpHeader.h	2015-08-03 13:56:30 +0000
@@ -9,6 +9,7 @@
 #ifndef SQUID_HTTPHEADER_H
 #define SQUID_HTTPHEADER_H
 
+#include "base/LookupTable.h"
 #include "http/RegisteredHeaders.h"
 /* because we pass a spec by value */
 #include "HttpHeaderMask.h"
@@ -23,24 +24,8 @@
 class HttpHdrRange;
 class HttpHdrSc;
 class Packable;
-class StoreEntry;
 class SBuf;
 
-/** possible types for http header fields */
-typedef enum {
-    ftInvalid = HDR_ENUM_END,   /**< to catch nasty errors with hdr_id<->fld_type clashes */
-    ftInt,
-    ftInt64,
-    ftStr,
-    ftDate_1123,
-    ftETag,
-    ftPCc,
-    ftPContRange,
-    ftPRange,
-    ftPSc,
-    ftDate_1123_or_ETag
-} field_type;
-
 /** Possible owners of http header */
 typedef enum {
     hoNone =0,
@@ -55,23 +40,6 @@
     hoEnd
 } http_hdr_owner_type;
 
-class HttpHeaderFieldAttrs
-{
-public:
-    HttpHeaderFieldAttrs() : name(NULL), id(HDR_BAD_HDR), type(ftInvalid) {}
-    HttpHeaderFieldAttrs(const char *aName, http_hdr_type anId, field_type aType = ftInvalid) : name(aName), id(anId), type(aType) {}
-#if __cplusplus >= 201103L
-    HttpHeaderFieldAttrs(const HttpHeaderFieldAttrs &) = default;
-    HttpHeaderFieldAttrs(HttpHeaderFieldAttrs &&) = default;
-#endif
-    // nothing to do as name is a pointer to global const string
-    ~HttpHeaderFieldAttrs() {}
-
-    const char *name;
-    http_hdr_type id;
-    field_type type;
-};
-
 /** Iteration for headers; use HttpHeaderPos as opaque type, do not interpret */
 typedef ssize_t HttpHeaderPos;
 
@@ -197,5 +165,8 @@
 void httpHeaderInitModule(void);
 void httpHeaderCleanModule(void);
 
+// for header string->id lookup, use headerLookupTable.lookup(hdr-as-sbuf);
+extern const LookupTable<http_hdr_type, HeaderTableRecord> headerLookupTable;
+
 #endif /* SQUID_HTTPHEADER_H */
 

=== modified file 'src/HttpHeaderFieldInfo.h'
--- src/HttpHeaderFieldInfo.h	2015-01-13 07:25:36 +0000
+++ src/HttpHeaderFieldInfo.h	2015-08-04 11:09:31 +0000
@@ -9,6 +9,7 @@
 #ifndef SQUID_HTTPHEADERFIELDINFO_H_
 #define SQUID_HTTPHEADERFIELDINFO_H_
 
+#include "http/RegisteredHeaders.h"
 #include "HttpHeaderFieldStat.h"
 #include "SquidString.h"
 
@@ -16,7 +17,7 @@
 class HttpHeaderFieldInfo
 {
 public:
-    HttpHeaderFieldInfo() : id(HDR_ACCEPT), type(ftInvalid) {}
+    HttpHeaderFieldInfo() : id(HDR_ACCEPT), type(field_type::ftInvalid) {}
 
     http_hdr_type id;
     String name;

=== modified file 'src/HttpHeaderTools.cc'
--- src/HttpHeaderTools.cc	2015-03-03 16:51:03 +0000
+++ src/HttpHeaderTools.cc	2015-08-04 10:50:30 +0000
@@ -18,6 +18,7 @@
 #include "ConfigParser.h"
 #include "fde.h"
 #include "globals.h"
+#include "http/RegisteredHeaders.h"
 #include "HttpHdrContRange.h"
 #include "HttpHeader.h"
 #include "HttpHeaderFieldInfo.h"
@@ -38,44 +39,6 @@
 
 static void httpHeaderPutStrvf(HttpHeader * hdr, http_hdr_type id, const char *fmt, va_list vargs);
 
-HttpHeaderFieldInfo *
-httpHeaderBuildFieldsInfo(const HttpHeaderFieldAttrs * attrs, int count)
-{
-    int i;
-    HttpHeaderFieldInfo *table = NULL;
-    assert(attrs && count);
-
-    /* allocate space */
-    table = new HttpHeaderFieldInfo[count];
-
-    for (i = 0; i < count; ++i) {
-        const http_hdr_type id = attrs[i].id;
-        HttpHeaderFieldInfo *info = table + id;
-        /* sanity checks */
-        assert(id >= 0 && id < count);
-        assert(attrs[i].name);
-        assert(info->id == HDR_ACCEPT && info->type == ftInvalid);  /* was not set before */
-        /* copy and init fields */
-        info->id = id;
-        info->type = attrs[i].type;
-        info->name = attrs[i].name;
-        assert(info->name.size());
-    }
-
-    return table;
-}
-
-void
-httpHeaderDestroyFieldsInfo(HttpHeaderFieldInfo * table, int count)
-{
-    int i;
-
-    for (i = 0; i < count; ++i)
-        table[i].name.clean();
-
-    delete [] table;
-}
-
 void
 httpHeaderMaskInit(HttpHeaderMask * mask, int value)
 {
@@ -424,9 +387,8 @@
 void
 HeaderManglers::dumpAccess(StoreEntry * entry, const char *name) const
 {
-    for (int i = 0; i < HDR_ENUM_END; ++i) {
-        header_mangler_dump_access(entry, name, known[i],
-                                   httpHeaderNameById(i));
+    for (int i = 0; headerTable[i].name != nullptr; ++i) {
+        header_mangler_dump_access(entry, name, known[i], headerTable[i].name);
     }
 
     typedef ManglersByName::const_iterator MBNCI;
@@ -439,9 +401,8 @@
 void
 HeaderManglers::dumpReplacement(StoreEntry * entry, const char *name) const
 {
-    for (int i = 0; i < HDR_ENUM_END; ++i) {
-        header_mangler_dump_replacement(entry, name, known[i],
-                                        httpHeaderNameById(i));
+    for (int i = 0; headerTable[i].name != nullptr; ++i) {
+        header_mangler_dump_replacement(entry, name, known[i],headerTable[i].name);
     }
 
     typedef ManglersByName::const_iterator MBNCI;
@@ -456,7 +417,7 @@
 headerMangler *
 HeaderManglers::track(const char *name)
 {
-    int id = httpHeaderIdByNameDef(name, strlen(name));
+    int id = headerLookupTable.lookup(SBuf(name));
 
     if (id == HDR_BAD_HDR) { // special keyword or a custom header
         if (strcmp(name, "All") == 0)
@@ -493,7 +454,7 @@
 HeaderManglers::find(const HttpHeaderEntry &e) const
 {
     // a known header with a configured ACL list
-    if (e.id != HDR_OTHER && 0 <= e.id && e.id < HDR_ENUM_END &&
+    if (e.id != HDR_OTHER && e.id < HDR_ENUM_END &&
             known[e.id].access_list)
         return &known[e.id];
 

=== modified file 'src/HttpHeaderTools.h'
--- src/HttpHeaderTools.h	2015-01-13 07:25:36 +0000
+++ src/HttpHeaderTools.h	2015-08-03 13:56:30 +0000
@@ -24,7 +24,6 @@
 
 class HeaderWithAcl;
 class HttpHeader;
-class HttpHeaderFieldInfo;
 class HttpRequest;
 class StoreEntry;
 class String;
@@ -115,11 +114,6 @@
 
 int httpHeaderParseOffset(const char *start, int64_t * off);
 
-HttpHeaderFieldInfo *httpHeaderBuildFieldsInfo(const HttpHeaderFieldAttrs * attrs, int count);
-void httpHeaderDestroyFieldsInfo(HttpHeaderFieldInfo * info, int count);
-http_hdr_type httpHeaderIdByName(const char *name, size_t name_len, const HttpHeaderFieldInfo * attrs, int end);
-http_hdr_type httpHeaderIdByNameDef(const char *name, int name_len);
-const char *httpHeaderNameById(int id);
 int httpHeaderHasConnDir(const HttpHeader * hdr, const char *directive);
 int httpHeaderParseInt(const char *start, int *val);
 void httpHeaderPutStrf(HttpHeader * hdr, http_hdr_type id, const char *fmt,...) PRINTF_FORMAT_ARG3;

=== modified file 'src/acl/HttpHeaderData.cc'
--- src/acl/HttpHeaderData.cc	2015-07-27 12:51:43 +0000
+++ src/acl/HttpHeaderData.cc	2015-08-03 13:56:30 +0000
@@ -76,7 +76,7 @@
     char* t = ConfigParser::strtokFile();
     assert (t != NULL);
     hdrName = t;
-    hdrId = httpHeaderIdByNameDef(hdrName.rawBuf(), hdrName.size());
+    hdrId = headerLookupTable.lookup(SBuf(hdrName));
     regex_rule->parse();
 }
 

=== modified file 'src/base/LookupTable.h'
--- src/base/LookupTable.h	2015-07-28 12:12:10 +0000
+++ src/base/LookupTable.h	2015-07-30 12:35:58 +0000
@@ -14,11 +14,27 @@
 #include <map>
 
 /**
- * SBuf -> enum lookup table
+ * a record in the initializer list for a LookupTable
+ *
+ * In case it is wished to extend the structure of a LookupTable's initializer
+ * list, it can be done by using a custom struct which must match
+ * LookupTableRecord's signature plus any extra custom fields the user may
+ * wish to add; the extended record type must then be passed as RecordType
+ * template parameter to LookupTable.
+ */
+template <typename EnumType>
+struct LookupTableRecord
+{
+    const char *name;
+    EnumType id;
+};
+
+/**
+ * SBuf -> case-insensitive enum lookup table
  *
  * How to use:
  * enum enum_type { ... };
- * static const LookupTable<enum_type>::Record initializerTable[] {
+ * static const LookupTable<enum_type>::Record initializerTable[] = {
  *   {"key1", ENUM_1}, {"key2", ENUM_2}, ... {nullptr, ENUM_INVALID_VALUE}
  * };
  * LookupTable<enum_type> lookupTableInstance(ENUM_INVALID_VALUE, initializerTable);
@@ -29,15 +45,18 @@
  * if (item != ENUM_INVALID_VALUE) { // do stuff }
  *
  */
-template<typename EnumType>
+
+struct SBufCaseInsensitiveLess : public std::binary_function<SBuf, SBuf, bool> {
+    bool operator() (const SBuf &x, const SBuf &y) const {
+        return x.caseCmp(y) < 0;
+    }
+};
+template<typename EnumType, typename RecordType = LookupTableRecord<EnumType> >
 class LookupTable
 {
 public:
     /// element of the lookup table initialization list
-    typedef struct {
-        const char *name;
-        EnumType id;
-    } Record;
+    typedef RecordType Record;
 
     LookupTable(const EnumType theInvalid, const Record data[]) :
         invalidValue(theInvalid)
@@ -46,6 +65,7 @@
             lookupTable[SBuf(data[i].name)] = data[i].id;
         }
     }
+
     EnumType lookup(const SBuf &key) const {
         auto r = lookupTable.find(key);
         if (r == lookupTable.end())
@@ -54,7 +74,7 @@
     }
 
 private:
-    typedef std::map<const SBuf, EnumType> lookupTable_t;
+    typedef std::map<const SBuf, EnumType, SBufCaseInsensitiveLess> lookupTable_t;
     lookupTable_t lookupTable;
     EnumType invalidValue;
 };

=== modified file 'src/cache_cf.cc'
--- src/cache_cf.cc	2015-07-29 07:11:17 +0000
+++ src/cache_cf.cc	2015-08-03 13:56:30 +0000
@@ -4608,7 +4608,7 @@
     }
     HeaderWithAcl hwa;
     hwa.fieldName = fn;
-    hwa.fieldId = httpHeaderIdByNameDef(fn, strlen(fn));
+    hwa.fieldId = headerLookupTable.lookup(SBuf(fn));
     if (hwa.fieldId == HDR_BAD_HDR)
         hwa.fieldId = HDR_OTHER;
 

=== modified file 'src/enums.h'
--- src/enums.h	2015-01-13 07:25:36 +0000
+++ src/enums.h	2015-08-03 13:56:30 +0000
@@ -32,7 +32,6 @@
 } peer_t;
 
 typedef enum {
-    CC_BADHDR = -1,
     CC_PUBLIC = 0,
     CC_PRIVATE,
     CC_NO_CACHE,
@@ -47,7 +46,7 @@
     CC_ONLY_IF_CACHED,
     CC_STALE_IF_ERROR,
     CC_OTHER,
-    CC_ENUM_END
+    CC_ENUM_END /* also used to mean "invalid" */
 } http_hdr_cc_type;
 
 typedef enum {
@@ -56,7 +55,7 @@
     SC_MAX_AGE,
     SC_CONTENT,
     SC_OTHER,
-    SC_ENUM_END
+    SC_ENUM_END /* also used to mean "invalid" */
 } http_hdr_sc_type;
 
 typedef enum _mem_status_t {

=== modified file 'src/external_acl.cc'
--- src/external_acl.cc	2015-07-21 00:12:11 +0000
+++ src/external_acl.cc	2015-08-03 13:56:30 +0000
@@ -244,7 +244,7 @@
     }
 
     format->header = xstrdup(header);
-    format->header_id = httpHeaderIdByNameDef(header, strlen(header));
+    format->header_id = headerLookupTable.lookup(SBuf(header));
 }
 
 void

=== modified file 'src/http/Makefile.am'
--- src/http/Makefile.am	2015-08-03 03:50:25 +0000
+++ src/http/Makefile.am	2015-08-04 11:09:58 +0000
@@ -19,6 +19,7 @@
 	MethodType.h \
 	ProtocolVersion.h \
 	RegisteredHeaders.h \
+	RegisteredHeaders.cc \
 	RequestMethod.cc \
 	RequestMethod.h \
 	StatusCode.cc \

=== added file 'src/http/RegisteredHeaders.cc'
--- src/http/RegisteredHeaders.cc	1970-01-01 00:00:00 +0000
+++ src/http/RegisteredHeaders.cc	2015-08-04 11:09:31 +0000
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#include "squid.h"
+#include "RegisteredHeaders.h"
+
+/*
+ * A table with major attributes for every known field.
+ *
+ * Invariant on this table:
+ * for each index in headerTable, (int)headerTable[index] = index
+ */
+const HeaderTableRecord headerTable[] = {
+    {"Accept", HDR_ACCEPT, field_type::ftStr},
+    {"Accept-Charset", HDR_ACCEPT_CHARSET, field_type::ftStr},
+    {"Accept-Encoding", HDR_ACCEPT_ENCODING, field_type::ftStr},
+    {"Accept-Language", HDR_ACCEPT_LANGUAGE, field_type::ftStr},
+    {"Accept-Ranges", HDR_ACCEPT_RANGES, field_type::ftStr},
+    {"Age", HDR_AGE, field_type::ftInt},
+    {"Allow", HDR_ALLOW, field_type::ftStr},
+    {"Alternate-Protocol", HDR_ALTERNATE_PROTOCOL, field_type::ftStr},
+    {"Authentication-Info", HDR_AUTHENTICATION_INFO, field_type::ftStr},
+    {"Authorization", HDR_AUTHORIZATION, field_type::ftStr},    /* for now */
+    {"Cache-Control", HDR_CACHE_CONTROL, field_type::ftPCc},
+    {"Connection", HDR_CONNECTION, field_type::ftStr},
+    {"Content-Base", HDR_CONTENT_BASE, field_type::ftStr},
+    {"Content-Disposition", HDR_CONTENT_DISPOSITION, field_type::ftStr},  /* for now */
+    {"Content-Encoding", HDR_CONTENT_ENCODING, field_type::ftStr},
+    {"Content-Language", HDR_CONTENT_LANGUAGE, field_type::ftStr},
+    {"Content-Length", HDR_CONTENT_LENGTH, field_type::ftInt64},
+    {"Content-Location", HDR_CONTENT_LOCATION, field_type::ftStr},
+    {"Content-MD5", HDR_CONTENT_MD5, field_type::ftStr},    /* for now */
+    {"Content-Range", HDR_CONTENT_RANGE, field_type::ftPContRange},
+    {"Content-Type", HDR_CONTENT_TYPE, field_type::ftStr},
+    {"Cookie", HDR_COOKIE, field_type::ftStr},
+    {"Cookie2", HDR_COOKIE2, field_type::ftStr},
+    {"Date", HDR_DATE, field_type::ftDate_1123},
+    {"ETag", HDR_ETAG, field_type::ftETag},
+    {"Expect", HDR_EXPECT, field_type::ftStr},
+    {"Expires", HDR_EXPIRES, field_type::ftDate_1123},
+    {"Forwarded", HDR_FORWARDED, field_type::ftStr},
+    {"From", HDR_FROM, field_type::ftStr},
+    {"Host", HDR_HOST, field_type::ftStr},
+    {"HTTP2-Settings", HDR_HTTP2_SETTINGS, field_type::ftStr}, /* for now */
+    {"If-Match", HDR_IF_MATCH, field_type::ftStr},  /* for now */
+    {"If-Modified-Since", HDR_IF_MODIFIED_SINCE, field_type::ftDate_1123},
+    {"If-None-Match", HDR_IF_NONE_MATCH, field_type::ftStr},    /* for now */
+    {"If-Range", HDR_IF_RANGE, field_type::ftDate_1123_or_ETag},
+    {"If-Unmodified-Since", HDR_IF_UNMODIFIED_SINCE, field_type::ftDate_1123},
+    {"Keep-Alive", HDR_KEEP_ALIVE, field_type::ftStr},
+    {"Key", HDR_KEY, field_type::ftStr},
+    {"Last-Modified", HDR_LAST_MODIFIED, field_type::ftDate_1123},
+    {"Link", HDR_LINK, field_type::ftStr},
+    {"Location", HDR_LOCATION, field_type::ftStr},
+    {"Max-Forwards", HDR_MAX_FORWARDS, field_type::ftInt64},
+    {"Mime-Version", HDR_MIME_VERSION, field_type::ftStr},  /* for now */
+    {"Negotiate", HDR_NEGOTIATE, field_type::ftStr},
+    {"Origin", HDR_ORIGIN, field_type::ftStr},
+    {"Pragma", HDR_PRAGMA, field_type::ftStr},
+    {"Proxy-Authenticate", HDR_PROXY_AUTHENTICATE, field_type::ftStr},
+    {"Proxy-Authentication-Info", HDR_PROXY_AUTHENTICATION_INFO, field_type::ftStr},
+    {"Proxy-Authorization", HDR_PROXY_AUTHORIZATION, field_type::ftStr},
+    {"Proxy-Connection", HDR_PROXY_CONNECTION, field_type::ftStr},
+    {"Proxy-support", HDR_PROXY_SUPPORT, field_type::ftStr},
+    {"Public", HDR_PUBLIC, field_type::ftStr},
+    {"Range", HDR_RANGE, field_type::ftPRange},
+    {"Referer", HDR_REFERER, field_type::ftStr},
+    {"Request-Range", HDR_REQUEST_RANGE, field_type::ftPRange}, /* usually matches HDR_RANGE */
+    {"Retry-Afield_type::fter", HDR_RETRY_AFTER, field_type::ftStr},    /* for now (field_type::ftDate_1123 or field_type::ftInt!} */
+    {"Server", HDR_SERVER, field_type::ftStr},
+    {"Set-Cookie", HDR_SET_COOKIE, field_type::ftStr},
+    {"Set-Cookie2", HDR_SET_COOKIE2, field_type::ftStr},
+    {"TE", HDR_TE, field_type::ftStr},
+    {"Title", HDR_TITLE, field_type::ftStr},
+    {"Trailer", HDR_TRAILER, field_type::ftStr},
+    {"Transfer-Encoding", HDR_TRANSFER_ENCODING, field_type::ftStr},
+    {"Translate", HDR_TRANSLATE, field_type::ftStr},    /* for now. may need to crop */
+    {"Unless-Modified-Since", HDR_UNLESS_MODIFIED_SINCE, field_type::ftStr},  /* for now ignore. may need to crop */
+    {"Upgrade", HDR_UPGRADE, field_type::ftStr},    /* for now */
+    {"User-Agent", HDR_USER_AGENT, field_type::ftStr},
+    {"Vary", HDR_VARY, field_type::ftStr},  /* for now */
+    {"Via", HDR_VIA, field_type::ftStr},    /* for now */
+    {"Warning", HDR_WARNING, field_type::ftStr},    /* for now */
+    {"WWW-Authenticate", HDR_WWW_AUTHENTICATE, field_type::ftStr},
+    {"X-Cache", HDR_X_CACHE, field_type::ftStr},
+    {"X-Cache-Lookup", HDR_X_CACHE_LOOKUP, field_type::ftStr},
+    {"X-Forwarded-For", HDR_X_FORWARDED_FOR, field_type::ftStr},
+    {"X-Request-URI", HDR_X_REQUEST_URI, field_type::ftStr},
+    {"X-Squid-Error", HDR_X_SQUID_ERROR, field_type::ftStr},
+#if X_ACCELERATOR_VARY
+    {"X-Accelerator-Vary", HDR_X_ACCELERATOR_VARY, field_type::ftStr},
+#endif
+#if USE_ADAPTATION
+    {"X-Next-Services", HDR_X_NEXT_SERVICES, field_type::ftStr},
+#endif
+    {"Surrogate-Capability", HDR_SURROGATE_CAPABILITY, field_type::ftStr},
+    {"Surrogate-Control", HDR_SURROGATE_CONTROL, field_type::ftPSc},
+    {"Front-End-Https", HDR_FRONT_END_HTTPS, field_type::ftStr},
+    {"FTP-Command", HDR_FTP_COMMAND, field_type::ftStr},
+    {"FTP-Arguments", HDR_FTP_ARGUMENTS, field_type::ftStr},
+    {"FTP-Pre", HDR_FTP_PRE, field_type::ftStr},
+    {"FTP-Status", HDR_FTP_STATUS, field_type::ftInt},
+    {"FTP-Reason", HDR_FTP_REASON, field_type::ftStr},
+    {"Other:", HDR_OTHER, field_type::ftStr},    /* ':' will not allow matches */
+    {nullptr, HDR_BAD_HDR, field_type::ftInvalid}    /* end of table */
+};
+

=== modified file 'src/http/RegisteredHeaders.h'
--- src/http/RegisteredHeaders.h	2015-05-15 00:38:20 +0000
+++ src/http/RegisteredHeaders.h	2015-08-04 10:15:12 +0000
@@ -12,8 +12,7 @@
 /// recognized or "known" header fields; and the RFC which defines them (or not)
 /// http://www.iana.org/assignments/message-headers/message-headers.xhtml
 typedef enum {
-    HDR_BAD_HDR = -1,
-    HDR_ACCEPT = 0,                     /**< RFC 7231 */
+    HDR_ACCEPT = 0,                     /**< RFC 7231 */ /* MUST BE FIRST */
     HDR_ACCEPT_CHARSET,                 /**< RFC 7231 */
     HDR_ACCEPT_ENCODING,                /**< RFC 7231 */
     /*HDR_ACCEPT_FEATURES,*/            /* RFC 2295 */
@@ -116,8 +115,35 @@
     HDR_FTP_STATUS,                     /**< Internal header for FTP reply status */
     HDR_FTP_REASON,                     /**< Internal header for FTP reply reason */
     HDR_OTHER,                          /**< internal tag value for "unknown" headers */
-    HDR_ENUM_END
+    HDR_ENUM_END,                       /**< internal tag for end-of-valid headers */
+    HDR_BAD_HDR                         /**< Invalid header. Must be after HDR_ENUM_END */
 } http_hdr_type;
 
+/** possible types for http header fields */
+enum class field_type {
+    ftInvalid,// = HDR_ENUM_END,   /**< to catch nasty errors with hdr_id<->fld_type clashes */
+    ftInt,
+    ftInt64,
+    ftStr,
+    ftDate_1123,
+    ftETag,
+    ftPCc,
+    ftPContRange,
+    ftPRange,
+    ftPSc,
+    ftDate_1123_or_ETag
+};
+
+/* POD for headerTable */
+class HeaderTableRecord {
+public:
+    const char *name;
+    http_hdr_type id;
+    field_type type;
+};
+
+/// header name->http_hdr_type lookup table.
+extern const HeaderTableRecord headerTable[];
+
 #endif /* SQUID_HTTP_REGISTEREDHEADERS_H */
 

# Begin bundle
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
