--- trunk//src/base/Makefile.am	2011-09-27 13:17:48.885454000 +0200
+++ playground-patch//src/base/Makefile.am	2011-09-28 15:16:23.313575947 +0200
@@ -2,21 +2,22 @@
 include $(top_srcdir)/src/Common.am
 include $(top_srcdir)/src/TestHeaders.am
 
 noinst_LTLIBRARIES = libbase.la
 
 libbase_la_SOURCES = \
 	AsyncCall.cc \
 	AsyncCall.h \
 	AsyncJob.h \
 	AsyncJob.cc \
 	AsyncJobCalls.h \
 	AsyncCallQueue.cc \
 	AsyncCallQueue.h \
 	TidyPointer.h \
 	CbcPointer.h \
 	InstanceId.h \
 	RunnersRegistry.cc \
 	RunnersRegistry.h \
 	Subscription.h \
 	TextException.cc \
-	TextException.h
+	TextException.h \
+	StringArea.h
diff -Nr -U20 trunk//src/base/StringArea.h playground-patch//src/base/StringArea.h
--- trunk//src/base/StringArea.h	1970-01-01 01:00:00.000000000 +0100
+++ playground-patch//src/base/StringArea.h	2011-09-28 15:16:23.313575947 +0200
@@ -0,0 +1,67 @@
+/*
+ * StringArea.h
+ *
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ */
+
+#ifndef SQUID_STRINGAREA_H
+#define SQUID_STRINGAREA_H
+
+#if HAVE_CSTRING
+#include <cstring>
+#endif
+
+/** A char* plus length combination. Useful for temporary storing
+ * and quickly looking up strings.
+ *
+ * The pointed-to string may not be null-terminated.
+ * The pointed-to string is not copied.
+ *
+ * Not meant for stand-alone storage. Validity of the
+ * pointed-to string is responsibility of the caller.
+ */
+class StringArea {
+    public:
+    /// build a StringArea by explicitly assigning pointed-to area and and length
+    StringArea(const char * ptr, size_t len): theStart(ptr), theLen(len) {}
+    bool operator==(const StringArea &s) const { return theLen==s.theLen && memcmp(theStart,s.theStart,theLen)==0; }
+    bool operator!=(const StringArea &s) const { return !operator==(s); }
+    bool operator< ( const StringArea &s) const {
+        return (theLen < s.theLen || (theLen == s.theLen && memcmp(theStart,s.theStart,theLen) < 0)) ; }
+
+    private:
+    // default constructor is disabled
+    StringArea();
+
+    /// pointed to the externally-managed memory area
+    const char *theStart;
+    /// length of the string
+    size_t theLen;
+};
+
+#endif /* SQUID_STRINGAREA_H */
diff -Nr -U20 trunk//src/client_side_request.cc playground-patch//src/client_side_request.cc
--- trunk//src/client_side_request.cc	2011-09-27 13:17:48.885454000 +0200
+++ playground-patch//src/client_side_request.cc	2011-09-28 15:16:23.313575947 +0200
@@ -50,40 +50,41 @@
 #include "adaptation/Answer.h"
 #include "adaptation/Iterator.h"
 #include "adaptation/Service.h"
 #if ICAP_CLIENT
 #include "adaptation/icap/History.h"
 #endif
 #endif
 #if USE_AUTH
 #include "auth/UserRequest.h"
 #endif
 #include "clientStream.h"
 #include "client_side.h"
 #include "client_side_reply.h"
 #include "client_side_request.h"
 #include "ClientRequestContext.h"
 #include "comm/Connection.h"
 #include "comm/Write.h"
 #include "compat/inet_pton.h"
 #include "fde.h"
 #include "format/Tokens.h"
+#include "HttpHdrCc.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
 #include "ip/QosConfig.h"
 #include "MemObject.h"
 #include "ProtoPort.h"
 #include "Store.h"
 #include "SquidTime.h"
 #include "wordlist.h"
 #include "err_detail_type.h"
 #if USE_SSL
 #include "ssl/support.h"
 #endif
 
 
 #if LINGERING_CLOSE
 #define comm_close comm_lingering_close
 #endif
 
 static const char *const crlf = "\r\n";
 
