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
*/
* 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) {