Commit 92230a27 authored by Jim Jagielski's avatar Jim Jagielski
Browse files

Merge r1597533, r1649491, r1665216, r1756553, r1756631, r1726675, r1718496,...

Merge r1597533, r1649491, r1665216, r1756553, r1756631, r1726675, r1718496, r1718476, r1747469 from trunk:

mod_cache: try to use the key of a possible open but stale cache entry
if we have one in cache_try_lock(). PR 50317

Submitted by: Ruediger Pluem


* modules/cache/mod_socache_memcache.c (socache_mc_store): Pass
  through expiration time.

Submitted by: Faidon Liambotis <paravoid debian.org>, jorton


* mod_cache: Preserve the Content-Type in case of 304 response.
304 does not contain Content-Type and mod_mime regenerates
the Content-Type based on the r->filename. This later leads to original
Content-Type to be lost (overwriten by whatever mod_mime generates).


mod_cache: Use the actual URI path and query-string for identifying the
cached entity (key), such that rewrites are taken into account when
running afterwards (CacheQuickHandler off).  PR 21935.
 


mod_cache: follow up to r1756553: log the real/actual cached URI (debug).



better s-maxage support
 
+  *) mod_cache: Consider Cache-Control: s-maxage in expiration
+     calculations.  [Eric Covener]
+
+  *) mod_cache: Allow caching of responses with an Expires header
+     in the past that also has Cache-Control: max-age or s-maxage.
+     PR55156. [Eric Covener]




remove dead code leftover from r1023387. 

Prior to this revision, there was an apr_atoi64 in this context.
Now, ap_cache_control() sets control.max_age (which is checked here) when
the maxage value was parsed OK.



duplicate debug-level AH00764 in the just-validated path.



Rename ap_casecmpstr[n]() to ap_cstr_casecmp[n](), update with APR doxygen
Submitted by: jkaluza, jorton, jkaluza, ylavic, ylavic, covener, covener, covener, wrowe
Reviewed/backported by: jim


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1772331 13f79535-47bb-0310-9956-ffa450edef68
parent 3d553bea
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -2,6 +2,13 @@

Changes with Apache 2.4.24

  *) mod_socache_memcache: Pass expiration time through to memcached.
     [Faidon Liambotis <paravoid debian.org>, Joe Orton]

  *) mod_cache: Use the actual URI path and query-string for identifying the
     cached entity (key), such that rewrites are taken into account when
     running afterwards (CacheQuickHandler off).  PR 21935.  [Yann Ylavic]

  *) mod_http2: new directive 'H2EarlyHints' to enable sending of HTTP status
     103 interim responses. Disabled by default. [Stefan Eissing]
     
+0 −21
Original line number Diff line number Diff line
@@ -117,27 +117,6 @@ RELEASE SHOWSTOPPERS:
PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
  [ start all new proposals below, under PATCHES PROPOSED. ]

  *) mod_cache: Bring up-to-date w/ trunk.
     trunk patch:
        try to use the key of a possible open but stale cache entry (PR 50317)
            http://svn.apache.org/r1597533
        socache_mc_store: Pass through expiration time.
            http://svn.apache.org/r1649491
        Preserve the Content-Type in case of 304 response
            http://svn.apache.org/r1665216
        Use the actual URI path and query-string (PR 21935)
            http://svn.apache.org/r1756553
            http://svn.apache.org/r1756631
        better s-maxage support
            http://svn.apache.org/r1726675
            http://svn.apache.org/r1718496
            http://svn.apache.org/r1718476
        Rename ap_casecmpstr[n]() to ap_cstr_casecmp[n](), update with APR doxygen
            http://svn.apache.org/r1747469 
     2.4.x patch: http://home.apache.org/~jim/patches/httpd-2.4-cache.patch.txt
     +1: jim, ylavic, wrowe
     ylavic: r1756553 and r1649491 have a CHANGES entry.

  *) ap_reclaim_child_processes(): Implement terminate immediately
     trunk patches:
       https://svn.apache.org/r1757061
