Commit cfaab854 authored by Graham Leggett's avatar Graham Leggett
Browse files

mod_cache: When a request other than GET or HEAD arrives, we must

invalidate existing cache entities as per RFC2616 13.10. PR 15868.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1070179 13f79535-47bb-0310-9956-ffa450edef68
parent fa35c650
Loading
Loading
Loading
Loading
+4 −0
Changes for CHANGES: 4 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -2,6 +2,10 @@

Changes with Apache 2.3.11

  *) mod_cache: When a request other than GET or HEAD arrives, we must
     invalidate existing cache entities as per RFC2616 13.10. PR 15868.
     [Graham Leggett]

  *) modules: Fix many modules that were not correctly initializing if they
     were not active during server startup but got enabled later during a
     graceful restart. [Stefan Fritsch]
+7 −1
Changes for docs/manual/mod/mod_cache.xml: 7 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -302,13 +302,15 @@
  </example>

  <p>Based on the caching decision made, the reason is also written to the
  subprocess environment under one the following three keys, as appropriate:</p>
  subprocess environment under one the following four keys, as appropriate:</p>

  <dl>
    <dt>cache-hit</dt><dd>The response was served from cache.</dd>
    <dt>cache-revalidate</dt><dd>The response was stale and was successfully
      revalidated, then served from cache.</dd>
    <dt>cache-miss</dt><dd>The response was served from the upstream server.</dd>
    <dt>cache-invalidate</dt><dd>The cached entity was invalidated by a request
      method other than GET or HEAD.</dd>
  </dl>

  <p>This makes it possible to support conditional logging of cached requests
@@ -318,8 +320,12 @@
    CustomLog cached-requests.log common env=cache-hit<br />
    CustomLog uncached-requests.log common env=cache-miss<br />
    CustomLog revalidated-requests.log common env=cache-revalidate<br />
    CustomLog invalidated-requests.log common env=cache-invalidate<br />
  </example>

  <p>For module authors, a hook called <var>cache_status</var> is available,
  allowing modules to respond to the caching outcomes above in customised
  ways.</p>
</section>

<directivesynopsis>
+47 −0
Changes for modules/cache/cache_storage.c: 47 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -389,6 +389,53 @@ int cache_select(cache_request_rec *cache, request_rec *r)
    return DECLINED;
}

/*
 * invalidate a specific URL entity in all caches
 *
 * All cached entities for this URL are removed, usually in
 * response to a POST/PUT or DELETE.
 *
 * This function returns OK if at least one entity was found and
 * removed, and DECLINED if no cached entities were removed.
 */
int cache_invalidate(cache_request_rec *cache, request_rec *r)
{
    cache_provider_list *list;
    apr_status_t rv, status = DECLINED;
    cache_handle_t *h;

    if (!cache) {
        /* This should never happen */
        ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r,
                "cache: No cache request information available for key"
                " generation");
        return DECLINED;
    }

    if (!cache->key) {
        rv = cache_generate_key(r, r->pool, &cache->key);
        if (rv != APR_SUCCESS) {
            return DECLINED;
        }
    }

    /* go through the cache types */
    h = apr_palloc(r->pool, sizeof(cache_handle_t));

    list = cache->providers;

    while (list) {
        rv = list->provider->open_entity(h, r, cache->key);
        if (OK == rv) {
            list->provider->remove_url(h, r);
            status = OK;
        }
        list = list->next;
    }

    return status;
}

apr_status_t cache_generate_key_default(request_rec *r, apr_pool_t* p,
        const char **key)
{
+14 −0
Changes for modules/cache/cache_storage.h: 14 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -40,6 +40,20 @@ int cache_remove_url(cache_request_rec *cache, request_rec *r);
int cache_create_entity(cache_request_rec *cache, request_rec *r,
                        apr_off_t size, apr_bucket_brigade *in);
int cache_select(cache_request_rec *cache, request_rec *r);

/**
 * invalidate a specific URL entity in all caches
 *
 * All cached entities for this URL are removed, usually in
 * response to a POST/PUT or DELETE.
 *
 * This function returns OK if at least one entity was found and
 * removed, and DECLINED if no cached entities were removed.
 * @param h cache_handle_t
 * @param r request_rec
 */
int cache_invalidate(cache_request_rec *cache, request_rec *r);

apr_status_t cache_generate_key_default(request_rec *r, apr_pool_t* p,
        const char **key);

+55 −20
Changes for modules/cache/mod_cache.c: 55 added lines, 20 removed lines.
Original line number Diff line number Diff line
@@ -75,11 +75,6 @@ static int cache_quick_handler(request_rec *r, int lookup)
    ap_filter_rec_t *cache_out_handle;
    cache_server_conf *conf;

    /* Delay initialization until we know we are handling a GET */
    if (r->method_number != M_GET) {
        return DECLINED;
    }

    conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
                                                      &cache_module);

