From: Graham Leggett Date: Tue, 12 Oct 2010 22:54:06 +0000 (+0000) Subject: mod_cache: Support stale-on-error behaviour for the mod_proxy case in X-Git-Tag: 2.3.9~328 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=109ca9b7375e0ed8de2643b0c86594acfd3c4f8b;p=thirdparty%2Fapache%2Fhttpd.git mod_cache: Support stale-on-error behaviour for the mod_proxy case in addition to the existing case where the error was generated by ourselves. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1021946 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/cache/mod_cache.c b/modules/cache/mod_cache.c index 90234169241..7c1cbc14c9d 100644 --- a/modules/cache/mod_cache.c +++ b/modules/cache/mod_cache.c @@ -779,6 +779,61 @@ static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in) dconf = ap_get_module_config(r->per_dir_config, &cache_module); + /* RFC2616 13.8 Errors or Incomplete Response Cache Behavior: + * If a cache receives a 5xx response while attempting to revalidate an + * entry, it MAY either forward this response to the requesting client, + * or act as if the server failed to respond. In the latter case, it MAY + * return a previously received response unless the cached entry + * includes the "must-revalidate" cache-control directive (see section + * 14.9). + * + * This covers the case where an error was generated behind us, for example + * by a backend server via mod_proxy. + */ + if (dconf->stale_on_error && r->status >= HTTP_INTERNAL_SERVER_ERROR) { + + ap_remove_output_filter(cache->remove_url_filter); + + if (cache->stale_handle && !ap_cache_liststr( + NULL, + apr_table_get(cache->stale_handle->resp_hdrs, "Cache-Control"), + "must-revalidate", NULL)) { + const char *warn_head; + + /* morph the current save filter into the out filter, and serve from + * cache. + */ + cache->handle = cache->stale_handle; + if (r->main) { + f->frec = cache_out_subreq_filter_handle; + } + else { + f->frec = cache_out_filter_handle; + } + + r->headers_out = cache->stale_handle->resp_hdrs; + + /* add a stale warning */ + warn_head = apr_table_get(r->err_headers_out, "Warning"); + if ((warn_head == NULL) || ((warn_head != NULL) + && (ap_strstr_c(warn_head, "110") == NULL))) { + apr_table_mergen(r->err_headers_out, "Warning", + "110 Response is stale"); + } + + cache_run_cache_status(cache->handle, r, r->headers_out, AP_CACHE_HIT, + apr_psprintf(r->pool, + "cache hit: %d status; stale content returned", + r->status)); + + /* give someone else the chance to cache the file */ + cache_remove_lock(conf, cache, f->r, NULL); + + /* pass brigade to our morphed out filter */ + return ap_pass_brigade(f, in); + } + } + /* read expiry date; if a bad date, then leave it so the client can * read it */ @@ -1534,6 +1589,9 @@ static void cache_insert_error_filter(request_rec *r) * return a previously received response unless the cached entry * includes the "must-revalidate" cache-control directive (see section * 14.9). + * + * This covers the case where the error was generated by our server via + * ap_die(). */ apr_pool_userdata_get(&dummy, CACHE_CTX_KEY, r->pool); if (dummy) {