From: Graham Leggett Date: Sat, 4 Sep 2010 15:20:30 +0000 (+0000) Subject: mod_cache: Check the request to determine whether we are allowed X-Git-Tag: 2.3.9~512 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c3084aa4dee9fd8700fd2ca43861aa33e8e1dadc;p=thirdparty%2Fapache%2Fhttpd.git mod_cache: Check the request to determine whether we are allowed to return cached content at all, and respect a "Cache-Control: no-cache" header from a client. Previously, "no-cache" would behave like "max-age=0". git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@992625 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 59b71ed5dce..ba55eb26c2b 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,11 @@ Changes with Apache 2.3.9 + *) mod_cache: Check the request to determine whether we are allowed + to return cached content at all, and respect a "Cache-Control: + no-cache" header from a client. Previously, "no-cache" would + behave like "max-age=0". [Graham Leggett] + *) mod_cache: Use a proper filter context to hold filter data instead of misusing the per-request configuration. Fixes a segfault on trunk when the normal handler is used. [Graham Leggett] diff --git a/modules/cache/cache_storage.c b/modules/cache/cache_storage.c index 9137fca0b0d..cfc0fdfaa02 100644 --- a/modules/cache/cache_storage.c +++ b/modules/cache/cache_storage.c @@ -203,6 +203,11 @@ int cache_select(request_rec *r) if (rv != APR_SUCCESS) { return rv; } + + if (!ap_cache_check_allowed(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 70242a793ae..af180770602 100644 --- a/modules/cache/cache_util.c +++ b/modules/cache/cache_util.c @@ -380,6 +380,64 @@ CACHE_DECLARE(apr_status_t) ap_cache_remove_lock(cache_server_conf *conf, return apr_file_remove(lockname, r->pool); } +CACHE_DECLARE(int) ap_cache_check_allowed(request_rec *r) { + const char *cc_cresp, *cc_req; + const char *pragma; + 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. + * + * This is covered under RFC2616 section 14.9.4 (Cache Revalidation and + * Reload Controls). + * + * - 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"); + + if (ap_cache_liststr(NULL, pragma, "no-cache", NULL) + || ap_cache_liststr(NULL, cc_req, "no-cache", NULL)) { + + if (!conf->ignorecachecontrol) { + return 0; + } + else { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, + "Incoming request is asking for an uncached version of " + "%s, but we have been configured to ignore it and serve " + "cached content anyway", r->unparsed_uri); + } + } + + if (ap_cache_liststr(NULL, cc_req, "no-store", NULL)) { + + if (!conf->ignorecachecontrol) { + /* We're not allowed to serve a cached copy */ + return 0; + } + else { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, + "Incoming request is asking for a no-store version of " + "%s, but we have been configured to ignore it and serve " + "cached content anyway", r->unparsed_uri); + } + } + + return 1; +} + + CACHE_DECLARE(int) ap_cache_check_freshness(cache_handle_t *h, request_rec *r) { @@ -402,10 +460,11 @@ CACHE_DECLARE(int) ap_cache_check_freshness(cache_handle_t *h, * We now want to check if our cached data is still fresh. This depends * on a few things, in this order: * - * - RFC2616 14.9.4 End to end reload, Cache-Control: no-cache. no-cache in - * either the request or the cached response means that we must - * revalidate the request unconditionally, overriding any expiration - * mechanism. It's equivalent to max-age=0,must-revalidate. + * - RFC2616 14.9.4 End to end reload, Cache-Control: no-cache. no-cache + * in either the request or the cached response means that we must + * perform the request unconditionally, and ignore cached content. We + * should never reach here, but if we do, mark the content as stale, + * as this is the best we can do. * * - RFC2616 14.32 Pragma: no-cache This is treated the same as * Cache-Control: no-cache. @@ -445,7 +504,8 @@ CACHE_DECLARE(int) ap_cache_check_freshness(cache_handle_t *h, ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server, "Incoming request is asking for a uncached version of " - "%s, but we know better and are ignoring it", + "%s, but we have been configured to ignore it and " + "serve a cached response anyway", r->unparsed_uri); } diff --git a/modules/cache/mod_cache.h b/modules/cache/mod_cache.h index d2984a45573..a8183372752 100644 --- a/modules/cache/mod_cache.h +++ b/modules/cache/mod_cache.h @@ -287,6 +287,15 @@ CACHE_DECLARE(apr_time_t) ap_cache_current_age(cache_info *info, const apr_time_ */ CACHE_DECLARE(int) ap_cache_check_freshness(cache_handle_t *h, request_rec *r); +/** + * Check the whether the request allows a cached object to be served as per RFC2616 + * section 14.9.4 (Cache Revalidation and Reload Controls) + * @param h cache_handle_t + * @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(request_rec *r); + /** * Try obtain a cache wide lock on the given cache key. *