@@ -117,6 +112,25 @@ static int cache_quick_handler(request_rec *r, int lookup)
        return DECLINED;
    }

    /* Are we something other than GET or HEAD? If so, invalidate
     * the cached entities.
     */
    if (r->method_number != M_GET) {

        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
                "Invalidating all cached entities in response to '%s' request for %s",
                r->method, r->uri);

        cache_invalidate(cache, r);

        /* we've got a cache invalidate! tell everyone who cares */
        cache_run_cache_status(cache->handle, r, r->headers_out,
                AP_CACHE_INVALIDATE, apr_psprintf(r->pool,
                        "cache invalidated by %s", r->method));

        return DECLINED;
    }

    /*
     * Try to serve this request from the cache.
     *
@@ -176,9 +190,10 @@ static int cache_quick_handler(request_rec *r, int lookup)
                     * is available later during running the filter may be
                     * different due to an internal redirect.
                     */
                    cache->remove_url_filter =
                        ap_add_output_filter_handle(cache_remove_url_filter_handle,
                                cache, r, r->connection);
                    cache->remove_url_filter = ap_add_output_filter_handle(
                            cache_remove_url_filter_handle, cache, r,
                            r->connection);

                }
                else {
                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv,
@@ -356,11 +371,6 @@ static int cache_handler(request_rec *r)
    ap_filter_rec_t *cache_save_handle;
    cache_server_conf *conf;

    /* Delay initialization until we know we are handling a GET */
    if (r->method_number != M_GET) {
        return DECLINED;
    }

    conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
                                                      &cache_module);

@@ -384,6 +394,26 @@ static int cache_handler(request_rec *r)
    /* save away the possible providers */
    cache->providers = providers;

    /* Are we something other than GET or HEAD? If so, invalidate
     * the cached entities.
     */
    if (r->method_number != M_GET) {

        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
                "Invalidating all cached entities in response to '%s' request for %s",
                r->method, r->uri);

        cache_invalidate(cache, r);

        /* we've got a cache invalidate! tell everyone who cares */
        cache_run_cache_status(cache->handle, r, r->headers_out,
                AP_CACHE_INVALIDATE, apr_psprintf(r->pool,
                        "cache invalidated by %s", r->method));

        return DECLINED;

    }

    /*
     * Try to serve this request from the cache.
     *
@@ -464,9 +494,10 @@ static int cache_handler(request_rec *r)
                 * is available later during running the filter may be
                 * different due to an internal redirect.
                 */
                cache->remove_url_filter =
                    ap_add_output_filter_handle(cache_remove_url_filter_handle,
                            cache, r, r->connection);
                cache->remove_url_filter
                        = ap_add_output_filter_handle(
                                cache_remove_url_filter_handle, cache, r,
                                r->connection);

            }
            else {
@@ -1538,6 +1569,10 @@ static int cache_status(cache_handle_t *h, request_rec *r,
        apr_table_setn(r->subprocess_env, AP_CACHE_MISS_ENV, reason);
        break;
    }
    case AP_CACHE_INVALIDATE: {
        apr_table_setn(r->subprocess_env, AP_CACHE_INVALIDATE_ENV, reason);
        break;
    }
    }

    apr_table_setn(r->subprocess_env, AP_CACHE_STATUS_ENV, reason);
@@ -1549,10 +1584,10 @@ static int cache_status(cache_handle_t *h, request_rec *r,
        x_cache = conf->x_cache;
    }
    if (x_cache) {
        apr_table_setn(headers, "X-Cache",
                apr_psprintf(r->pool, "%s from %s",
                        status == AP_CACHE_HIT ? "HIT" : status
                                == AP_CACHE_REVALIDATE ? "REVALIDATE" : "MISS",
        apr_table_setn(headers, "X-Cache", apr_psprintf(r->pool, "%s from %s",
                status == AP_CACHE_HIT ? "HIT"
                        : status == AP_CACHE_REVALIDATE ? "REVALIDATE" : status
                                == AP_CACHE_INVALIDATE ? "INVALIDATE" : "MISS",
                r->server->server_hostname));
    }

Loading