=== modified file 'src/HttpHdrCc.cc'
--- src/HttpHdrCc.cc	2012-09-04 11:58:36 +0000
+++ src/HttpHdrCc.cc	2013-02-14 07:29:50 +0000
@@ -194,15 +194,38 @@
             }
             break;
 
+        case CC_PRIVATE:
+            if (!p) {
+                // Value parameter is optional.
+                setMask(type,true);
+                private_.clean();
+            } else if (/* p &&*/ !httpHeaderParseQuotedString(p, (ilen-nlen-1), &private_)) {
+                debugs(65, 2, "cc: invalid private= specs near '" << item << "'");
+                clearPrivate();
+            } else {
+                setMask(type,true);
+            }
+            break;
+
+        case CC_NO_CACHE:
+            if (!p) {
+                // On Requests, missing value parameter is expected syntax.
+                // On Responses, value parameter is optional.
+                setMask(type,true);
+                no_cache.clean();
+            } else if (/* p &&*/ !httpHeaderParseQuotedString(p, (ilen-nlen-1), &no_cache)) {
+                debugs(65, 2, "cc: invalid no-cache= specs near '" << item << "'");
+                clearNoCache();
+            } else {
+                // On Requests, a value parameter is invalid syntax.
+                // XXX: identify when parsing request header and dump err message here.
+                setMask(type,true);
+            }
+            break;
+
         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;

=== modified file 'src/HttpHdrCc.h'
--- src/HttpHdrCc.h	2012-09-21 14:57:30 +0000
+++ src/HttpHdrCc.h	2013-02-14 07:26:38 +0000
@@ -74,15 +74,15 @@
 
     //manipulation for Cache-Control: private header
     bool hasPrivate() const {return isSet(CC_PRIVATE);}
-    bool Private() const {return isSet(CC_PRIVATE);}
-    void Private(bool v) {setMask(CC_PRIVATE,v);}
-    void clearPrivate() {setMask(CC_PRIVATE,false);}
+    const String &Private() const {return private_;}
+    void Private(String &v) {setMask(CC_PRIVATE,true); private_.append(v);} // uses append for multi-line headers
+    void clearPrivate() {setMask(CC_PRIVATE,false); private_.clean();}
 
     //manipulation for Cache-Control: no-cache header
     bool hasNoCache() const {return isSet(CC_NO_CACHE);}
-    bool noCache() const {return isSet(CC_NO_CACHE);}
-    void noCache(bool v) {setMask(CC_NO_CACHE,v);}
-    void clearNoCache() {setMask(CC_NO_CACHE,false);}
+    const String &noCache() const {return no_cache;}
+    void noCache(String &v) {setMask(CC_NO_CACHE,true); no_cache.append(v);} // uses append for multi-line headers
+    void clearNoCache() {setMask(CC_NO_CACHE,false); no_cache.clean();}
 
     //manipulation for Cache-Control: no-store header
     bool hasNoStore() const {return isSet(CC_NO_STORE);}
@@ -166,6 +166,9 @@
     int32_t max_stale;
     int32_t stale_if_error;
     int32_t min_fresh;
+    String private_; ///< List of headers sent as value for CC:private="...". May be empty/undefined if the value is missing.
+    String no_cache; ///< List of header sent as value for CC:no-cache="...". May be empty/undefined if the value is missing.
+
     /// low-level part of the public set method, performs no checks
     _SQUID_INLINE_ void setMask(http_hdr_cc_type id, bool newval=true);
     _SQUID_INLINE_ void setValue(int32_t &value, int32_t new_value, http_hdr_cc_type hdr, bool setting=true);

