Commit c20eb1c5 authored by Justin Erenkrantz's avatar Justin Erenkrantz
Browse files

Add CacheStorePrivate, CacheStoreNoStore, and clarify CacheIgnoreCacheControl.

* docs/manual/mod/mod_cache.xml: Update documentation for
  CacheIgnoreCacheControl and add documentation for two new directives.
* modules/cache/mod_cache.c
  (cache_url_handler): Honor 'Cache-Control: no-cache' request header.
  (cache_save_filter): Only honor no-store or private when their respective
                       directives are Off (which is the default).
  rest of file: add in standard configuration syntax stuff...
* modules/cache/mod_cache.h: Minor formatting tweak and add new fields.

Suggested by: Pier Fumagalli


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@149492 13f79535-47bb-0310-9956-ffa450edef68
parent 7f5df005
Loading
Loading
Loading
Loading
+3 −0
Changes for CHANGES: 3 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -2,6 +2,9 @@ Changes with Apache 2.1.3
  [Remove entries to the current 2.0 section below, when backported]
  *) mod_cache: Add CacheStorePrivate and CacheStoreNoStore directive.
     [Justin Erenkrantz]
  *) Remove compiled-in upper limit on LimitRequestFieldSize.
     [Bill Stoddard]
+78 −7
Changes for docs/manual/mod/mod_cache.xml: 78 added lines, 7 removed lines.
Original line number Diff line number Diff line
@@ -235,24 +235,33 @@ header.</description>

<directivesynopsis>
<name>CacheIgnoreCacheControl</name>
<description>Ignore the fact that the client requested the content not be
cached.</description>
<description>Ignore request to not serve cached content to client</description>
<syntax>CacheIgnoreCacheControl On|Off</syntax>
<default>CacheIgnoreCacheControl Off</default>
<contextlist><context>server config</context><context>virtual host</context>
</contextlist>

<usage>
    <p>Ordinarily, documents with no-cache or no-store header values will not be stored in the cache.
    The <directive>CacheIgnoreCacheControl</directive> directive allows this behavior to be overridden.
    <directive>CacheIgnoreCacheControl</directive> On tells the server to attempt to cache the document
    even if it contains no-cache or no-store header values. Documents requiring authorization will
    <em>never</em> be cached.</p>
    <p>Ordinarily, requests containing a Cache-Control: no-cache or
    Pragma: no-cache header value will not be served from the cache.  The
    <directive>CacheIgnoreCacheControl</directive> directive allows this
    behavior to be overridden.  <directive>CacheIgnoreCacheControl</directive>
    On tells the server to attempt to serve the resource from the cache even
    if the request contains no-cache header values.  Resources requiring
    authorization will <em>never</em> be cached.</p>

    <example>
      CacheIgnoreCacheControl On
    </example>

    <note type="warning"><title>Warning:</title>
       This directive will allow serving from the cache even if the client has
       requested that the document not be served from the cache.  This might
       result in stale content being served.
    </note>
</usage>
<seealso><directive module="mod_cache">CacheStorePrivate</directive></seealso>
<seealso><directive module="mod_cache">CacheStoreNoStore</directive></seealso>
</directivesynopsis>

<directivesynopsis>
@@ -343,4 +352,66 @@ LastModified date.</description>
</usage>
</directivesynopsis>

<directivesynopsis>
<name>CacheStorePrivate</name>
<description>Attempt to cache responses that the server has marked as private</description>
<syntax>CacheStorePrivate On|Off</syntax>
<default>CacheStorePrivate Off</default>
<contextlist><context>server config</context><context>virtual host</context>
</contextlist>

<usage>
    <p>Ordinarily, responses with Cache-Control: private header values will not
       be stored in the cache.  The <directive>CacheStorePrivate</directive>
       directive allows this behavior to be overridden.
       <directive>CacheStorePrivate</directive> On
       tells the server to attempt to cache the resource even if it contains
       private header values.  Resources requiring authorization will
       <em>never</em> be cached.</p>

    <example>
      CacheStorePrivate On
    </example>

    <note type="warning"><title>Warning:</title>
       This directive will allow caching even if the upstream server has
       requested that the resource not be cached.  This directive is only
       ideal for a 'private' cache.
    </note>
</usage>
<seealso><directive module="mod_cache">CacheIgnoreCacheControl</directive></seealso>
<seealso><directive module="mod_cache">CacheStoreNoStore</directive></seealso>
</directivesynopsis>

<directivesynopsis>
<name>CacheStoreNoStore</name>
<description>Attempt to cache requests or responses that have been marked as no-store.</description>
<syntax>CacheStoreNoStore On|Off</syntax>
<default>CacheStoreNoStore Off</default>
<contextlist><context>server config</context><context>virtual host</context>
</contextlist>