@@ -177,41 +178,41 @@
     setConn(aConn);
     al.tcpClient = clientConnection = aConn->clientConnection;
     dlinkAdd(this, &active, &ClientActiveRequests);
 #if USE_ADAPTATION
     request_satisfaction_mode = false;
 #endif
 #if USE_SSL
     sslBumpNeed = needUnknown;
 #endif
 }
 
 /*
  * returns true if client specified that the object must come from the cache
  * without contacting origin server
  */
 bool
 ClientHttpRequest::onlyIfCached()const
 {
     assert(request);
     return request->cache_control &&
-           EBIT_TEST(request->cache_control->mask, CC_ONLY_IF_CACHED);
+           request->cache_control->onlyIfCached();
 }
 
 /*
  * This function is designed to serve a fairly specific purpose.
  * Occasionally our vBNS-connected caches can talk to each other, but not
  * the rest of the world.  Here we try to detect frequent failures which
  * make the cache unusable (e.g. DNS lookup and connect() failures).  If
  * the failure:success ratio goes above 1.0 then we go into "hit only"
  * mode where we only return UDP_HIT or UDP_MISS_NOFETCH.  Neighbors
  * will only fetch HITs from us if they are using the ICP protocol.  We
  * stay in this mode for 5 minutes.
  *
  * Duane W., Sept 16, 1996
  */
 
 #define FAILURE_MODE_TIME 300
 
 static void
 checkFailureRatio(err_type etype, hier_code hcode)
 {
@@ -1002,41 +1003,41 @@
     int no_cache = 0;
     const char *str;
 
     request->imslen = -1;
     request->ims = req_hdr->getTime(HDR_IF_MODIFIED_SINCE);
 
     if (request->ims > 0)
         request->flags.ims = 1;
 
     if (!request->flags.ignore_cc) {
         if (req_hdr->has(HDR_PRAGMA)) {
             String s = req_hdr->getList(HDR_PRAGMA);
 
             if (strListIsMember(&s, "no-cache", ','))
                 no_cache++;
 
             s.clean();
         }
 
         if (request->cache_control)
-            if (EBIT_TEST(request->cache_control->mask, CC_NO_CACHE))
+            if (request->cache_control->noCache())
                 no_cache++;
 
         /*
         * Work around for supporting the Reload button in IE browsers when Squid
         * is used as an accelerator or transparent proxy, by turning accelerated
         * IMS request to no-cache requests. Now knows about IE 5.5 fix (is
         * actually only fixed in SP1, but we can't tell whether we are talking to
         * SP1 or not so all 5.5 versions are treated 'normally').
         */
         if (Config.onoff.ie_refresh) {
             if (http->flags.accel && request->flags.ims) {
                 if ((str = req_hdr->getStr(HDR_USER_AGENT))) {
                     if (strstr(str, "MSIE 5.01") != NULL)
                         no_cache++;
                     else if (strstr(str, "MSIE 5.0") != NULL)
                         no_cache++;
                     else if (strstr(str, "MSIE 4.") != NULL)
                         no_cache++;
                     else if (strstr(str, "MSIE 3.") != NULL)
                         no_cache++;
diff -Nr -U20 trunk//src/enums.h playground-patch//src/enums.h
--- trunk//src/enums.h	2011-09-27 13:17:48.885454000 +0200
+++ playground-patch//src/enums.h	2011-09-28 15:16:23.313575947 +0200
@@ -201,41 +201,40 @@
 #endif
 
 typedef enum {
     MEM_NONE,
     MEM_2K_BUF,
     MEM_4K_BUF,
     MEM_8K_BUF,
     MEM_16K_BUF,
     MEM_32K_BUF,
     MEM_64K_BUF,
     MEM_ACL_DENY_INFO_LIST,
     MEM_ACL_NAME_LIST,
 #if USE_CACHE_DIGESTS
     MEM_CACHE_DIGEST,
 #endif
     MEM_CLIENT_INFO,
     MEM_LINK_LIST,
     MEM_DLINK_NODE,
     MEM_DREAD_CTRL,
     MEM_DWRITE_Q,
-    MEM_HTTP_HDR_CC,
     MEM_HTTP_HDR_CONTENT_RANGE,
     MEM_MD5_DIGEST,
     MEM_NETDBENTRY,
     MEM_NET_DB_NAME,
     MEM_RELIST,
     // IMPORTANT: leave this here. pools above are initialized early with memInit()
     MEM_DONTFREE,
     // following pools are initialized late by their component if needed (or never)
     MEM_FQDNCACHE_ENTRY,
     MEM_FWD_SERVER,
 #if !USE_DNSSERVERS
     MEM_IDNS_QUERY,
 #endif
     MEM_IPCACHE_ENTRY,
     MEM_MAX
 } mem_type;
 
 enum {
     STORE_LOG_CREATE,
     STORE_LOG_SWAPIN,
diff -Nr -U20 trunk//src/http.cc playground-patch//src/http.cc
--- trunk//src/http.cc	2011-09-27 13:17:48.885454000 +0200
+++ playground-patch//src/http.cc	2011-09-28 15:16:23.313575947 +0200
@@ -41,40 +41,41 @@
 #include "squid.h"
 
 #include "acl/FilledChecklist.h"
 #if USE_AUTH
 #include "auth/UserRequest.h"
 #endif
 #include "base/AsyncJobCalls.h"
 #include "base/TextException.h"
 #include "base64.h"
 #include "comm/Connection.h"
 #include "comm/Write.h"
 #if USE_DELAY_POOLS
 #include "DelayPools.h"
 #endif
 #include "err_detail_type.h"
 #include "errorpage.h"
 #include "fde.h"
 #include "http.h"
 #include "HttpControlMsg.h"
 #include "HttpHdrContRange.h"
+#include "HttpHdrCc.h"
 #include "HttpHdrSc.h"
 #include "HttpHdrScTarget.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
 #include "MemBuf.h"
 #include "MemObject.h"
 #include "protos.h"
 #include "rfc1738.h"
 #include "SquidTime.h"
 #include "Store.h"
 
 
 #define SQUID_ENTER_THROWING_CODE() try {
 #define SQUID_EXIT_THROWING_CODE(status) \
   	status = true; \
     } \
     catch (const std::exception &e) { \
 	debugs (11, 1, "Exception error:" << e.what()); \
 	status = false; \
     }
@@ -313,92 +314,92 @@
                 else
                     reply->expires = reply->date + sctusable->max_stale;
 
                 /* And update the timestamps */
                 entry->timestampsSet();
             }
 
             /* We ignore cache-control directives as per the Surrogate specification */
             ignoreCacheControl = true;
 
             httpHdrScTargetDestroy(sctusable);
         }
     }
 }
 
 int
 HttpStateData::cacheableReply()
 {
     HttpReply const *rep = finalReply();
     HttpHeader const *hdr = &rep->header;
-    const int cc_mask = (rep->cache_control) ? rep->cache_control->mask : 0;
     const char *v;
 #if USE_HTTP_VIOLATIONS
 
     const refresh_t *R = NULL;
 
     /* This strange looking define first looks up the refresh pattern
      * and then checks if the specified flag is set. The main purpose
      * of this is to simplify the refresh pattern lookup and USE_HTTP_VIOLATIONS
      * condition
      */
 #define REFRESH_OVERRIDE(flag) \
     ((R = (R ? R : refreshLimits(entry->mem_obj->url))) , \
     (R && R->flags.flag))
 #else
 #define REFRESH_OVERRIDE(flag) 0
 #endif
 
     if (surrogateNoStore)
         return 0;
 
     // RFC 2616: do not cache replies to responses with no-store CC directive
     if (request && request->cache_control &&
-            EBIT_TEST(request->cache_control->mask, CC_NO_STORE) &&
+            request->cache_control->noStore() &&
             !REFRESH_OVERRIDE(ignore_no_store))
         return 0;
 
-    if (!ignoreCacheControl) {
-        if (EBIT_TEST(cc_mask, CC_PRIVATE)) {
+    if (!ignoreCacheControl && request->cache_control != NULL) {
+        const HttpHdrCc* cc=request->cache_control;
+        if (cc->Private()) {
             if (!REFRESH_OVERRIDE(ignore_private))
                 return 0;
         }
 
-        if (EBIT_TEST(cc_mask, CC_NO_CACHE)) {
+        if (cc->noCache()) {
             if (!REFRESH_OVERRIDE(ignore_no_cache))
                 return 0;
         }
 
-        if (EBIT_TEST(cc_mask, CC_NO_STORE)) {
+        if (cc->noStore()) {
             if (!REFRESH_OVERRIDE(ignore_no_store))
                 return 0;
         }
     }
 
     if (request->flags.auth || request->flags.auth_sent) {
         /*
          * Responses to requests with authorization may be cached
          * only if a Cache-Control: public reply header is present.
          * RFC 2068, sec 14.9.4
          */
 
-        if (!EBIT_TEST(cc_mask, CC_PUBLIC)) {
+        if (!request->cache_control->Public()) {
             if (!REFRESH_OVERRIDE(ignore_auth))
                 return 0;
         }
     }
 
     /* Pragma: no-cache in _replies_ is not documented in HTTP,
      * but servers like "Active Imaging Webcast/2.0" sure do use it */
     if (hdr->has(HDR_PRAGMA)) {
         String s = hdr->getList(HDR_PRAGMA);
         const int no_cache = strListIsMember(&s, "no-cache", ',');
         s.clean();
 
         if (no_cache) {
             if (!REFRESH_OVERRIDE(ignore_no_cache))
                 return 0;
         }
     }
 
     /*
      * The "multipart/x-mixed-replace" content type is used for
@@ -908,43 +909,44 @@
     case -1:
 
 #if USE_HTTP_VIOLATIONS
         if (Config.negativeTtl > 0)
             entry->cacheNegatively();
         else
 #endif
             entry->makePrivate();
 
         break;
 
     default:
         assert(0);
 
         break;
     }
 
 no_cache:
 
     if (!ignoreCacheControl && rep->cache_control) {
-        if (EBIT_TEST(rep->cache_control->mask, CC_PROXY_REVALIDATE) ||
-                EBIT_TEST(rep->cache_control->mask, CC_MUST_REVALIDATE) ||
-                EBIT_TEST(rep->cache_control->mask, CC_S_MAXAGE))
+        if (rep->cache_control->proxyRevalidate() ||
+                rep->cache_control->mustRevalidate() ||
+                rep->cache_control->haveSMaxAge()
+                )
             EBIT_SET(entry->flags, ENTRY_REVALIDATE);
     }
 
 #if HEADERS_LOG
     headersLog(1, 0, request->method, rep);
 
 #endif
 
     ctx_exit(ctx);
 }
 
 HttpStateData::ConnectionStatus
 HttpStateData::statusIfComplete() const
 {
     const HttpReply *rep = virginReply();
     /** \par
      * If the reply wants to close the connection, it takes precedence */
 
     if (httpHeaderHasConnDir(&rep->header, "close"))
         return COMPLETE_NONPERSISTENT_MSG;
@@ -1743,63 +1745,63 @@
                               (int) request->port);
         }
     }
 
     /* append Authorization if known in URL, not in header and going direct */
     if (!hdr_out->has(HDR_AUTHORIZATION)) {
         if (!request->flags.proxying && request->login && *request->login) {
             httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
                               old_base64_encode(request->login));
         }
     }
 
     /* Fixup (Proxy-)Authorization special cases. Plain relaying dealt with above */
     httpFixupAuthentication(request, hdr_in, hdr_out, flags);
 
     /* append Cache-Control, add max-age if not there already */
     {
         HttpHdrCc *cc = hdr_in->getCc();
 
         if (!cc)
-            cc = httpHdrCcCreate();
+            cc = new HttpHdrCc();
 
 #if 0 /* see bug 2330 */
         /* Set no-cache if determined needed but not found */
         if (request->flags.nocache)
             EBIT_SET(cc->mask, CC_NO_CACHE);
 #endif
 
         /* Add max-age only without no-cache */
-        if (!EBIT_TEST(cc->mask, CC_MAX_AGE) && !EBIT_TEST(cc->mask, CC_NO_CACHE)) {
+        if (cc->haveMaxAge() && !cc->noCache()) {
             const char *url =
                 entry ? entry->url() : urlCanonical(request);
-            httpHdrCcSetMaxAge(cc, getMaxAge(url));
+            cc->maxAge(getMaxAge(url));
 
         }
 
         /* Enforce sibling relations */
         if (flags.only_if_cached)
-            EBIT_SET(cc->mask, CC_ONLY_IF_CACHED);
+            cc->onlyIfCached(true);
 
         hdr_out->putCc(cc);
 
-        httpHdrCcDestroy(cc);
+        delete cc;
     }
 
     /* maybe append Connection: keep-alive */
     if (flags.keepalive) {
         hdr_out->putStr(HDR_CONNECTION, "keep-alive");
     }
 
     /* append Front-End-Https */
     if (flags.front_end_https) {
         if (flags.front_end_https == 1 || request->protocol == AnyP::PROTO_HTTPS)
             hdr_out->putStr(HDR_FRONT_END_HTTPS, "On");
     }
 
     if (flags.chunked_request) {
         // Do not just copy the original value so that if the client-side
         // starts decode other encodings, this code may remain valid.
         hdr_out->putStr(HDR_TRANSFER_ENCODING, "chunked");
     }
 
     /* Now mangle the headers. */
diff -Nr -U20 trunk//src/HttpHdrCc.cc playground-patch//src/HttpHdrCc.cc
--- trunk//src/HttpHdrCc.cc	2011-09-27 13:17:48.885454000 +0200
+++ playground-patch//src/HttpHdrCc.cc	2011-09-28 15:16:23.293575947 +0200
@@ -1,332 +1,271 @@
-
 /*
- * $Id$
  *
  * DEBUG: section 65    HTTP Cache Control Header
- * AUTHOR: Alex Rousskov
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
  * ----------------------------------------------------------
  *
  *  Squid is the result of efforts by numerous individuals from
  *  the Internet community; see the CONTRIBUTORS file for full
  *  details.   Many organizations have provided support for Squid's
  *  development; see the SPONSORS file for full details.  Squid is
  *  Copyrighted (C) 2001 by the Regents of the University of
  *  California; see the COPYRIGHT file for full details.  Squid
  *  incorporates software developed and/or copyrighted by other
  *  sources; see the CREDITS file for full details.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #include "squid.h"
+#include "base/StringArea.h"
 #include "Store.h"
 #include "HttpHeader.h"
+#include "HttpHdrCc.h"
 
-/* this table is used for parsing cache control header */
-static const HttpHeaderFieldAttrs CcAttrs[CC_ENUM_END] = {
-    {"public", (http_hdr_type)CC_PUBLIC},
-
-    {"private", (http_hdr_type)CC_PRIVATE},
-    {"no-cache", (http_hdr_type)CC_NO_CACHE},
-    {"no-store", (http_hdr_type)CC_NO_STORE},
-    {"no-transform", (http_hdr_type)CC_NO_TRANSFORM},
-    {"must-revalidate", (http_hdr_type)CC_MUST_REVALIDATE},
-    {"proxy-revalidate", (http_hdr_type)CC_PROXY_REVALIDATE},
-    {"only-if-cached", (http_hdr_type)CC_ONLY_IF_CACHED},
-    {"max-age", (http_hdr_type)CC_MAX_AGE},
-    {"s-maxage", (http_hdr_type)CC_S_MAXAGE},
-    {"max-stale", (http_hdr_type)CC_MAX_STALE},
-    {"stale-if-error", (http_hdr_type)CC_STALE_IF_ERROR},
-    {"min-fresh", (http_hdr_type)CC_MIN_FRESH},
-    {"Other,", (http_hdr_type)CC_OTHER}	/* ',' will protect from matches */
+#if HAVE_MAP
+#include <map>
+#endif
+
+/* a row in the table used for parsing cache control header and statistics */
+typedef struct {
+    const char *name;
+    http_hdr_cc_type id;
+    HttpHeaderFieldStat stat;
+} HttpHeaderCcFields;
+
+/* order must match that of enum http_hdr_cc_type. The constraint is verified at initialization time */
+static HttpHeaderCcFields CcAttrs[CC_ENUM_END] = {
+        {"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 */
 };
 
-HttpHeaderFieldInfo *CcFieldsInfo = NULL;
+/// Map an header name to its type, to expedite parsing
+typedef std::map<const StringArea,http_hdr_cc_type> CcNameToIdMap_t;
+static CcNameToIdMap_t CcNameToIdMap;
 
+/// iterate over a table of http_header_cc_type structs
 http_hdr_cc_type &operator++ (http_hdr_cc_type &aHeader)
 {
     int tmp = (int)aHeader;
     aHeader = (http_hdr_cc_type)(++tmp);
     return aHeader;
 }
 
 
-/* local prototypes */
-static int httpHdrCcParseInit(HttpHdrCc * cc, const String * str);
-
-
-/* module initialization */
-
+/// Module initialization hook
 void
 httpHdrCcInitModule(void)
 {
-    CcFieldsInfo = httpHeaderBuildFieldsInfo(CcAttrs, CC_ENUM_END);
+    /* 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 StringArea k(f.name,strlen(f.name));
+        CcNameToIdMap[k]=f.id;
+    }
 }
 
+/// Module cleanup hook.
 void
 httpHdrCcCleanModule(void)
 {
-    httpHeaderDestroyFieldsInfo(CcFieldsInfo, CC_ENUM_END);
-    CcFieldsInfo = NULL;
+    // HdrCcNameToIdMap is self-cleaning
 }
 
-/* implementation */
-
-HttpHdrCc *
-httpHdrCcCreate(void)
-{
-    HttpHdrCc *cc = (HttpHdrCc *)memAllocate(MEM_HTTP_HDR_CC);
-    cc->max_age = cc->s_maxage = cc->max_stale = cc->min_fresh = -1;
-    return cc;
-}
-
-/* creates an cc object from a 0-terminating string */
-HttpHdrCc *
-httpHdrCcParseCreate(const String * str)
+void
+HttpHdrCc::clear()
 {
-    HttpHdrCc *cc = httpHdrCcCreate();
-
-    if (!httpHdrCcParseInit(cc, str)) {
-        httpHdrCcDestroy(cc);
-        cc = NULL;
-    }
-
-    return cc;
+    *this=HttpHdrCc();
 }
 
-/* parses a 0-terminating string and inits cc */
-static int
-httpHdrCcParseInit(HttpHdrCc * cc, const String * str)
+bool
+HttpHdrCc::parse(const String & str)
 {
     const char *item;
     const char *p;		/* '=' parameter */
     const char *pos = NULL;
     http_hdr_cc_type type;
     int ilen;
     int nlen;
-    assert(cc && str);
 
     /* iterate through comma separated list */
 
-    while (strListGetItem(str, ',', &item, &ilen, &pos)) {
+    while (strListGetItem(&str, ',', &item, &ilen, &pos)) {
         /* isolate directive name */
 
         if ((p = (const char *)memchr(item, '=', ilen)) && (p - item < ilen))
             nlen = p++ - item;
         else
             nlen = ilen;
 
         /* find type */
-        type = (http_hdr_cc_type ) httpHeaderIdByName(item, nlen,
-                CcFieldsInfo, CC_ENUM_END);
-
-        if (type < 0) {
-            debugs(65, 2, "hdr cc: unknown cache-directive: near '" << item << "' in '" << str << "'");
-            type = CC_OTHER;
-        }
+        const CcNameToIdMap_t::const_iterator i=CcNameToIdMap.find(StringArea(item,nlen));
+        if (i==CcNameToIdMap.end())
+            type=CC_OTHER;
+        else
+            type=i->second;
 
         // ignore known duplicate directives
-        if (EBIT_TEST(cc->mask, type)) {
+        if (isSet(type)) {
             if (type != CC_OTHER) {
                 debugs(65, 2, "hdr cc: ignoring duplicate cache-directive: near '" << item << "' in '" << str << "'");
-                CcFieldsInfo[type].stat.repCount++;
+                ++CcAttrs[type].stat.repCount;
                 continue;
             }
-        } else {
-            EBIT_SET(cc->mask, type);
         }
 
-        /* post-processing special cases */
+        /* special-case-parsing and attribute-setting */
         switch (type) {
 
         case CC_MAX_AGE:
-
-            if (!p || !httpHeaderParseInt(p, &cc->max_age)) {
+            int32_t ma;
+            if (!p || !httpHeaderParseInt(p, &ma)) {
                 debugs(65, 2, "cc: invalid max-age specs near '" << item << "'");
-                cc->max_age = -1;
-                EBIT_CLR(cc->mask, type);
+                clearMaxAge();
+            } else {
+                maxAge(ma);
             }
-
             break;
 
         case CC_S_MAXAGE:
-
-            if (!p || !httpHeaderParseInt(p, &cc->s_maxage)) {
+            if (!p || !httpHeaderParseInt(p, &s_maxage)) {
                 debugs(65, 2, "cc: invalid s-maxage specs near '" << item << "'");
-                cc->s_maxage = -1;
-                EBIT_CLR(cc->mask, type);
+                clearSMaxAge();
             }
-
             break;
 
         case CC_MAX_STALE:
-
-            if (!p || !httpHeaderParseInt(p, &cc->max_stale)) {
+            if (!p || !httpHeaderParseInt(p, &max_stale)) {
                 debugs(65, 2, "cc: max-stale directive is valid without value");
-                cc->max_stale = -1;
+                maxStale(MAX_STALE_ALWAYS);
             }
-
             break;
 
         case CC_MIN_FRESH:
-
-            if (!p || !httpHeaderParseInt(p, &cc->min_fresh)) {
+            if (!p || !httpHeaderParseInt(p, &min_fresh)) {
                 debugs(65, 2, "cc: invalid min-fresh specs near '" << item << "'");
-                cc->min_fresh = -1;
-                EBIT_CLR(cc->mask, type);
+                clearMinFresh();
             }
-
             break;
 
         case CC_STALE_IF_ERROR:
-            if (!p || !httpHeaderParseInt(p, &cc->stale_if_error)) {
+            if (!p || !httpHeaderParseInt(p, &stale_if_error)) {
                 debugs(65, 2, "cc: invalid stale-if-error specs near '" << item << "'");
-                cc->stale_if_error = -1;
-                EBIT_CLR(cc->mask, type);
+                clearStaleIfError();
             }
             break;
 
-        case CC_OTHER:
-
-            if (cc->other.size())
-                cc->other.append(", ");
+        case CC_PUBLIC: Public(true); break;
+        case CC_PRIVATE: Private(true); break;
+        case CC_NO_CACHE: noCache(true); break;
+        case CC_NO_STORE: noStore(true); break;
+        case CC_NO_TRANSFORM: noTransform(true); break;
+        case CC_MUST_REVALIDATE: mustRevalidate(true); break;
+        case CC_PROXY_REVALIDATE: proxyRevalidate(true); break;
+        case CC_ONLY_IF_CACHED: onlyIfCached(true); break;
 
-            cc->other.append(item, ilen);
+        case CC_OTHER:
+            if (other.size())
+                other.append(", ");
 
+            other.append(item, ilen);
             break;
 
         default:
             /* note that we ignore most of '=' specs (RFCVIOLATION) */
             break;
         }
     }
 
-    return cc->mask != 0;
+    return (mask != 0);
 }
 
 void
-httpHdrCcDestroy(HttpHdrCc * cc)
-{
-    assert(cc);
-
-    if (cc->other.defined())
-        cc->other.clean();
-
-    memFree(cc, MEM_HTTP_HDR_CC);
-}
-
-HttpHdrCc *
-httpHdrCcDup(const HttpHdrCc * cc)
-{
-    HttpHdrCc *dup;
-    assert(cc);
-    dup = httpHdrCcCreate();
-    dup->mask = cc->mask;
-    dup->max_age = cc->max_age;
-    dup->s_maxage = cc->s_maxage;
-    dup->max_stale = cc->max_stale;
-    dup->min_fresh = cc->min_fresh;
-    return dup;
-}
-
-void
-httpHdrCcPackInto(const HttpHdrCc * cc, Packer * p)
+HttpHdrCc::packInto(Packer * p) const
 {
     http_hdr_cc_type flag;
     int pcount = 0;
-    assert(cc && p);
+    assert(p);
 
     for (flag = CC_PUBLIC; flag < CC_ENUM_END; ++flag) {
-        if (EBIT_TEST(cc->mask, flag) && flag != CC_OTHER) {
+        if (isSet(flag) && flag != CC_OTHER) {
 
             /* print option name */
-            packerPrintf(p, (pcount ? ", " SQUIDSTRINGPH : SQUIDSTRINGPH),
-                         SQUIDSTRINGPRINT(CcFieldsInfo[flag].name));
+            packerPrintf(p, (pcount ? ", %s": "%s") , CcAttrs[flag].name);
 
             /* handle options with values */
 
             if (flag == CC_MAX_AGE)
-                packerPrintf(p, "=%d", (int) cc->max_age);
+                packerPrintf(p, "=%d", (int) maxAge());
 
             if (flag == CC_S_MAXAGE)
-                packerPrintf(p, "=%d", (int) cc->s_maxage);
+                packerPrintf(p, "=%d", (int) sMaxAge());
 
-            if (flag == CC_MAX_STALE && cc->max_stale >= 0)
-                packerPrintf(p, "=%d", (int) cc->max_stale);
+            if (flag == CC_MAX_STALE && maxStale()!=MAX_STALE_ALWAYS)
+                packerPrintf(p, "=%d", (int) maxStale());
 
             if (flag == CC_MIN_FRESH)
-                packerPrintf(p, "=%d", (int) cc->min_fresh);
+                packerPrintf(p, "=%d", (int) minFresh());
 
-            pcount++;
+            ++pcount;
         }
     }
 
-    if (cc->other.size() != 0)
+    if (other.size() != 0)
         packerPrintf(p, (pcount ? ", " SQUIDSTRINGPH : SQUIDSTRINGPH),
-                     SQUIDSTRINGPRINT(cc->other));
-}
-
-/* negative max_age will clean old max_Age setting */
-void
-httpHdrCcSetMaxAge(HttpHdrCc * cc, int max_age)
-{
-    assert(cc);
-    cc->max_age = max_age;
-
-    if (max_age >= 0)
-        EBIT_SET(cc->mask, CC_MAX_AGE);
-    else
-        EBIT_CLR(cc->mask, CC_MAX_AGE);
-}
-
-/* negative s_maxage will clean old s-maxage setting */
-void
-httpHdrCcSetSMaxAge(HttpHdrCc * cc, int s_maxage)
-{
-    assert(cc);
-    cc->s_maxage = s_maxage;
-
-    if (s_maxage >= 0)
-        EBIT_SET(cc->mask, CC_S_MAXAGE);
-    else
-        EBIT_CLR(cc->mask, CC_S_MAXAGE);
+                     SQUIDSTRINGPRINT(other));
 }
 
 void
 httpHdrCcUpdateStats(const HttpHdrCc * cc, StatHist * hist)
 {
     http_hdr_cc_type c;
     assert(cc);
 
     for (c = CC_PUBLIC; c < CC_ENUM_END; ++c)
-        if (EBIT_TEST(cc->mask, c))
+        if (cc->isSet(c))
             statHistCount(hist, c);
 }
 
 void
 httpHdrCcStatDumper(StoreEntry * sentry, int idx, double val, double size, int count)
 {
     extern const HttpHeaderStat *dump_stat;	/* argh! */
     const int id = (int) val;
     const int valid_id = id >= 0 && id < CC_ENUM_END;
-    const char *name = valid_id ? CcFieldsInfo[id].name.termedBuf() : "INVALID";
+    const char *name = valid_id ? CcAttrs[id].name : "INVALID";
 
     if (count || valid_id)
         storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
                           id, name, count, xdiv(count, dump_stat->ccParsedCount));
 }
+
+#if !_USE_INLINE_
+#include "HttpHdrCc.cci"
+#endif
diff -Nr -U20 trunk//src/HttpHdrCc.cci playground-patch//src/HttpHdrCc.cci
--- trunk//src/HttpHdrCc.cci	1970-01-01 01:00:00.000000000 +0100
+++ playground-patch//src/HttpHdrCc.cci	2011-09-28 15:16:23.293575947 +0200
@@ -0,0 +1,46 @@
+/*
+ *
+ * DEBUG: section 65    HTTP Cache Control Header
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+bool
+HttpHdrCc::isSet(http_hdr_cc_type id) const
+{
+    assert(id>=CC_PUBLIC && id < CC_ENUM_END);
+    return EBIT_TEST(mask,id);
+}
+
+void
+HttpHdrCc::setMask(http_hdr_cc_type id, bool newval)
+{
+    if (newval)
+        EBIT_SET(mask,id);
+    else
+        EBIT_CLR(mask,id);
+}
diff -Nr -U20 trunk//src/HttpHdrCc.h playground-patch//src/HttpHdrCc.h
--- trunk//src/HttpHdrCc.h	1970-01-01 01:00:00.000000000 +0100
+++ playground-patch//src/HttpHdrCc.h	2011-09-28 15:16:23.303575947 +0200
@@ -0,0 +1,183 @@
+/*
+ * HttpHdrCc.h
+ *
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ */
+
+#ifndef SQUID_HTTPHDRCC_H
+#define SQUID_HTTPHDRCC_H
+
+#include "config.h"
+#include "MemPool.h"
+#include "SquidString.h"
+
+/** Http Cache-Control header representation
+ *
+ * Store and parse the Cache-Control HTTP header.
+ */
+class HttpHdrCc
+{
+
+public:
+	static const int32_t MAX_AGE_UNKNOWN=-1; //max-age is unset
+	static const int32_t S_MAXAGE_UNKNOWN=-1; //s-maxage is unset
+	static const int32_t MAX_STALE_UNKNOWN=-1; //max-stale is unset
+	static const int32_t MAX_STALE_ALWAYS=-2; //max-stale is set to no value
+	static const int32_t STALE_IF_ERROR_UNKNOWN=-1; //stale_if_error is unset
+	static const int32_t MIN_FRESH_UNKNOWN=-1; //min_fresh is unset
+
+    HttpHdrCc() :
+            mask(0), max_age(MAX_AGE_UNKNOWN), s_maxage(S_MAXAGE_UNKNOWN),
+            max_stale(MAX_STALE_UNKNOWN), stale_if_error(STALE_IF_ERROR_UNKNOWN),
+            min_fresh(MIN_FRESH_UNKNOWN) {}
+
+    /// reset data-members to default state
+    void clear();
+
+    /// parse a header-string and fill in appropriate values.
+    bool parse(const String & s);
+
+    //manipulation for Cache-Control: public header
+    inline bool havePublic() const {return isSet(CC_PUBLIC);}
+    inline bool Public() const {return isSet(CC_PUBLIC);}
+    inline void Public(bool newval) {setMask(CC_PUBLIC,newval);}
+    inline void clearPublic() {setMask(CC_PUBLIC,false);}
+
+    //manipulation for Cache-Control: private header
+    inline bool havePrivate() const {return isSet(CC_PRIVATE);}
+    inline bool Private() const {return isSet(CC_PRIVATE);}
+    inline void Private(bool newval) {setMask(CC_PRIVATE,newval);}
+    inline void clearPrivate() {setMask(CC_PRIVATE,false);}
+
+    //manipulation for Cache-Control: no-cache header
+    inline bool haveNoCache() const {return isSet(CC_NO_CACHE);}
+    inline bool noCache() const {return isSet(CC_NO_CACHE);}
+    inline void noCache(bool newval) {setMask(CC_NO_CACHE,newval);}
+    inline void clearNoCache() {setMask(CC_NO_CACHE,false);}
+
+    //manipulation for Cache-Control: no-store header
+    inline bool haveNoStore() const {return isSet(CC_NO_STORE);}
+    inline bool noStore() const {return isSet(CC_NO_STORE);}
+    inline void noStore(bool newval) {setMask(CC_NO_STORE,newval);}
+    inline void clearNoStore() {setMask(CC_NO_STORE,false);}
+
+    //manipulation for Cache-Control: no-transform header
+    inline bool haveNoTransform() const {return isSet(CC_NO_TRANSFORM);}
+    inline bool noTransform() const {return isSet(CC_NO_TRANSFORM);}
+    inline void noTransform(bool newval) {setMask(CC_NO_TRANSFORM,newval);}
+    inline void clearNoTransform() {setMask(CC_NO_TRANSFORM,false);}
+
+    //manipulation for Cache-Control: must-revalidate header
+    inline bool haveMustRevalidate() const {return isSet(CC_MUST_REVALIDATE);}
+    inline bool mustRevalidate() const {return isSet(CC_MUST_REVALIDATE);}
+    inline void mustRevalidate(bool newval) {setMask(CC_MUST_REVALIDATE,newval);}
+    inline void clearMustRevalidate() {setMask(CC_MUST_REVALIDATE,false);}
+
+    //manipulation for Cache-Control: proxy-revalidate header
+    inline bool haveProxyRevalidate() const {return isSet(CC_PROXY_REVALIDATE);}
+    inline bool proxyRevalidate() const {return isSet(CC_PROXY_REVALIDATE);}
+    inline void proxyRevalidate(bool newval) {setMask(CC_PROXY_REVALIDATE,newval);}
+    inline void clearProxyRevalidate() {setMask(CC_PROXY_REVALIDATE,false);}
+
+    //manipulation for Cache-Control: max-age header
+    inline bool haveMaxAge() const {return isSet(CC_MAX_AGE);}
+    inline int32_t maxAge() const { return max_age;}
+    inline void maxAge(int32_t newval) {if (newval < 0) return; max_age = newval; setMask(CC_MAX_AGE); }
+    inline void clearMaxAge() {max_age=MAX_AGE_UNKNOWN; setMask(CC_MAX_AGE,false);}
+
+    //manipulation for Cache-Control: s-maxage header
+    inline bool haveSMaxAge() const {return isSet(CC_S_MAXAGE);}
+    inline int32_t sMaxAge() const { return s_maxage;}
+    inline void sMaxAge(int32_t newval) {if (newval < 0) return; s_maxage = newval; setMask(CC_S_MAXAGE); }
+    inline void clearSMaxAge() {s_maxage=MAX_AGE_UNKNOWN; setMask(CC_S_MAXAGE,false);}
+
+    //manipulation for Cache-Control: max-stale header
+    inline bool haveMaxStale() const {return isSet(CC_MAX_STALE);}
+    inline int32_t maxStale() const { return max_stale;}
+    // max-stale has a special value (MAX_STALE_ALWAYS) which correspond to having
+    // the directive without a numeric specification, and directs to consider the object
+    // as always-expired.
+    inline void maxStale(int32_t newval) {
+        if (newval < 0 && newval != CC_MAX_STALE) return;
+        max_stale = newval; setMask(CC_MAX_STALE); }
+    inline void clearMaxStale() {max_stale=MAX_STALE_UNKNOWN; setMask(CC_MAX_STALE,false);}
+
+    //manipulation for Cache-Control:min-fresh header
+    inline bool haveMinFresh() const {return isSet(CC_MIN_FRESH);}
+    inline int32_t minFresh() const { return min_fresh;}
+    inline void minFresh(int32_t newval) {if (newval < 0) return; min_fresh = newval; setMask(CC_MIN_FRESH); }
+    inline void clearMinFresh() {min_fresh=MIN_FRESH_UNKNOWN; setMask(CC_MIN_FRESH,false);}
+
+    //manipulation for Cache-Control: only-if-cached header
+    inline bool haveOnlyIfCached() const {return isSet(CC_ONLY_IF_CACHED);}
+    inline bool onlyIfCached() const {return isSet(CC_ONLY_IF_CACHED);}
+    inline void onlyIfCached(bool newval) {setMask(CC_ONLY_IF_CACHED,newval);}
+    inline void clearOnlyIfCached() {setMask(CC_ONLY_IF_CACHED,false);}
+
+    //manipulation for Cache-Control: stale-if-error header
+    inline bool haveStaleIfError() const {return isSet(CC_STALE_IF_ERROR);}
+    inline int32_t staleIfError() const { return stale_if_error;}
+    inline void staleIfError(int32_t newval) {if (newval < 0) return; stale_if_error = newval; setMask(CC_STALE_IF_ERROR); }
+    inline void clearStaleIfError() {stale_if_error=STALE_IF_ERROR_UNKNOWN; setMask(CC_STALE_IF_ERROR,false);}
+
+    /// check whether the attribute value supplied by id is set
+    _SQUID_INLINE_ bool isSet(http_hdr_cc_type id) const;
+
+    void packInto(Packer * p) const;
+
+    MEMPROXY_CLASS(HttpHdrCc);
+
+    /** bit-mask representing what header values are set among those
+     * recognized by squid.
+     *
+     * managed via EBIT_SET/TEST/CLR
+     */
+private:
+    int32_t mask;
+    int32_t max_age;
+    int32_t s_maxage;
+    int32_t max_stale;
+    int32_t stale_if_error;
+    int32_t min_fresh;
+    /// low-level part of the public set method, performs no checks
+    _SQUID_INLINE_ void setMask(http_hdr_cc_type id, bool newval=true);
+
+public:
+    /**comma-separated representation of the header values which were
+     * received but are not recognized.
+     */
+    String other;
+};
+
+MEMPROXY_CLASS_INLINE(HttpHdrCc);
+
+#if _USE_INLINE_
+#include "HttpHdrCc.cci"
+#endif
+
+#endif /* SQUID_HTTPHDRCC_H */
diff -Nr -U20 trunk//src/HttpHeader.cc playground-patch//src/HttpHeader.cc
--- trunk//src/HttpHeader.cc	2011-09-27 13:17:48.885454000 +0200
+++ playground-patch//src/HttpHeader.cc	2011-09-28 15:16:23.303575947 +0200
@@ -19,40 +19,41 @@
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #include "squid.h"
 #include "base64.h"
 #include "HttpHdrContRange.h"
+#include "HttpHdrCc.h"
 #include "HttpHdrSc.h"
 #include "HttpHeader.h"
 #include "MemBuf.h"
 #include "mgr/Registration.h"
 #include "rfc1123.h"
 #include "Store.h"
 #include "TimeOrTag.h"
 
 /*
  * On naming conventions:
  *
  * HTTP/1.1 defines message-header as
  *
  * message-header = field-name ":" [ field-value ] CRLF
  * field-name     = token
  * field-value    = *( field-content | LWS )
  *
  * HTTP/1.1 does not give a name name a group of all message-headers in a message.
  * Squid 1.1 seems to refer to that group _plus_ start-line as "headers".
  *
@@ -1134,41 +1135,41 @@
 }
 
 void
 HttpHeader::putAuth(const char *auth_scheme, const char *realm)
 {
     assert(auth_scheme && realm);
     httpHeaderPutStrf(this, HDR_WWW_AUTHENTICATE, "%s realm=\"%s\"", auth_scheme, realm);
 }
 
 void
 HttpHeader::putCc(const HttpHdrCc * cc)
 {
     MemBuf mb;
     Packer p;
     assert(cc);
     /* remove old directives if any */
     delById(HDR_CACHE_CONTROL);
     /* pack into mb */
     mb.init();
     packerToMemInit(&p, &mb);
-    httpHdrCcPackInto(cc, &p);
+    cc->packInto(&p);
     /* put */
     addEntry(new HttpHeaderEntry(HDR_CACHE_CONTROL, NULL, mb.buf));
     /* cleanup */
     packerClean(&p);
     mb.clean();
 }
 
 void
 HttpHeader::putContRange(const HttpHdrContRange * cr)
 {
     MemBuf mb;
     Packer p;
     assert(cr);
     /* remove old directives if any */
     delById(HDR_CONTENT_RANGE);
     /* pack into mb */
     mb.init();
     packerToMemInit(&p, &mb);
     httpHdrContRangePackInto(cr, &p);
     /* put */
@@ -1293,50 +1294,53 @@
 
 /* unusual */
 const char *
 HttpHeader::getLastStr(http_hdr_type id) const
 {
     HttpHeaderEntry *e;
     assert_eid(id);
     assert(Headers[id].type == ftStr);	/* must be of an appropriate type */
 
     if ((e = findLastEntry(id))) {
         httpHeaderNoteParsedEntry(e->id, e->value, 0);	/* no errors are possible */
         return e->value.termedBuf();
     }
 
     return NULL;
 }
 
 HttpHdrCc *
 HttpHeader::getCc() const
 {
-    HttpHdrCc *cc;
-    String s;
-
     if (!CBIT_TEST(mask, HDR_CACHE_CONTROL))
         return NULL;
     PROF_start(HttpHeader_getCc);
 
+    String s;
     getList(HDR_CACHE_CONTROL, &s);
 
-    cc = httpHdrCcParseCreate(&s);
+    HttpHdrCc *cc=new HttpHdrCc();
+
+    if (!cc->parse(s)) {
+        delete cc;
+        cc = NULL;
+    }
 
     HttpHeaderStats[owner].ccParsedCount++;
 
     if (cc)
         httpHdrCcUpdateStats(cc, &HttpHeaderStats[owner].ccTypeDistr);
 
     httpHeaderNoteParsedEntry(HDR_CACHE_CONTROL, s, !cc);
 
     PROF_stop(HttpHeader_getCc);
 
     return cc;
 }
 
 HttpHdrRange *
 HttpHeader::getRange() const
 {
     HttpHdrRange *r = NULL;
     HttpHeaderEntry *e;
     /* some clients will send "Request-Range" _and_ *matching* "Range"
      * who knows, some clients might send Request-Range only;
diff -Nr -U20 trunk//src/HttpReply.cc playground-patch//src/HttpReply.cc
--- trunk//src/HttpReply.cc	2011-09-27 13:17:48.885454000 +0200
+++ playground-patch//src/HttpReply.cc	2011-09-28 15:16:23.303575947 +0200
@@ -21,40 +21,41 @@
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #include "squid.h"
 #include "SquidTime.h"
 #include "Store.h"
 #include "HttpReply.h"
 #include "HttpHdrContRange.h"
+#include "HttpHdrCc.h"
 #include "HttpHdrSc.h"
 #include "acl/FilledChecklist.h"
 #include "HttpRequest.h"
 #include "MemBuf.h"
 
 /* local constants */
 
 /* If we receive a 304 from the origin during a cache revalidation, we must
  * update the headers of the existing entry. Specifically, we need to update all
  * end-to-end headers and not any hop-by-hop headers (rfc2616 13.5.3).
  *
  * This is not the whole story though: since it is possible for a faulty/malicious
  * origin server to set headers it should not in a 304, we must explicitly ignore
  * these too. Specifically all entity-headers except those permitted in a 304
  * (rfc2616 10.3.5) must be ignored.
  *
  * 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
  */
@@ -313,55 +314,55 @@
     /* clean cache */
     hdrCacheClean();
     /* update raw headers */
     header.update(&freshRep->header,
                   (const HttpHeaderMask *) &Denied304HeadersMask);
 
     header.compact();
     /* init cache */
     hdrCacheInit();
 }
 
 /* internal routines */
 
 time_t
 HttpReply::hdrExpirationTime()
 {
     /* The s-maxage and max-age directive takes priority over Expires */
 
     if (cache_control) {
         if (date >= 0) {
-            if (cache_control->s_maxage >= 0)
-                return date + cache_control->s_maxage;
+            if (cache_control->haveSMaxAge())
+                return date + cache_control->sMaxAge();
 
-            if (cache_control->max_age >= 0)
-                return date + cache_control->max_age;
+            if (cache_control->haveMaxAge())
+                return date + cache_control->maxAge();
         } else {
             /*
              * Conservatively handle the case when we have a max-age
              * header, but no Date for reference?
              */
 
-            if (cache_control->s_maxage >= 0)
+            if (cache_control->haveSMaxAge())
                 return squid_curtime;
 
-            if (cache_control->max_age >= 0)
+            if (cache_control->haveMaxAge())
                 return squid_curtime;
         }
     }
 
     if (Config.onoff.vary_ignore_expire &&
             header.has(HDR_VARY)) {
         const time_t d = header.getTime(HDR_DATE);
         const time_t e = header.getTime(HDR_EXPIRES);
 
         if (d == e)
             return -1;
     }
 
     if (header.has(HDR_EXPIRES)) {
         const time_t e = header.getTime(HDR_EXPIRES);
         /*
          * HTTP/1.0 says that robust implementations should consider
          * bad or malformed Expires header as equivalent to "expires
          * immediately."
          */
@@ -385,41 +386,41 @@
     content_range = header.getContRange();
     keep_alive = persistent() ? 1 : 0;
     const char *str = header.getStr(HDR_CONTENT_TYPE);
 
     if (str)
         content_type.limitInit(str, strcspn(str, ";\t "));
     else
         content_type = String();
 
     /* be sure to set expires after date and cache-control */
     expires = hdrExpirationTime();
 }
 
 /* sync this routine when you update HttpReply struct */
 void
 HttpReply::hdrCacheClean()
 {
     content_type.clean();
 
     if (cache_control) {
-        httpHdrCcDestroy(cache_control);
+        delete cache_control;
         cache_control = NULL;
     }
 
     if (surrogate_control) {
         httpHdrScDestroy(surrogate_control);
         surrogate_control = NULL;
     }
 
     if (content_range) {
         httpHdrContRangeDestroy(content_range);
         content_range = NULL;
     }
 }
 
 /*
  * Returns the body size of a HTTP response
  */
 int64_t
 HttpReply::bodySize(const HttpRequestMethod& method) const
 {
diff -Nr -U20 trunk//src/HttpRequest.cc playground-patch//src/HttpRequest.cc
--- trunk//src/HttpRequest.cc	2011-09-27 13:17:48.885454000 +0200
+++ playground-patch//src/HttpRequest.cc	2011-09-28 15:16:23.303575947 +0200
@@ -20,40 +20,41 @@
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
  */
 
 #include "squid.h"
 #include "DnsLookupDetails.h"
 #include "HttpRequest.h"
+#include "HttpHdrCc.h"
 #if USE_AUTH
 #include "auth/UserRequest.h"
 #endif
 #include "HttpHeaderRange.h"
 #include "log/Config.h"
 #include "MemBuf.h"
 #include "Store.h"
 #if ICAP_CLIENT
 #include "adaptation/icap/icap_log.h"
 #endif
 #include "acl/FilledChecklist.h"
 #include "err_detail_type.h"
 
 HttpRequest::HttpRequest() : HttpMsg(hoRequest)
 {
     init();
 }
 
 HttpRequest::HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aUrlpath) : HttpMsg(hoRequest)
 {
@@ -128,41 +129,41 @@
 }
 
 void
 HttpRequest::clean()
 {
     // we used to assert that the pipe is NULL, but now the request only
     // points to a pipe that is owned and initiated by another object.
     body_pipe = NULL;
 #if USE_AUTH
     auth_user_request = NULL;
 #endif
     safe_free(canonical);
 
     safe_free(vary_headers);
 
     urlpath.clean();
 
     header.clean();
 
     if (cache_control) {
-        httpHdrCcDestroy(cache_control);
+        delete cache_control;
         cache_control = NULL;
     }
 
     if (range) {
         delete range;
         range = NULL;
     }
 
     myportname.clean();
 
     tag.clean();
 #if USE_AUTH
     extacl_user.clean();
     extacl_passwd.clean();
 #endif
     extacl_log.clean();
 
     extacl_message.clean();
 
 #if USE_ADAPTATION
diff -Nr -U20 trunk//src/Makefile.am playground-patch//src/Makefile.am
--- trunk//src/Makefile.am	2011-09-27 13:17:48.885454000 +0200
+++ playground-patch//src/Makefile.am	2011-09-28 15:16:23.313575947 +0200
@@ -325,41 +325,43 @@
 	filemap.cc \
 	forward.cc \
 	forward.h \
 	fqdncache.cc \
 	ftp.cc \
 	Generic.h \
 	globals.h \
 	gopher.cc \
 	helper.cc \
 	helper.h \
 	HelperChildConfig.h \
 	HelperChildConfig.cc \
 	hier_code.h \
 	HierarchyLogEntry.h \
 	$(HTCPSOURCE) \
 	http.cc \
 	http.h \
 	HttpStatusCode.h \
 	HttpStatusLine.cc \
 	HttpStatusLine.h \
+	HttpHdrCc.h \
 	HttpHdrCc.cc \
+	HttpHdrCc.cci \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrSc.h \
 	HttpHdrScTarget.cc \
 	HttpHdrScTarget.h \
 	HttpHdrContRange.cc \
 	HttpHdrContRange.h \
 	HttpHeader.cc \
 	HttpHeader.h \
 	HttpHeaderMask.h \
 	HttpHeaderRange.h \
 	HttpHeaderTools.cc \
 	HttpBody.cc \
 	HttpControlMsg.h \
 	HttpMsg.cc \
 	HttpMsg.h \
 	HttpParser.cc \
 	HttpParser.h \
 	HttpReply.cc \
 	HttpReply.h \
@@ -1016,41 +1018,43 @@
 #	tests/testX.cc \
 #	tests/testMain.cc \
 #	X.h \
 #	X.cc
 #nodist_tests_testX_SOURCES=\
 #	$(TESTSOURCES)
 #tests_testX_LDFLAGS = $(LIBADD_DL)
 #tests_testX_LDADD=\
 #	$(SQUID_CPPUNIT_LIBS) \
 #	$(SQUID_CPPUNIT_LA) \
 #	$(COMPAT_LIB) \
 #tests_testX_DEPENDENCIES= $(SQUID_CPPUNIT_LA)
 
 
 # - add other component .(h|cc) files needed to link and run tests
 tests_testHttpReply_SOURCES=\
 	cbdata.cc \
 	cbdata.h \
 	ETag.cc \
 	HttpBody.cc \
+	HttpHdrCc.h \
 	HttpHdrCc.cc \
+	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrContRange.h \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrSc.h \
 	HttpHdrScTarget.cc \
 	HttpHdrScTarget.h \
 	HttpHeader.cc \
 	HttpHeader.h \
 	HttpHeaderMask.h \
 	HttpHeaderTools.cc \
 	HttpControlMsg.h \
 	HttpMsg.cc \
 	HttpMsg.h \
 	HttpReply.cc \
 	HttpReply.h \
 	HttpStatusCode.h \
 	HttpStatusLine.cc \
 	HttpStatusLine.h \
 	mem.cc \
@@ -1111,41 +1115,43 @@
 ##	String.cc \
 ##
 ##	disk.cc \
 ##	fs/libfs.la \
 tests_testACLMaxUserIP_SOURCES= \
 	cbdata.cc \
 	ClientInfo.h \
 	ConfigOption.cc \
 	ConfigParser.cc \
 	DiskIO/ReadRequest.cc \
 	DiskIO/WriteRequest.cc \
 	ETag.cc \
 	event.cc \
 	filemap.cc \
 	HelperChildConfig.h \
 	HelperChildConfig.cc \
 	HttpHeader.cc \
 	HttpHeaderTools.cc \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
+	HttpHdrCc.h \
 	HttpHdrCc.cc \
+	HttpHdrCc.cci \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpMsg.cc \
 	HttpRequestMethod.cc \
 	int.cc \
 	list.cc \
 	mem_node.cc \
 	Packer.cc \
 	Parsing.cc \
 	SquidMath.cc \
 	StatHist.cc \
 	stmem.cc \
 	String.cc \
 	store_dir.cc \
 	StoreIOState.cc \
 	StoreMeta.cc \
 	StoreMetaMD5.cc \
 	StoreMetaSTD.cc \
 	StoreMetaSTDLFS.cc \
 	StoreMetaUnpacker.cc \
@@ -1276,41 +1282,43 @@
 	ETag.cc \
 	event.cc \
 	external_acl.cc \
 	ExternalACLEntry.cc \
 	fd.cc \
 	fde.cc \
 	filemap.cc \
 	forward.cc \
 	fqdncache.cc \
 	ftp.cc \
 	gopher.cc \
 	hier_code.h \
 	helper.cc \
 	HelperChildConfig.h \
 	HelperChildConfig.cc \
 	$(HTCPSOURCE) \
 	http.cc \
 	HttpBody.cc \
 	HttpHeader.cc \
 	HttpHeaderTools.cc \
+	HttpHdrCc.h \
 	HttpHdrCc.cc \
+	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpMsg.cc \
 	HttpReply.cc \
 	HttpStatusLine.cc \
 	icp_v2.cc \
 	icp_v3.cc \
 	$(IPC_SOURCE) \
 	ipcache.cc \
 	int.cc \
 	internal.cc \
 	list.cc \
 	multicast.cc \
 	mem_node.cc \
 	MemBuf.cc \
 	MemObject.cc \
 	mime.cc \
 	mime_header.cc \
@@ -1412,41 +1420,43 @@
 	$(REPL_OBJS) \
 	$(SQUID_CPPUNIT_LA)
 
 #	tests/stub_CommIO.cc \
 #	tests/stub_comm.cc
 tests_testDiskIO_SOURCES = \
 	CacheDigest.cc \
 	cbdata.cc \
 	ClientInfo.h \
 	ConfigOption.cc \
 	ConfigParser.cc \
 	$(DELAY_POOL_SOURCE) \
 	$(DISKIO_SOURCE) \
 	disk.cc \
 	ETag.cc \
 	EventLoop.cc \
 	event.cc \
 	fd.cc \
 	filemap.cc \
 	HttpBody.cc \
+	HttpHdrCc.h \
 	HttpHdrCc.cc \
+	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpHdrRange.cc \
 	HttpHeaderTools.cc \
 	HttpHeader.cc \
 	HttpMsg.cc \
 	HttpReply.cc \
 	HttpRequestMethod.cc \
 	HttpStatusLine.cc \
 	int.cc \
 	list.cc \
 	MemBuf.cc \
 	MemObject.cc \
 	mem_node.cc \
 	mem.cc \
 	Packer.cc \
 	Parsing.cc \
 	refresh.cc \
 	RemovalPolicy.cc \
@@ -1587,41 +1597,43 @@
 	EventLoop.cc \
 	external_acl.cc \
 	ExternalACLEntry.cc \
 	FadingCounter.cc \
 	fd.cc \
 	fde.cc \
 	filemap.cc \
 	forward.cc \
 	fqdncache.cc \
 	ftp.cc \
 	gopher.cc \
 	helper.cc \
 	HelperChildConfig.h \
 	HelperChildConfig.cc \
 	hier_code.h \
 	$(HTCPSOURCE) \
 	http.cc \
 	HttpBody.cc \
 	HttpHeader.cc \
 	HttpHeaderTools.cc \
+	HttpHdrCc.h \
 	HttpHdrCc.cc \
+	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpMsg.cc \
 	HttpParser.cc \
 	HttpParser.h \
 	HttpReply.cc \
 	HttpRequest.cc \
 	HttpRequestMethod.cc \
 	HttpStatusLine.cc \
 	icp_v2.cc \
 	icp_v3.cc \
 	$(IPC_SOURCE) \
 	ipcache.cc \
 	int.cc \
 	internal.cc \
 	list.cc \
 	mem.cc \
 	mem_node.cc \
@@ -1772,41 +1784,43 @@
 	event.cc \
 	external_acl.cc \
 	ExternalACLEntry.cc \
 	FadingCounter.cc \
 	fd.cc \
 	fde.cc \
 	filemap.cc \
 	forward.cc \
 	fqdncache.cc \
 	ftp.cc \
 	gopher.cc \
 	helper.cc \
 	HelperChildConfig.h \
 	HelperChildConfig.cc \
 	hier_code.h \
 	$(HTCPSOURCE) \
 	http.cc \
 	HttpBody.cc \
 	HttpHeader.cc \
 	HttpHeaderTools.cc \
+	HttpHdrCc.h \
 	HttpHdrCc.cc \
+	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpMsg.cc \
 	HttpParser.cc \
 	HttpParser.h \
 	HttpReply.cc \
 	HttpRequest.cc \
 	HttpRequestMethod.cc \
 	HttpStatusLine.cc \
 	icp_v2.cc \
 	icp_v3.cc \
 	$(IPC_SOURCE) \
 	ipcache.cc \
 	int.cc \
 	internal.cc \
 	list.cc \
 	MemBuf.cc \
 	MemObject.cc \
@@ -1953,41 +1967,43 @@
 	errorpage.cc \
 	ETag.cc \
 	event.cc \
 	external_acl.cc \
 	ExternalACLEntry.cc \
 	FadingCounter.cc \
 	fd.cc \
 	fde.cc \
 	filemap.cc \
 	forward.cc \
 	fqdncache.cc \
 	ftp.cc \
 	gopher.cc \
 	helper.cc \
 	HelperChildConfig.h \
 	HelperChildConfig.cc \
 	hier_code.h \
 	$(HTCPSOURCE) \
 	http.cc \
 	HttpBody.cc \
+	HttpHdrCc.h \
 	HttpHdrCc.cc \
+	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpHeader.cc \
 	HttpHeaderTools.cc \
 	HttpMsg.cc \
 	HttpParser.cc \
 	HttpParser.h \
 	HttpReply.cc \
 	HttpRequest.cc \
 	HttpRequestMethod.cc \
 	HttpStatusLine.cc \
 	icp_v2.cc \
 	icp_v3.cc \
 	int.cc \
 	internal.cc \
 	$(IPC_SOURCE) \
 	ipcache.cc \
 	list.cc \
@@ -2178,41 +2194,43 @@
 	$(DNSSOURCE) \
 	errorpage.cc \
 	ETag.cc \
 	external_acl.cc \
 	ExternalACLEntry.cc \
 	fd.cc \
 	fde.cc \
 	forward.cc \
 	fqdncache.cc \
 	ftp.cc \
 	gopher.cc \
 	helper.cc \
 	HelperChildConfig.h \
 	HelperChildConfig.cc \
 	hier_code.h \
 	$(HTCPSOURCE) \
 	http.cc \
 	HttpBody.cc \
 	HttpHeader.cc \
 	HttpHeaderTools.cc \
+	HttpHdrCc.h \
 	HttpHdrCc.cc \
+	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpMsg.cc \
 	HttpReply.cc \
 	HttpStatusLine.cc \
 	icp_v2.cc \
 	icp_v3.cc \
 	$(IPC_SOURCE) \
 	ipcache.cc \
 	int.cc \
 	internal.cc \
 	list.cc \
 	multicast.cc \
 	mem_node.cc \
 	MemBuf.cc \
 	MemObject.cc \
 	mime.cc \
 	mime_header.cc \
@@ -2310,41 +2328,43 @@
 tests_testHttpRequest_DEPENDENCIES = \
 	$(REPL_OBJS) \
 	$(SQUID_CPPUNIT_LA)
 
 ## why so many sources? well httpHeaderTools requites ACLChecklist & friends.
 ## first line - what we are testing.
 tests_testStore_SOURCES= \
 	CacheDigest.cc \
 	cbdata.cc \
 	ClientInfo.h \
 	ConfigOption.cc \
 	ConfigParser.cc \
 	$(DELAY_POOL_SOURCE) \
 	disk.cc \
 	DiskIO/ReadRequest.cc \
 	DiskIO/WriteRequest.cc \
 	ETag.cc \
 	event.cc \
 	EventLoop.cc \
 	filemap.cc \
+	HttpHdrCc.h \
 	HttpHdrCc.cc \
+	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpHeaderTools.cc \
 	HttpHeader.cc \
 	HttpMsg.cc \
 	HttpRequestMethod.cc \
 	int.cc \
 	list.cc \
 	mem.cc \
 	mem_node.cc \
 	MemBuf.cc \
 	Packer.cc \
 	Parsing.cc \
 	RemovalPolicy.cc \
 	refresh.cc \
 	StatHist.cc \
 	stmem.cc \
 	store.cc \
@@ -2548,41 +2568,43 @@
 	ConfigOption.cc \
 	SwapDir.cc \
 	tests/stub_acl.cc \
 	tests/stub_cache_cf.cc \
 	tests/stub_helper.cc \
 	cbdata.cc \
 	String.cc \
 	tests/stub_debug.cc \
 	tests/stub_client_side_request.cc \
 	tests/stub_http.cc \
 	mem_node.cc \
 	stmem.cc \
 	tests/stub_mime.cc \
 	HttpHeaderTools.cc \
 	HttpHeader.cc \
 	mem.cc \
 	ClientInfo.h \
 	MemBuf.cc \
 	HttpHdrContRange.cc \
 	Packer.cc \
+	HttpHdrCc.h \
 	HttpHdrCc.cc \
+	HttpHdrCc.cci \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	url.cc \
 	StatHist.cc \
 	HttpHdrRange.cc \
 	ETag.cc \
 	tests/stub_errorpage.cc \
 	tests/stub_HttpRequest.cc \
 	tests/stub_access_log.cc \
 	refresh.cc \
 	tests/stub_store_client.cc \
 	tests/stub_tools.cc \
 	tests/testStoreSupport.cc \
 	tests/testStoreSupport.h \
 	time.cc \
 	URLScheme.cc \
 	wordlist.cc \
 	$(DISKIO_SOURCE)
 
 nodist_tests_testUfs_SOURCES = \
@@ -2678,41 +2700,43 @@
 	Parsing.cc \
 	ConfigOption.cc \
 	SwapDir.cc \
 	tests/stub_acl.cc \
 	tests/stub_cache_cf.cc \
 	tests/stub_helper.cc \
 	cbdata.cc \
 	String.cc \
 	tests/stub_client_side_request.cc \
 	tests/stub_http.cc \
 	mem_node.cc \
 	stmem.cc \
 	tests/stub_mime.cc \
 	HttpHeaderTools.cc \
 	HttpHeader.cc \
 	mem.cc \
 	ClientInfo.h \
 	MemBuf.cc \
 	HttpHdrContRange.cc \
 	Packer.cc \
+	HttpHdrCc.h \
 	HttpHdrCc.cc \
+	HttpHdrCc.cci \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	url.cc \
 	StatHist.cc \
 	HttpHdrRange.cc \
 	ETag.cc \
 	tests/stub_errorpage.cc \
 	tests/stub_HttpRequest.cc \
 	tests/stub_access_log.cc \
 	refresh.cc \
 	tests/stub_MemStore.cc \
 	tests/stub_Port.cc \
 	tests/stub_store_client.cc \
 	tests/stub_tools.cc \
 	tests/stub_UdsOp.cc \
 	tests/testStoreSupport.cc \
 	tests/testStoreSupport.h \
 	time.cc \
 	URLScheme.cc \
 	wordlist.cc \
@@ -2807,41 +2831,43 @@
 	SwapDir.cc \
 	tests/stub_acl.cc \
 	tests/stub_cache_cf.cc \
 	tests/stub_helper.cc \
 	cbdata.cc \
 	String.cc \
 	tests/stub_comm.cc \
 	tests/stub_debug.cc \
 	tests/stub_client_side_request.cc \
 	tests/stub_http.cc \
 	mem_node.cc \
 	stmem.cc \
 	tests/stub_mime.cc \
 	HttpHeaderTools.cc \
 	HttpHeader.cc \
 	mem.cc \
 	ClientInfo.h \
 	MemBuf.cc \
 	HttpHdrContRange.cc \
 	Packer.cc \
+	HttpHdrCc.h \
 	HttpHdrCc.cc \
+	HttpHdrCc.cci \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	url.cc \
 	StatHist.cc \
 	HttpHdrRange.cc \
 	ETag.cc \
 	tests/stub_errorpage.cc \
 	tests/stub_HttpRequest.cc \
 	tests/stub_access_log.cc \
 	refresh.cc \
 	tests/stub_store_client.cc \
 	tests/stub_tools.cc \
 	tests/testStoreSupport.cc \
 	tests/testStoreSupport.h \
 	time.cc \
 	URLScheme.cc \
 	wordlist.cc \
 	$(DISKIO_SOURCE)
 
 nodist_tests_testNull_SOURCES = \
@@ -2909,41 +2935,43 @@
 	$(DNSSOURCE) \
 	errorpage.cc \
 	ETag.cc \
 	event.cc \
 	external_acl.cc \
 	ExternalACLEntry.cc \
 	fd.cc \
 	fde.cc \
 	filemap.cc \
 	forward.cc \
 	fqdncache.cc \
 	ftp.cc \
 	gopher.cc \
 	helper.cc \
 	HelperChildConfig.h \
 	HelperChildConfig.cc \
 	hier_code.h \
 	$(HTCPSOURCE) \
 	http.cc \
 	HttpBody.cc \
+	HttpHdrCc.h \
 	HttpHdrCc.cc \
+	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpHeader.cc \
 	HttpHeaderTools.cc \
 	HttpMsg.cc \
 	HttpParser.cc \
 	HttpParser.h \
 	HttpReply.cc \
 	HttpRequest.cc \
 	HttpRequestMethod.cc \
 	HttpStatusLine.cc \
 	icp_v2.cc \
 	icp_v3.cc \
 	$(IPC_SOURCE) \
 	ipcache.cc \
 	int.cc \
 	internal.cc \
 	list.cc \
diff -Nr -U20 trunk//src/Makefile.am.orig playground-patch//src/Makefile.am.orig
--- trunk//src/mem.cc	2011-09-27 13:17:48.885454000 +0200
+++ playground-patch//src/mem.cc	2011-09-28 15:16:23.323575947 +0200
@@ -436,41 +436,40 @@
      * malloc() for those? @?@
      */
     memDataInit(MEM_2K_BUF, "2K Buffer", 2048, 10, false);
     memDataInit(MEM_4K_BUF, "4K Buffer", 4096, 10, false);
     memDataInit(MEM_8K_BUF, "8K Buffer", 8192, 10, false);
     memDataInit(MEM_16K_BUF, "16K Buffer", 16384, 10, false);
     memDataInit(MEM_32K_BUF, "32K Buffer", 32768, 10, false);
     memDataInit(MEM_64K_BUF, "64K Buffer", 65536, 10, false);
     memDataInit(MEM_ACL_DENY_INFO_LIST, "acl_deny_info_list",
                 sizeof(acl_deny_info_list), 0);
     memDataInit(MEM_ACL_NAME_LIST, "acl_name_list", sizeof(acl_name_list), 0);
 #if USE_CACHE_DIGESTS
 
     memDataInit(MEM_CACHE_DIGEST, "CacheDigest", sizeof(CacheDigest), 0);
 #endif
 
     memDataInit(MEM_LINK_LIST, "link_list", sizeof(link_list), 10);
     memDataInit(MEM_DLINK_NODE, "dlink_node", sizeof(dlink_node), 10);
     memDataInit(MEM_DREAD_CTRL, "dread_ctrl", sizeof(dread_ctrl), 0);
     memDataInit(MEM_DWRITE_Q, "dwrite_q", sizeof(dwrite_q), 0);
-    memDataInit(MEM_HTTP_HDR_CC, "HttpHdrCc", sizeof(HttpHdrCc), 0);
     memDataInit(MEM_HTTP_HDR_CONTENT_RANGE, "HttpHdrContRange", sizeof(HttpHdrContRange), 0);
     memDataInit(MEM_NETDBENTRY, "netdbEntry", sizeof(netdbEntry), 0);
     memDataInit(MEM_NET_DB_NAME, "net_db_name", sizeof(net_db_name), 0);
     memDataInit(MEM_RELIST, "relist", sizeof(relist), 0);
     memDataInit(MEM_CLIENT_INFO, "ClientInfo", sizeof(ClientInfo), 0);
     memDataInit(MEM_MD5_DIGEST, "MD5 digest", SQUID_MD5_DIGEST_LENGTH, 0);
     MemPools[MEM_MD5_DIGEST]->setChunkSize(512 * 1024);
 
     /** Lastly init the string pools. */
     for (i = 0; i < mem_str_pool_count; ++i) {
         StrPools[i].pool = memPoolCreate(StrPoolsAttrs[i].name, StrPoolsAttrs[i].obj_size);
         StrPools[i].pool->zeroOnPush(false);
 
         if (StrPools[i].pool->objectSize() != StrPoolsAttrs[i].obj_size)
             debugs(13, 1, "Notice: " << StrPoolsAttrs[i].name << " is " << StrPools[i].pool->objectSize() << " bytes instead of requested " << StrPoolsAttrs[i].obj_size << " bytes");
     }
 
     MemIsInitialized = true;
     /** \par
      * finally register with the cache manager */
diff -Nr -U20 trunk//src/mime.cc playground-patch//src/mime.cc
--- trunk//src/mime.cc	2011-09-27 13:17:48.885454000 +0200
+++ playground-patch//src/mime.cc	2011-09-28 15:16:23.323575947 +0200
@@ -17,40 +17,41 @@
  *  incorporates software developed and/or copyrighted by other
  *  sources; see the CREDITS file for full details.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #include "squid.h"
+#include "HttpHdrCc.h"
 #include "Store.h"
 #include "StoreClient.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
 #include "MemObject.h"
 #include "fde.h"
 #include "MemBuf.h"
 
 #define GET_HDR_SZ 1024
 
 class MimeIcon : public StoreClient
 {
 
 public:
     MimeIcon ();
     ~MimeIcon ();
     void setName (char const *);
     char const * getName () const;
     void _free();
     void load();
@@ -445,43 +446,43 @@
     flags.cachable = 1;
     StoreEntry *e = storeCreateEntry(url,
                                      url,
                                      flags,
                                      METHOD_GET);
     assert(e != NULL);
     EBIT_SET(e->flags, ENTRY_SPECIAL);
     e->setPublicKey();
     e->buffer();
     HttpRequest *r = HttpRequest::CreateFromUrl(url);
 
     if (NULL == r)
         fatal("mimeLoadIcon: cannot parse internal URL");
 
     e->mem_obj->request = HTTPMSGLOCK(r);
 
     HttpReply *reply = new HttpReply;
 
     reply->setHeaders(HTTP_OK, NULL, mimeGetContentType(icon), sb.st_size, sb.st_mtime, -1);
 
-    reply->cache_control = httpHdrCcCreate();
+    reply->cache_control = new HttpHdrCc();
 
-    httpHdrCcSetMaxAge(reply->cache_control, 86400);
+    reply->cache_control->maxAge(86400);
 
     reply->header.putCc(reply->cache_control);
 
     e->replaceHttpReply(reply);
 
     /* read the file into the buffer and append it to store */
     buf = (char *)memAllocate(MEM_4K_BUF);
 
     while ((n = FD_READ_METHOD(fd, buf, 4096)) > 0)
         e->append(buf, n);
 
     file_close(fd);
 
     e->flush();
 
     e->complete();
 
     e->timestampsSet();
 
     debugs(25, 3, "Loaded icon " << url);
diff -Nr -U20 trunk//src/protos.h playground-patch//src/protos.h
--- trunk//src/protos.h	2011-09-27 13:17:48.885454000 +0200
+++ playground-patch//src/protos.h	2011-09-28 15:16:23.323575947 +0200
@@ -220,47 +220,40 @@
 SQUIDCEXTERN const char *httpMakeVaryMark(HttpRequest * request, HttpReply const * reply);
 
 #include "HttpStatusCode.h"
 SQUIDCEXTERN const char *httpStatusString(http_status status);
 
 /* Http Body */
 /* init/clean */
 SQUIDCEXTERN void httpBodyInit(HttpBody * body);
 SQUIDCEXTERN void httpBodyClean(HttpBody * body);
 /* get body ptr (always use this) */
 SQUIDCEXTERN const char *httpBodyPtr(const HttpBody * body);
 /* set body, does not clone mb so you should not reuse it */
 SQUIDCEXTERN void httpBodySet(HttpBody * body, MemBuf * mb);
 
 /* pack */
 SQUIDCEXTERN void httpBodyPackInto(const HttpBody * body, Packer * p);
 
 /* Http Cache Control Header Field */
 SQUIDCEXTERN void httpHdrCcInitModule(void);
 SQUIDCEXTERN void httpHdrCcCleanModule(void);
-SQUIDCEXTERN HttpHdrCc *httpHdrCcCreate(void);
-SQUIDCEXTERN HttpHdrCc *httpHdrCcParseCreate(const String * str);
-SQUIDCEXTERN void httpHdrCcDestroy(HttpHdrCc * cc);
-SQUIDCEXTERN HttpHdrCc *httpHdrCcDup(const HttpHdrCc * cc);
-SQUIDCEXTERN void httpHdrCcPackInto(const HttpHdrCc * cc, Packer * p);
-SQUIDCEXTERN void httpHdrCcSetMaxAge(HttpHdrCc * cc, int max_age);
-SQUIDCEXTERN void httpHdrCcSetSMaxAge(HttpHdrCc * cc, int s_maxage);
 SQUIDCEXTERN void httpHdrCcUpdateStats(const HttpHdrCc * cc, StatHist * hist);
 void httpHdrCcStatDumper(StoreEntry * sentry, int idx, double val, double size, int count);
 
 /* Http Header Tools */
 class HttpHeaderFieldInfo;
 SQUIDCEXTERN HttpHeaderFieldInfo *httpHeaderBuildFieldsInfo(const HttpHeaderFieldAttrs * attrs, int count);
 SQUIDCEXTERN void httpHeaderDestroyFieldsInfo(HttpHeaderFieldInfo * info, int count);
 SQUIDCEXTERN http_hdr_type httpHeaderIdByName(const char *name, size_t name_len, const HttpHeaderFieldInfo * attrs, int end);
 SQUIDCEXTERN http_hdr_type httpHeaderIdByNameDef(const char *name, int name_len);
 SQUIDCEXTERN const char *httpHeaderNameById(int id);
 SQUIDCEXTERN int httpHeaderHasConnDir(const HttpHeader * hdr, const char *directive);
 SQUIDCEXTERN void strListAdd(String * str, const char *item, char del);
 SQUIDCEXTERN int strListIsMember(const String * str, const char *item, char del);
 SQUIDCEXTERN int strListIsSubstr(const String * list, const char *s, char del);
 SQUIDCEXTERN int strListGetItem(const String * str, char del, const char **item, int *ilen, const char **pos);
 SQUIDCEXTERN const char *getStringPrefix(const char *str, const char *end);
 SQUIDCEXTERN int httpHeaderParseInt(const char *start, int *val);
 SQUIDCEXTERN int httpHeaderParseOffset(const char *start, int64_t * off);
 SQUIDCEXTERN void
 httpHeaderPutStrf(HttpHeader * hdr, http_hdr_type id, const char *fmt,...) PRINTF_FORMAT_ARG3;
diff -Nr -U20 trunk//src/refresh.cc playground-patch//src/refresh.cc
--- trunk//src/refresh.cc	2011-09-27 13:17:48.885454000 +0200
+++ playground-patch//src/refresh.cc	2011-09-28 15:16:23.333575947 +0200
@@ -21,40 +21,41 @@
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #ifndef USE_POSIX_REGEX
 #define USE_POSIX_REGEX		/* put before includes; always use POSIX */
 #endif
 
 #include "squid.h"
+#include "HttpHdrCc.h"
 #include "mgr/Registration.h"
 #include "Store.h"
 #include "MemObject.h"
 #include "HttpRequest.h"
 #include "HttpReply.h"
 #include "SquidTime.h"
 
 typedef enum {
     rcHTTP,
     rcICP,
 #if USE_HTCP
     rcHTCP,
 #endif
 #if USE_CACHE_DIGESTS
     rcCDigest,
 #endif
     rcStore,
     rcCount
 } refreshCountsEnum;
 
@@ -250,61 +251,62 @@
     // FIXME: what to do when age < 0 or counter overflow?
     assert(age >= 0);
 
     R = uri ? refreshLimits(uri) : refreshUncompiledPattern(".");
 
     if (NULL == R)
         R = &DefaultRefresh;
 
     debugs(22, 3, "refreshCheck: Matched '" << R->pattern << " " <<
            (int) R->min << " " << (int) (100.0 * R->pct) << "%% " <<
            (int) R->max << "'");
 
     debugs(22, 3, "\tage:\t" << age);
 
     debugs(22, 3, "\tcheck_time:\t" << mkrfc1123(check_time));
 
     debugs(22, 3, "\tentry->timestamp:\t" << mkrfc1123(entry->timestamp));
 
     if (request && !request->flags.ignore_cc) {
         const HttpHdrCc *const cc = request->cache_control;
-        if (cc && cc->min_fresh > 0) {
+        if (cc && cc->haveMinFresh()) {
+            const int32_t minFresh=cc->minFresh();
             debugs(22, 3, "\tage + min-fresh:\t" << age << " + " <<
-                   cc->min_fresh << " = " << age + cc->min_fresh);
+            		minFresh << " = " << age + minFresh);
             debugs(22, 3, "\tcheck_time + min-fresh:\t" << check_time << " + "
-                   << cc->min_fresh << " = " <<
-                   mkrfc1123(check_time + cc->min_fresh));
-            age += cc->min_fresh;
-            check_time += cc->min_fresh;
+                   << minFresh << " = " <<
+                   mkrfc1123(check_time + minFresh));
+            age += minFresh;
+            check_time += minFresh;
         }
     }
 
     memset(&sf, '\0', sizeof(sf));
 
     staleness = refreshStaleness(entry, check_time, age, R, &sf);
 
     debugs(22, 3, "Staleness = " << staleness);
 
     // stale-if-error requires any failure be passed thru when its period is over.
     if (request && entry->mem_obj && entry->mem_obj->getReply() && entry->mem_obj->getReply()->cache_control &&
-            EBIT_TEST(entry->mem_obj->getReply()->cache_control->mask, CC_STALE_IF_ERROR) &&
-            entry->mem_obj->getReply()->cache_control->stale_if_error < staleness) {
+    		entry->mem_obj->getReply()->cache_control->haveStaleIfError() &&
+            entry->mem_obj->getReply()->cache_control->staleIfError() < staleness) {
 
         debugs(22, 3, "refreshCheck: stale-if-error period expired.");
         request->flags.fail_on_validation_err = 1;
     }
 
     if (EBIT_TEST(entry->flags, ENTRY_REVALIDATE) && staleness > -1
 #if USE_HTTP_VIOLATIONS
             && !R->flags.ignore_must_revalidate
 #endif
        ) {
         debugs(22, 3, "refreshCheck: YES: Must revalidate stale response");
         if (request)
             request->flags.fail_on_validation_err = 1;
         return STALE_MUST_REVALIDATE;
     }
 
     /* request-specific checks */
     if (request && !request->flags.ignore_cc) {
         HttpHdrCc *cc = request->cache_control;
 
@@ -317,65 +319,65 @@
 #if USE_HTTP_VIOLATIONS
 
         if (!request->flags.nocache_hack) {
             (void) 0;
         } else if (R->flags.ignore_reload) {
             /* The clients no-cache header is ignored */
             debugs(22, 3, "refreshCheck: MAYBE: ignore-reload");
         } else if (R->flags.reload_into_ims || Config.onoff.reload_into_ims) {
             /* The clients no-cache header is changed into a IMS query */
             debugs(22, 3, "refreshCheck: YES: reload-into-ims");
             return STALE_RELOAD_INTO_IMS;
         } else {
             /* The clients no-cache header is not overridden on this request */
             debugs(22, 3, "refreshCheck: YES: client reload");
             request->flags.nocache = 1;
             return STALE_FORCED_RELOAD;
         }
 
 #endif
         if (NULL != cc) {
-            if (cc->max_age > -1) {
+            if (cc->haveMaxAge()) {
 #if USE_HTTP_VIOLATIONS
-                if (R->flags.ignore_reload && cc->max_age == 0) {
+                if (R->flags.ignore_reload && cc->maxAge() == 0) {
                     debugs(22, 3, "refreshCheck: MAYBE: client-max-age = 0 and ignore-reload");
                 } else
 #endif
                 {
-                    if (cc->max_age == 0) {
+                    if (cc->maxAge() == 0) {
                         debugs(22, 3, "refreshCheck: YES: client-max-age = 0");
                         return STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE;
                     }
 
-                    if (age > cc->max_age) {
+                    if (age > cc->maxAge()) {
                         debugs(22, 3, "refreshCheck: YES: age > client-max-age");
                         return STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE;
                     }
                 }
             }
 
-            if (EBIT_TEST(cc->mask, CC_MAX_STALE) && staleness > -1) {
-                if (cc->max_stale < 0) {
+            if (cc->haveMaxStale() && staleness > -1) {
+                if (cc->maxStale()==HttpHdrCc::MAX_STALE_ALWAYS) {
                     /* max-stale directive without a value */
                     debugs(22, 3, "refreshCheck: NO: max-stale wildcard");
                     return FRESH_REQUEST_MAX_STALE_ALL;
-                } else if (staleness < cc->max_stale) {
+                } else if (staleness < cc->maxStale()) {
                     debugs(22, 3, "refreshCheck: NO: staleness < max-stale");
                     return FRESH_REQUEST_MAX_STALE_VALUE;
                 }
             }
         }
     }
 
     if (-1 == staleness) {
         debugs(22, 3, "refreshCheck: object isn't stale..");
         if (sf.expires) {
             debugs(22, 3, "refreshCheck: returning FRESH_EXPIRES");
             return FRESH_EXPIRES;
         }
 
         assert(!sf.max);
 
         if (sf.lmfactor) {
             debugs(22, 3, "refreshCheck: returning FRESH_LMFACTOR_RULE");
             return FRESH_LMFACTOR_RULE;
         }
diff -Nr -U20 trunk//src/structs.h playground-patch//src/structs.h
--- trunk//src/structs.h	2011-09-27 13:17:48.885454000 +0200
+++ playground-patch//src/structs.h	2011-09-28 15:16:23.333575947 +0200
@@ -706,55 +706,40 @@
  * Note: HttpBody is used only for messages with a small content that is
  * known a priory (e.g., error messages).
  */
 
 class MemBuf;
 
 struct _HttpBody {
     /* private */
     MemBuf *mb;
 };
 
 #include "SquidString.h"
 /* http header extention field */
 
 class HttpHdrExtField
 {
     String name;		/* field-name  from HTTP/1.1 (no column after name) */
     String value;		/* field-value from HTTP/1.1 */
 };
 
-/* http cache control header field */
-
-class HttpHdrCc
-{
-
-public:
-    int mask;
-    int max_age;
-    int s_maxage;
-    int max_stale;
-    int stale_if_error;
-    int min_fresh;
-    String other;
-};
-
 /* per field statistics */
 
 class HttpHeaderFieldStat
 {
 
 public:
     HttpHeaderFieldStat() : aliveCount(0), seenCount(0), parsCount(0), errCount(0), repCount(0) {}
 
     int aliveCount;		/* created but not destroyed (count) */
     int seenCount;		/* #fields we've seen */
     int parsCount;		/* #parsing attempts */
     int errCount;		/* #pasring errors */
     int repCount;		/* #repetitons */
 };
 
 /* compiled version of HttpHeaderFieldAttrs plus stats */
 
 class HttpHeaderFieldInfo
 {
 
