Here is the patch that strips the "no-cache=" or "private=" specified headers after the origin server's validation, leaving the only headers updated by the origin.
Regards, Yann. Index: modules/cache/cache_storage.c =================================================================== --- modules/cache/cache_storage.c (revision 1456050) +++ modules/cache/cache_storage.c (working copy) @@ -156,6 +156,51 @@ apr_table_unset(h->resp_hdrs, "Last-Modified"); } + v = apr_table_get(h->resp_hdrs, "Cache-Control"); + if (v && (h->cache_obj->info.control.no_cache_header || + h->cache_obj->info.control.private_header)) { + /* + * RFC2616 14.9.1: If the no-cache directive does specify one or more + * field-names, then a cache MAY use the response to satisfy a + * subsequent request, subject to any other restrictions on caching. + * However, the specified field-name(s) MUST NOT be sent in the + * response to a subsequent request without successful revalidation + * with the origin server. + * + * Hence we will strip these cached headers (if any) and let the only + * ones validated by the origin server. + */ + char *token; + apr_size_t len; + while ((token = ap_get_list_item(r->pool, &v))) { + /* ap_get_list_item() strips the spurious whitespaces and + * lowercases anything (but the quoted-strings) */ + if (strncmp(token, "no-cache=", 9) == 0) { + token += 9; + } + else if (strncmp(token, "private=", 8) == 0) { + token += 8; + } + else { + continue; + } + + /* RFC2616 14.9: quoted list of field-names */ + len = strlen(token); + if (token[0] == '"' && token[--len] == '"') { + (++token)[--len] = '\0'; + do { + const char *name = ap_cache_tokstr(r->pool, token, + (const char**)&token); + if (name) { + /* strip that name header the response */ + apr_table_unset(h->resp_hdrs, name); + } + } while (token); + } + } + } + /* The HTTP specification says that it is legal to merge duplicate * headers into one. Some browsers that support Cookies don't like * merged headers and prefer that each Set-Cookie header is sent