]> granicus.if.org Git - apache/commitdiff
mod_cache: Support stale-on-error behaviour for the mod_proxy case in
authorGraham Leggett <minfrin@apache.org>
Tue, 12 Oct 2010 22:54:06 +0000 (22:54 +0000)
committerGraham Leggett <minfrin@apache.org>
Tue, 12 Oct 2010 22:54:06 +0000 (22:54 +0000)
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

modules/cache/mod_cache.c

index 902341692419bccfd4cfc1f15bb67dd6698a3723..7c1cbc14c9def8da827e3d28a6e5142a40bd92d4 100644 (file)
@@ -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) {