+29 −21
Original line number Diff line number Diff line
@@ -115,7 +115,7 @@ int cache_create_entity(cache_request_rec *cache, request_rec *r,

static int filter_header_do(void *v, const char *key, const char *val)
{
    if ((*key == 'W' || *key == 'w') && !strcasecmp(key, "Warning")
    if ((*key == 'W' || *key == 'w') && !ap_cstr_casecmp(key, "Warning")
            && *val == '1') {
        /* any stored Warning headers with warn-code 1xx (see section
         * 14.46) MUST be deleted from the cache entry and the forwarded
@@ -129,7 +129,7 @@ static int filter_header_do(void *v, const char *key, const char *val)
}
static int remove_header_do(void *v, const char *key, const char *val)
{
    if ((*key == 'W' || *key == 'w') && !strcasecmp(key, "Warning")) {
    if ((*key == 'W' || *key == 'w') && !ap_cstr_casecmp(key, "Warning")) {
        /* any stored Warning headers with warn-code 2xx MUST be retained
         * in the cache entry and the forwarded response.
         */
@@ -427,7 +427,9 @@ int cache_select(cache_request_rec *cache, request_rec *r)
}

static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p,
        const char *uri, apr_uri_t *parsed_uri, const char **key)
                                           const char *uri, const char *query,
                                           apr_uri_t *parsed_uri,
                                           const char **key)
{
    cache_server_conf *conf;
    char *port_str, *hn, *lcs;
@@ -563,7 +565,7 @@ static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p,
     * if needed.
     */
    path = uri;
    querystring = parsed_uri->query;
    querystring = apr_pstrdup(p, query ? query : parsed_uri->query);
    if (conf->ignore_session_id->nelts) {
        int i;
        char **identifier;
@@ -588,7 +590,7 @@ static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p,
            /*
             * Check if the identifier is in the querystring and cut it out.
             */
            if (querystring) {
            if (querystring && *querystring) {
                /*
                 * First check if the identifier is at the beginning of the
                 * querystring and followed by a '='
@@ -605,7 +607,7 @@ static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p,
                     * identifier with a '&' and append a '='
                     */
                    complete = apr_pstrcat(p, "&", *identifier, "=", NULL);
                    param = strstr(querystring, complete);
                    param = ap_strstr_c(querystring, complete);
                    /* If we found something we are sitting on the '&' */
                    if (param) {
                        param++;
@@ -669,7 +671,11 @@ static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p,
apr_status_t cache_generate_key_default(request_rec *r, apr_pool_t* p,
        const char **key)
{
    return cache_canonicalise_key(r, p, r->uri, &r->parsed_uri, key);
    /* We want the actual query-string, which may differ from
     * r->parsed_uri.query (immutable), so use "" (not NULL).
     */
    const char *args = r->args ? r->args : "";
    return cache_canonicalise_key(r, p, r->uri, args, &r->parsed_uri, key);
}

/*
@@ -709,11 +715,12 @@ int cache_invalidate(cache_request_rec *cache, request_rec *r)

    location = apr_table_get(r->headers_out, "Location");
    if (location) {
        if (APR_SUCCESS != apr_uri_parse(r->pool, location, &location_uri)
                || APR_SUCCESS
                        != cache_canonicalise_key(r, r->pool, location,
        if (apr_uri_parse(r->pool, location, &location_uri)
                || cache_canonicalise_key(r, r->pool,
                                          location, NULL,
                                          &location_uri, &location_key)
                || !(r->parsed_uri.hostname && location_uri.hostname
                || !(r->parsed_uri.hostname
                     && location_uri.hostname
                     && !strcmp(r->parsed_uri.hostname,
                                location_uri.hostname))) {
            location_key = NULL;
@@ -722,13 +729,14 @@ int cache_invalidate(cache_request_rec *cache, request_rec *r)

    content_location = apr_table_get(r->headers_out, "Content-Location");
    if (content_location) {
        if (APR_SUCCESS
                != apr_uri_parse(r->pool, content_location,
        if (apr_uri_parse(r->pool, content_location,
                          &content_location_uri)
                || APR_SUCCESS
                        != cache_canonicalise_key(r, r->pool, content_location,
                                &content_location_uri, &content_location_key)
                || !(r->parsed_uri.hostname && content_location_uri.hostname
                || cache_canonicalise_key(r, r->pool,
                                          content_location, NULL,
                                          &content_location_uri,
                                          &content_location_key)
                || !(r->parsed_uri.hostname
                     && content_location_uri.hostname
                     && !strcmp(r->parsed_uri.hostname,
                                content_location_uri.hostname))) {
            content_location_key = NULL;
+45 −62
Original line number Diff line number Diff line
@@ -31,8 +31,9 @@ extern module AP_MODULE_DECLARE_DATA cache_module;
 * in "filter". All but the path comparisons are case-insensitive.
 */
static int uri_meets_conditions(const apr_uri_t *filter, const int pathlen,
                                const apr_uri_t *url)
                                request_rec *r)
{
    const apr_uri_t *url = &r->parsed_uri;

    /* Scheme, hostname port and local part. The filter URI and the
     * URI we test may have the following shapes:
@@ -55,7 +56,7 @@ static int uri_meets_conditions(const apr_uri_t *filter, const int pathlen,
    }
    else {
        /* The URI scheme must be present and identical except for case. */
        if (!url->scheme || strcasecmp(filter->scheme, url->scheme)) {
        if (!url->scheme || ap_cstr_casecmp(filter->scheme, url->scheme)) {
            return 0;
        }

@@ -113,7 +114,7 @@ static int uri_meets_conditions(const apr_uri_t *filter, const int pathlen,
    /* For HTTP caching purposes, an empty (NULL) path is equivalent to
     * a single "/" path. RFCs 3986/2396
     */
    if (!url->path) {
    if (!r->uri) {
        if (*filter->path == '/' && pathlen == 1) {
            return 1;
        }
@@ -125,7 +126,7 @@ static int uri_meets_conditions(const apr_uri_t *filter, const int pathlen,
    /* Url has met all of the filter conditions so far, determine
     * if the paths match.
     */
    return !strncmp(filter->path, url->path, pathlen);
    return !strncmp(filter->path, r->uri, pathlen);
}

static cache_provider_list *get_provider(request_rec *r, struct cache_enable *ent,
@@ -167,8 +168,7 @@ static cache_provider_list *get_provider(request_rec *r, struct cache_enable *en
}

cache_provider_list *cache_get_providers(request_rec *r,
        cache_server_conf *conf,
        apr_uri_t uri)
                                         cache_server_conf *conf)
{
    cache_dir_conf *dconf = ap_get_module_config(r->per_dir_config, &cache_module);
    cache_provider_list *providers = NULL;
@@ -183,7 +183,7 @@ cache_provider_list *cache_get_providers(request_rec *r,
    for (i = 0; i < conf->cachedisable->nelts; i++) {
        struct cache_disable *ent =
                               (struct cache_disable *)conf->cachedisable->elts;
        if (uri_meets_conditions(&ent[i].url, ent[i].pathlen, &uri)) {
        if (uri_meets_conditions(&ent[i].url, ent[i].pathlen, r)) {
            /* Stop searching now. */
            return NULL;
        }
@@ -200,7 +200,7 @@ cache_provider_list *cache_get_providers(request_rec *r,
    for (i = 0; i < conf->cacheenable->nelts; i++) {
        struct cache_enable *ent =
                                (struct cache_enable *)conf->cacheenable->elts;
        if (uri_meets_conditions(&ent[i].url, ent[i].pathlen, &uri)) {
        if (uri_meets_conditions(&ent[i].url, ent[i].pathlen, r)) {
            providers = get_provider(r, &ent[i], providers);
        }
    }
@@ -284,8 +284,26 @@ apr_status_t cache_try_lock(cache_server_conf *conf, cache_request_rec *cache,

    /* create the key if it doesn't exist */
    if (!cache->key) {
        cache_handle_t *h;
        /*
         * Try to use the key of a possible open but stale cache
         * entry if we have one.
         */
        if (cache->handle != NULL) {
            h = cache->handle;
        }
        else {
            h = cache->stale_handle;
        }
        if ((h != NULL) &&
            (h->cache_obj != NULL) &&
            (h->cache_obj->key != NULL)) {
            cache->key = apr_pstrdup(r->pool, h->cache_obj->key);
        }
        else {
            cache_generate_key(r, r->pool, &cache->key);
        }
    }

    /* create a hashed filename from the key, and save it for later */
    lockname = ap_cache_generate_name(r->pool, 0, 0, cache->key);
@@ -315,7 +333,7 @@ apr_status_t cache_try_lock(cache_server_conf *conf, cache_request_rec *cache,
    status = apr_stat(&finfo, lockname,
                APR_FINFO_MTIME | APR_FINFO_NLINK, r->pool);
    if (!(APR_STATUS_IS_ENOENT(status)) && APR_SUCCESS != status) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EEXIST, r, APLOGNO(00779)
        ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00779)
                "Could not stat a cache lock file: %s",
                lockname);
        return status;
@@ -981,12 +999,7 @@ int ap_cache_control(request_rec *r, cache_control_t *cc,
        char *header = apr_pstrdup(r->pool, pragma_header);
        const char *token = cache_strqtok(header, CACHE_SEPARATOR, &last);
        while (token) {
            /* handle most common quickest case... */
            if (!strcmp(token, "no-cache")) {
                cc->no_cache = 1;
            }
            /* ...then try slowest case */
            else if (!strcasecmp(token, "no-cache")) {
            if (!ap_cstr_casecmp(token, "no-cache")) {
                cc->no_cache = 1;
            }
            token = cache_strqtok(NULL, CACHE_SEPARATOR, &last);
@@ -1003,52 +1016,36 @@ int ap_cache_control(request_rec *r, cache_control_t *cc,
            switch (token[0]) {
            case 'n':
            case 'N': {
                /* handle most common quickest cases... */
                if (!strcmp(token, "no-cache")) {
                    cc->no_cache = 1;
                }
                else if (!strcmp(token, "no-store")) {
                    cc->no_store = 1;
                }
                /* ...then try slowest cases */
                else if (!strncasecmp(token, "no-cache", 8)) {
                if (!ap_cstr_casecmpn(token, "no-cache", 8)) {
                    if (token[8] == '=') {
                        cc->no_cache_header = 1;
                    }
                    else if (!token[8]) {
                        cc->no_cache = 1;
                    }
                    break;
                }
                else if (!strcasecmp(token, "no-store")) {
                else if (!ap_cstr_casecmp(token, "no-store")) {
                    cc->no_store = 1;
                }
                else if (!strcasecmp(token, "no-transform")) {
                else if (!ap_cstr_casecmp(token, "no-transform")) {
                    cc->no_transform = 1;
                }
                break;
            }
            case 'm':
            case 'M': {
                /* handle most common quickest cases... */
                if (!strcmp(token, "max-age=0")) {
                    cc->max_age = 1;
                    cc->max_age_value = 0;
                }
                else if (!strcmp(token, "must-revalidate")) {
                    cc->must_revalidate = 1;
                }
                /* ...then try slowest cases */
                else if (!strncasecmp(token, "max-age", 7)) {
                if (!ap_cstr_casecmpn(token, "max-age", 7)) {
                    if (token[7] == '='
                            && !apr_strtoff(&offt, token + 8, &endp, 10)
                            && endp > token + 8 && !*endp) {
                        cc->max_age = 1;
                        cc->max_age_value = offt;
                    }
                    break;
                }
                else if (!strncasecmp(token, "max-stale", 9)) {
                else if (!ap_cstr_casecmp(token, "must-revalidate")) {
                    cc->must_revalidate = 1;
                }
                else if (!ap_cstr_casecmpn(token, "max-stale", 9)) {
                    if (token[9] == '='
                            && !apr_strtoff(&offt, token + 10, &endp, 10)
                            && endp > token + 10 && !*endp) {
@@ -1059,63 +1056,51 @@ int ap_cache_control(request_rec *r, cache_control_t *cc,
                        cc->max_stale = 1;
                        cc->max_stale_value = -1;
                    }
                    break;
                }
                else if (!strncasecmp(token, "min-fresh", 9)) {
                else if (!ap_cstr_casecmpn(token, "min-fresh", 9)) {
                    if (token[9] == '='
                            && !apr_strtoff(&offt, token + 10, &endp, 10)
                            && endp > token + 10 && !*endp) {
                        cc->min_fresh = 1;
                        cc->min_fresh_value = offt;
                    }
                    break;
                }
                else if (!strcasecmp(token, "must-revalidate")) {
                    cc->must_revalidate = 1;
                }
                break;
            }
            case 'o':
            case 'O': {
                if (!strcasecmp(token, "only-if-cached")) {
                if (!ap_cstr_casecmp(token, "only-if-cached")) {
                    cc->only_if_cached = 1;
                }
                break;
            }
            case 'p':
            case 'P': {
                /* handle most common quickest cases... */
                if (!strcmp(token, "private")) {
                    cc->private = 1;
                }
                /* ...then try slowest cases */
                else if (!strcasecmp(token, "public")) {
                if (!ap_cstr_casecmp(token, "public")) {
                    cc->public = 1;
                }
                else if (!strncasecmp(token, "private", 7)) {
                else if (!ap_cstr_casecmpn(token, "private", 7)) {
                    if (token[7] == '=') {
                        cc->private_header = 1;
                    }
                    else if (!token[7]) {
                        cc->private = 1;
                    }
                    break;
                }
                else if (!strcasecmp(token, "proxy-revalidate")) {
                else if (!ap_cstr_casecmp(token, "proxy-revalidate")) {
                    cc->proxy_revalidate = 1;
                }
                break;
            }
            case 's':
            case 'S': {
                if (!strncasecmp(token, "s-maxage", 8)) {
                if (!ap_cstr_casecmpn(token, "s-maxage", 8)) {
                    if (token[8] == '='
                            && !apr_strtoff(&offt, token + 9, &endp, 10)
                            && endp > token + 9 && !*endp) {
                        cc->s_maxage = 1;
                        cc->s_maxage_value = offt;
                    }
                    break;
                }
                break;
            }
@@ -1145,8 +1130,7 @@ static int cache_control_remove(request_rec *r, const char *cc_header,
            switch (token[0]) {
            case 'n':
            case 'N': {
                if (!strncmp(token, "no-cache", 8)
                        || !strncasecmp(token, "no-cache", 8)) {
                if (!ap_cstr_casecmpn(token, "no-cache", 8)) {
                    if (token[8] == '=') {
                        const char *header = cache_strqtok(token + 9,
                                CACHE_SEPARATOR "\"", &slast);
@@ -1163,8 +1147,7 @@ static int cache_control_remove(request_rec *r, const char *cc_header,
            }
            case 'p':
            case 'P': {
                if (!strncmp(token, "private", 7)
                        || !strncasecmp(token, "private", 7)) {
                if (!ap_cstr_casecmpn(token, "private", 7)) {
                    if (token[7] == '=') {
                        const char *header = cache_strqtok(token + 8,
                                CACHE_SEPARATOR "\"", &slast);
+1 −1
Original line number Diff line number Diff line
@@ -300,7 +300,7 @@ apr_status_t cache_remove_lock(cache_server_conf *conf,
        cache_request_rec *cache, request_rec *r, apr_bucket_brigade *bb);

cache_provider_list *cache_get_providers(request_rec *r,
        cache_server_conf *conf, apr_uri_t uri);
                                         cache_server_conf *conf);

/**
 * Get a value from a table, where the table may contain multiple
Loading