From 9fedad7f26e8464889e6b6eb3d7ed690b8bd5ef7 Mon Sep 17 00:00:00 2001 From: Graham Leggett Date: Tue, 28 May 2013 21:09:34 +0000 Subject: [PATCH] mod_cache: Honour Cache-Control: no-store in a request. trunk patch: http://svn.apache.org/r1479222 2.4.x patch: http://people.apache.org/~minfrin/httpd-mod_cache-nostore2.4.patch Submitted by: minfrin Reviewed by: jim, wrowe git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1487121 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 2 ++ STATUS | 5 ---- modules/cache/cache_storage.c | 11 ++++++--- modules/cache/cache_util.c | 46 ++++++++++++++++++++++++++--------- modules/cache/cache_util.h | 11 ++++++++- modules/cache/mod_cache.c | 10 ++++++++ 6 files changed, 64 insertions(+), 21 deletions(-) diff --git a/CHANGES b/CHANGES index ee5b7cd724..f6d5ffd8ac 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,8 @@ Changes with Apache 2.4.5 + *) mod_cache: Honour Cache-Control: no-store in a request. [Graham Leggett] + *) mod_cache: Make sure that contradictory entity headers present in a 304 Not Modified response are caught and cause the entity to be removed. [Graham Leggett] diff --git a/STATUS b/STATUS index fcbc5821b9..cc920ea9cc 100644 --- a/STATUS +++ b/STATUS @@ -90,11 +90,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - * mod_cache: Honour Cache-Control: no-store in a request. - trunk patch: http://svn.apache.org/r1479222 - 2.4.x patch: http://people.apache.org/~minfrin/httpd-mod_cache-nostore2.4.patch - +1: minfrin, jim, wrowe - * mod_cache: Ensure that updated responses to HEAD requests don't get mistakenly paired with a previously cached body. Ensure that any existing body is removed when a HEAD request is cached. diff --git a/modules/cache/cache_storage.c b/modules/cache/cache_storage.c index b1968ff258..11f98e8f01 100644 --- a/modules/cache/cache_storage.c +++ b/modules/cache/cache_storage.c @@ -225,6 +225,13 @@ int cache_select(cache_request_rec *cache, request_rec *r) return DECLINED; } + /* if no-cache, we can't serve from the cache, but we may store to the + * cache. + */ + if (!ap_cache_check_no_cache(cache, r)) { + return DECLINED; + } + if (!cache->key) { rv = cache_generate_key(r, r->pool, &cache->key); if (rv != APR_SUCCESS) { @@ -232,10 +239,6 @@ int cache_select(cache_request_rec *cache, request_rec *r) } } - if (!ap_cache_check_allowed(cache, r)) { - return DECLINED; - } - /* go through the cache types till we get a match */ h = apr_palloc(r->pool, sizeof(cache_handle_t)); diff --git a/modules/cache/cache_util.c b/modules/cache/cache_util.c index f85b125423..7b7fb45c23 100644 --- a/modules/cache/cache_util.c +++ b/modules/cache/cache_util.c @@ -410,9 +410,9 @@ apr_status_t cache_remove_lock(cache_server_conf *conf, return apr_file_remove(lockname, r->pool); } -CACHE_DECLARE(int) ap_cache_check_allowed(cache_request_rec *cache, request_rec *r) { - const char *cc_req; - const char *pragma; +int ap_cache_check_no_cache(cache_request_rec *cache, request_rec *r) +{ + cache_server_conf *conf = (cache_server_conf *)ap_get_module_config(r->server->module_config, &cache_module); @@ -427,16 +427,15 @@ CACHE_DECLARE(int) ap_cache_check_allowed(cache_request_rec *cache, request_rec * - RFC2616 14.9.4 End to end reload, Cache-Control: no-cache, or Pragma: * no-cache. The server MUST NOT use a cached copy when responding to such * a request. - * - * - RFC2616 14.9.2 What May be Stored by Caches. If Cache-Control: - * no-store arrives, do not serve from the cache. */ /* This value comes from the client's initial request. */ - cc_req = apr_table_get(r->headers_in, "Cache-Control"); - pragma = apr_table_get(r->headers_in, "Pragma"); - - ap_cache_control(r, &cache->control_in, cc_req, pragma, r->headers_in); + if (!cache->control_in.parsed) { + const char *cc_req = cache_table_getm(r->pool, r->headers_in, + "Cache-Control"); + const char *pragma = cache_table_getm(r->pool, r->headers_in, "Pragma"); + ap_cache_control(r, &cache->control_in, cc_req, pragma, r->headers_in); + } if (cache->control_in.no_cache) { @@ -451,6 +450,32 @@ CACHE_DECLARE(int) ap_cache_check_allowed(cache_request_rec *cache, request_rec } } + return 1; +} + +int ap_cache_check_no_store(cache_request_rec *cache, request_rec *r) +{ + + cache_server_conf *conf = + (cache_server_conf *)ap_get_module_config(r->server->module_config, + &cache_module); + + /* + * At this point, we may have data cached, but the request may have + * specified that cached data may not be used in a response. + * + * - RFC2616 14.9.2 What May be Stored by Caches. If Cache-Control: + * no-store arrives, do not serve from or store to the cache. + */ + + /* This value comes from the client's initial request. */ + if (!cache->control_in.parsed) { + const char *cc_req = cache_table_getm(r->pool, r->headers_in, + "Cache-Control"); + const char *pragma = cache_table_getm(r->pool, r->headers_in, "Pragma"); + ap_cache_control(r, &cache->control_in, cc_req, pragma, r->headers_in); + } + if (cache->control_in.no_store) { if (!conf->ignorecachecontrol) { @@ -468,7 +493,6 @@ CACHE_DECLARE(int) ap_cache_check_allowed(cache_request_rec *cache, request_rec return 1; } - int cache_check_freshness(cache_handle_t *h, cache_request_rec *cache, request_rec *r) { diff --git a/modules/cache/cache_util.h b/modules/cache/cache_util.h index 65321d1fb8..3a54fadd06 100644 --- a/modules/cache/cache_util.h +++ b/modules/cache/cache_util.h @@ -239,7 +239,16 @@ typedef struct { * @param r request_rec * @return 0 ==> cache object may not be served, 1 ==> cache object may be served */ -CACHE_DECLARE(int) ap_cache_check_allowed(cache_request_rec *cache, request_rec *r); +int ap_cache_check_no_cache(cache_request_rec *cache, request_rec *r); + +/** + * Check the whether the request allows a cached object to be stored as per RFC2616 + * section 14.9.2 (What May be Stored by Caches) + * @param cache cache_request_rec + * @param r request_rec + * @return 0 ==> cache object may not be served, 1 ==> cache object may be served + */ +int ap_cache_check_no_store(cache_request_rec *cache, request_rec *r); /** * Check the freshness of the cache object per RFC2616 section 13.2 (Expiration Model) diff --git a/modules/cache/mod_cache.c b/modules/cache/mod_cache.c index de61ba12c0..9258ebd564 100644 --- a/modules/cache/mod_cache.c +++ b/modules/cache/mod_cache.c @@ -102,6 +102,9 @@ static int cache_quick_handler(request_rec *r, int lookup) /* * Are we allowed to serve cached info at all? */ + if (!ap_cache_check_no_store(cache, r)) { + return DECLINED; + } /* find certain cache controlling headers */ auth = apr_table_get(r->headers_in, "Authorization"); @@ -401,6 +404,13 @@ static int cache_handler(request_rec *r) /* save away the possible providers */ cache->providers = providers; + /* + * Are we allowed to serve cached info at all? + */ + if (!ap_cache_check_no_store(cache, r)) { + return DECLINED; + } + /* Are we PUT/POST/DELETE? If so, prepare to invalidate the cached entities. */ switch (r->method_number) { -- 2.40.0