<usage>
    <p>Ordinarily, requests or responses with Cache-Control: no-store header
       values will not be stored in the cache.  The
       <directive>CacheStoreNoCache</directive> directive allows this
       behavior to be overridden.  <directive>CacheStoreNoCache</directive> On
       tells the server to attempt to cache the resource even if it contains
       no-store header values.  Resources requiring authorization will
       <em>never</em> be cached.</p>

    <example>
      CacheStoreNoStore On
    </example>

    <note type="warning"><title>Warning:</title>
       As described in RFC 2616, the no-store directive is intended to
       "prevent the inadvertent release or retention of sensitive information
       (for example, on backup tapes)."  Enabling this option could store
       sensitive information in the cache.  You are hereby warned.
    </note>
</usage>
<seealso><directive module="mod_cache">CacheIgnoreCacheControl</directive></seealso>
<seealso><directive module="mod_cache">CacheStorePrivate</directive></seealso>
</directivesynopsis>
</modulesynopsis>
+74 −16
Changes for modules/cache/mod_cache.c: 74 added lines, 16 removed lines.
Original line number Diff line number Diff line
@@ -47,7 +47,7 @@ static ap_filter_rec_t *cache_out_filter_handle;
static int cache_url_handler(request_rec *r, int lookup)
{
    apr_status_t rv;
    const char *pragma, *auth;
    const char *auth;
    apr_uri_t uri;
    char *url;
    char *path;
@@ -93,21 +93,23 @@ static int cache_url_handler(request_rec *r, int lookup)
     */

    /* find certain cache controlling headers */
    pragma = apr_table_get(r->headers_in, "Pragma");
    auth = apr_table_get(r->headers_in, "Authorization");

    /* first things first - does the request allow us to return
     * cached information at all? If not, just decline the request.
     *
     * Note that there is a big difference between not being allowed
     * to cache a request (no-store) and not being allowed to return
     * to cache a response (no-store) and not being allowed to return
     * a cached request without revalidation (max-age=0).
     *
     * Caching is forbidden under the following circumstances:
     * Serving from a cache is forbidden under the following circumstances:
     *
     * - RFC2616 14.9.2 Cache-Control: no-store
     * - RFC2616 14.9.1 Cache-Control: no-cache
     * - Pragma: no-cache
     * - Any requests requiring authorization.
     *
     * Updating a cache is forbidden under the following circumstances:
     * - RFC2616 14.9.2 Cache-Control: no-store
     */
    if (conf->ignorecachecontrol == 1 && auth == NULL) {
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
@@ -115,8 +117,14 @@ static int cache_url_handler(request_rec *r, int lookup)
                     "%s, but we know better and are ignoring it", url);
    }
    else {
        if (ap_cache_liststr(NULL, pragma, "no-cache", NULL) ||
            auth != NULL) {
        const char *pragma, *cc_in;

        pragma = apr_table_get(r->headers_in, "Pragma");
        cc_in = apr_table_get(r->headers_in, "Cache-Control");

        if (auth != NULL ||
            ap_cache_liststr(NULL, pragma, "no-cache", NULL) ||
            ap_cache_liststr(NULL, cc_in, "no-cache", NULL)) {
            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                         "cache: no-cache or authorization forbids caching "
                         "of %s", url);
@@ -263,10 +271,16 @@ static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in)
    char *reason;
    apr_pool_t *p;

    /* check first whether running this filter has any point or not */
    /* If the user has Cache-Control: no-store from RFC 2616, don't store! */
    conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
                                                      &cache_module);

    /* If the request has Cache-Control: no-store from RFC 2616, don't store
     * unless CacheStoreNoStore is active.
     */
    cc_in = apr_table_get(r->headers_in, "Cache-Control");
    if (r->no_cache || ap_cache_liststr(NULL, cc_in, "no-store", NULL)) {
    if (r->no_cache ||
        (!conf->store_nostore &&
         ap_cache_liststr(NULL, cc_in, "no-store", NULL))) {
        ap_remove_output_filter(f);
        return ap_pass_brigade(f->next, in);
    }
@@ -349,7 +363,6 @@ static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in)
        lastmod = APR_DATE_BAD;
    }

    conf = (cache_server_conf *) ap_get_module_config(r->server->module_config, &cache_module);
    /* read the etag and cache-control from the entity */
    etag = apr_table_get(r->err_headers_out, "Etag");
    if (etag == NULL) {
@@ -410,14 +423,16 @@ static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in)
        /* HEAD requests */
        reason = "HTTP HEAD request";
    }
    else if (ap_cache_liststr(NULL, cc_out, "no-store", NULL)) {
    else if (!conf->store_nostore &&
             ap_cache_liststr(NULL, cc_out, "no-store", NULL)) {
        /* RFC2616 14.9.2 Cache-Control: no-store response
         * indicating do not cache, or stop now if you are
         * trying to cache it */
        reason = "Cache-Control: no-store present";
    }
    else if (ap_cache_liststr(NULL, cc_out, "private", NULL)) {
        /* RFC2616 14.9.1 Cache-Control: private
    else if (!conf->store_private &&
             ap_cache_liststr(NULL, cc_out, "private", NULL)) {
        /* RFC2616 14.9.1 Cache-Control: private response
         * this object is marked for this user's eyes only. Behave
         * as a tunnel.
         */
@@ -706,6 +721,10 @@ static void * create_cache_config(apr_pool_t *p, server_rec *s)
    ps->no_last_mod_ignore = 0;
    ps->ignorecachecontrol = 0;
    ps->ignorecachecontrol_set = 0;
    ps->store_private = 0;
    ps->store_private_set = 0;
    ps->store_nostore = 0;
    ps->store_nostore_set = 0;
    /* array of headers that should not be stored in cache */
    ps->ignore_headers = apr_array_make(p, 10, sizeof(char *));
    ps->ignore_headers_set = CACHE_IGNORE_HEADERS_UNSET;
@@ -742,6 +761,14 @@ static void * merge_cache_config(apr_pool_t *p, void *basev, void *overridesv)
        (overrides->ignorecachecontrol_set == 0)
        ? base->ignorecachecontrol
        : overrides->ignorecachecontrol;
    ps->store_private  =
        (overrides->store_private_set == 0)
        ? base->store_private
        : overrides->store_private;
    ps->store_nostore  =
        (overrides->store_nostore_set == 0)
        ? base->store_nostore
        : overrides->store_nostore;
    ps->ignore_headers =
        (overrides->ignore_headers_set == CACHE_IGNORE_HEADERS_UNSET)
        ? base->ignore_headers
@@ -775,6 +802,32 @@ static const char *set_cache_ignore_cachecontrol(cmd_parms *parms,
    return NULL;
}

static const char *set_cache_store_private(cmd_parms *parms, void *dummy,
                                           int flag)
{
    cache_server_conf *conf;

    conf =
        (cache_server_conf *)ap_get_module_config(parms->server->module_config,
                                                  &cache_module);
    conf->store_private = flag;
    conf->store_private_set = 1;
    return NULL;
}

static const char *set_cache_store_nostore(cmd_parms *parms, void *dummy,
                                           int flag)
{
    cache_server_conf *conf;

    conf =
        (cache_server_conf *)ap_get_module_config(parms->server->module_config,
                                                  &cache_module);
    conf->store_nostore = flag;
    conf->store_nostore_set = 1;
    return NULL;
}

static const char *add_ignore_header(cmd_parms *parms, void *dummy,
                                     const char *header)
{
@@ -915,9 +968,14 @@ static const command_rec cache_cmds[] =
                 RSRC_CONF,
                 "Ignore Responses where there is no Last Modified Header"),
    AP_INIT_FLAG("CacheIgnoreCacheControl", set_cache_ignore_cachecontrol,
                  NULL, 
                  RSRC_CONF, 
                 NULL, RSRC_CONF,
                 "Ignore requests from the client for uncached content"),
    AP_INIT_FLAG("CacheStorePrivate", set_cache_store_private,
                 NULL, RSRC_CONF,
                 "Ignore 'Cache-Control: private' and store private content"),
    AP_INIT_FLAG("CacheStoreNoStore", set_cache_store_nostore,
                 NULL, RSRC_CONF,
                 "Ignore 'Cache-Control: no-store' and store sensitive content"),
    AP_INIT_ITERATE("CacheIgnoreHeaders", add_ignore_header, NULL, RSRC_CONF,
                    "A space separated list of headers that should not be "
                    "stored by the cache"),
+12 −3
Changes for modules/cache/mod_cache.h: 12 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -117,11 +117,14 @@ struct cache_disable {
typedef struct {
    apr_array_header_t *cacheenable;    /* URLs to cache */
    apr_array_header_t *cachedisable;   /* URLs not to cache */
    apr_time_t maxex;			/* Maximum time to keep cached files in msecs */
    /* Maximum time to keep cached files in msecs */
    apr_time_t maxex;
    int maxex_set;
    apr_time_t defex;           /* default time to keep cached file in msecs */
    /* default time to keep cached file in msecs */
    apr_time_t defex;
    int defex_set;
    double factor;              /* factor for estimating expires date */
    /* factor for estimating expires date */
    double factor;
    int factor_set;
    /** ignore the last-modified header when deciding to cache this request */
    int no_last_mod_ignore_set;
@@ -129,6 +132,12 @@ typedef struct {
    /** ignore client's requests for uncached responses */
    int ignorecachecontrol;
    int ignorecachecontrol_set;
    /** ignore Cache-Control: private header from server */
    int store_private;
    int store_private_set;
    /** ignore Cache-Control: no-store header from client or server */
    int store_nostore;
    int store_nostore_set;
    /** store the headers that should not be stored in the cache */
    apr_array_header_t *ignore_headers;
    /* flag if CacheIgnoreHeader has been set */