=== modified file 'src/client_side_request.cc'
--- src/client_side_request.cc	2013-02-12 11:34:35 +0000
+++ src/client_side_request.cc	2013-02-12 12:14:34 +0000
@@ -1094,7 +1094,7 @@
 
     if (!request->flags.ignoreCc) {
         if (request->cache_control) {
-            if (request->cache_control->noCache())
+            if (request->cache_control->hasNoCache())
                 no_cache=true;
 
             // RFC 2616: treat Pragma:no-cache as if it was Cache-Control:no-cache when Cache-Control is missing

=== modified file 'src/http.cc'
--- src/http.cc	2013-02-16 11:42:53 +0000
+++ src/http.cc	2013-02-17 01:41:03 +0000
@@ -362,6 +362,16 @@
         }
 
         // NP: request CC:no-cache only means cache READ is forbidden. STORE is permitted.
+        if (rep->cache_control->hasNoCache() && rep->cache_control->noCache().defined()) {
+            /* TODO: we are allowed to cache when no-cache= has parameters.
+             * Provided we strip away any of the listed headers unless they are revalidated
+             * successfully (ie, must revalidate AND these headers are prohibited on stale replies).
+             * That is a bit tricky for squid right now so we avoid caching entirely.
+             */
+            debugs(22, 3, HERE << "NO because server reply Cache-Control:no-cache has parameters");
+            return 0;
+        }
+
         // NP: request CC:private is undefined. We ignore.
         // NP: other request CC flags are limiters on HIT/MISS. We don't care about here.
 
@@ -375,8 +385,13 @@
         // RFC 2616 section 14.9.1 - MUST NOT cache any response with CC:private in a shared cache like Squid.
         // TODO: add a shared/private cache configuration possibility.
         if (rep->cache_control &&
-                rep->cache_control->Private() &&
+                rep->cache_control->hasPrivate() &&
                 !REFRESH_OVERRIDE(ignore_private)) {
+            /* TODO: we are allowed to cache when private= has parameters.
+             * Provided we strip away any of the listed headers unless they are revalidated
+             * successfully (ie, must revalidate AND these headers are prohibited on stale replies).
+             * That is a bit tricky for squid right now so we avoid caching entirely.
+             */
             debugs(22, 3, HERE << "NO because server reply Cache-Control:private");
             return 0;
         }
@@ -411,15 +426,15 @@
             // NP: given the must-revalidate exception we should also be able to exempt no-cache.
             // HTTPbis WG verdict on this is that it is omitted from the spec due to being 'unexpected' by
             // some. The caching+revalidate is not exactly unsafe though with Squids interpretation of no-cache
-            // as equivalent to must-revalidate in the reply.
-        } else if (rep->cache_control->noCache() && !REFRESH_OVERRIDE(ignore_must_revalidate)) {
+            // (without parameters) as equivalent to must-revalidate in the reply.
+        } else if (rep->cache_control->hasNoCache() && !rep->cache_control->noCache().defined() && !REFRESH_OVERRIDE(ignore_must_revalidate)) {
             debugs(22, 3, HERE << "Authenticated but server reply Cache-Control:no-cache (equivalent to must-revalidate)");
             mayStore = true;
 #endif
 
             // HTTPbis pt6 section 3.2: a response CC:s-maxage is present
         } else if (rep->cache_control->sMaxAge()) {
-            debugs(22, 3, HERE << " Authenticated but server reply Cache-Control:s-maxage");
+            debugs(22, 3, HERE << "Authenticated but server reply Cache-Control:s-maxage");
             mayStore = true;
         }
 
@@ -964,10 +979,22 @@
 
     if (!ignoreCacheControl) {
         if (rep->cache_control) {
-            if (rep->cache_control->proxyRevalidate() ||
-                    rep->cache_control->mustRevalidate() ||
-                    rep->cache_control->noCache() ||
-                    rep->cache_control->hasSMaxAge())
+            // We are required to revalidate on many conditions.
+            // For security reasons we do so even if storage was caused by refresh_pattern ignore-* option
+
+            // CC:must-revalidate or CC:proxy-revalidate
+            const bool CcMustRevalidate = (rep->cache_control->proxyRevalidate() || rep->cache_control->mustRevalidate());
+
+            // CC:no-cache (not only if there are no parameters)
+            const bool CcNoCacheNoParams = (rep->cache_control->hasNoCache() && rep->cache_control->noCache().undefined());
+
+            // CC:s-maxage=N
+            const bool CcSMaxAge = rep->cache_control->hasSMaxAge();
+
+            // CC:private (if stored)
+            const bool CcPrivate = rep->cache_control->hasPrivate();
+
+            if (CcMustRevalidate || CcNoCacheNoParams || CcSMaxAge || CcPrivate)
                 EBIT_SET(entry->flags, ENTRY_REVALIDATE);
         }
 #if USE_HTTP_VIOLATIONS // response header Pragma::no-cache is undefined in HTTP
@@ -1803,7 +1830,7 @@
 #endif
 
         /* Add max-age only without no-cache */
-        if (!cc->hasMaxAge() && !cc->noCache()) {
+        if (!cc->hasMaxAge() && !cc->hasNoCache()) {
             const char *url =
                 entry ? entry->url() : urlCanonical(request);
             cc->maxAge(getMaxAge(url));


