mirror of
https://github.com/apache/httpd.git
synced 2025-07-30 20:03:10 +03:00
mod_cache: Fix a regression in 2.4.25 for the forward proxy case by
computing and using the same entity key according to when the cache checks, loads and saves the request. PR 60577. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1783842 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
5
CHANGES
5
CHANGES
@ -1,6 +1,11 @@
|
|||||||
-*- coding: utf-8 -*-
|
-*- coding: utf-8 -*-
|
||||||
Changes with Apache 2.5.0
|
Changes with Apache 2.5.0
|
||||||
|
|
||||||
|
*) mod_cache: Fix a regression in 2.4.25 for the forward proxy case by
|
||||||
|
computing and using the same entity key according to when the cache
|
||||||
|
checks, loads and saves the request.
|
||||||
|
PR 60577. [Yann Ylavic]
|
||||||
|
|
||||||
*) mod_proxy_http2: support for ProxyPreserverHost directive. [Stefan Eissing]
|
*) mod_proxy_http2: support for ProxyPreserverHost directive. [Stefan Eissing]
|
||||||
|
|
||||||
*) mod_proxy_fcgi: Add ProxyFCGISetEnvIf to fixup CGI environment
|
*) mod_proxy_fcgi: Add ProxyFCGISetEnvIf to fixup CGI environment
|
||||||
|
87
modules/cache/cache_storage.c
vendored
87
modules/cache/cache_storage.c
vendored
@ -427,7 +427,7 @@ int cache_select(cache_request_rec *cache, request_rec *r)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p,
|
static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p,
|
||||||
const char *uri, const char *query,
|
const char *path, const char *query,
|
||||||
apr_uri_t *parsed_uri,
|
apr_uri_t *parsed_uri,
|
||||||
const char **key)
|
const char **key)
|
||||||
{
|
{
|
||||||
@ -435,8 +435,8 @@ static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p,
|
|||||||
char *port_str, *hn, *lcs;
|
char *port_str, *hn, *lcs;
|
||||||
const char *hostname, *scheme;
|
const char *hostname, *scheme;
|
||||||
int i;
|
int i;
|
||||||
const char *path;
|
const char *kpath;
|
||||||
char *querystring;
|
const char *kquery;
|
||||||
|
|
||||||
if (*key) {
|
if (*key) {
|
||||||
/*
|
/*
|
||||||
@ -564,8 +564,8 @@ static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p,
|
|||||||
* Check if we need to ignore session identifiers in the URL and do so
|
* Check if we need to ignore session identifiers in the URL and do so
|
||||||
* if needed.
|
* if needed.
|
||||||
*/
|
*/
|
||||||
path = uri;
|
kpath = path;
|
||||||
querystring = apr_pstrdup(p, query ? query : parsed_uri->query);
|
kquery = conf->ignorequerystring ? NULL : query;
|
||||||
if (conf->ignore_session_id->nelts) {
|
if (conf->ignore_session_id->nelts) {
|
||||||
int i;
|
int i;
|
||||||
char **identifier;
|
char **identifier;
|
||||||
@ -580,24 +580,23 @@ static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p,
|
|||||||
* Check that we have a parameter separator in the last segment
|
* Check that we have a parameter separator in the last segment
|
||||||
* of the path and that the parameter matches our identifier
|
* of the path and that the parameter matches our identifier
|
||||||
*/
|
*/
|
||||||
if ((param = ap_strrchr_c(path, ';'))
|
if ((param = ap_strrchr_c(kpath, ';'))
|
||||||
&& !strncmp(param + 1, *identifier, len)
|
&& !strncmp(param + 1, *identifier, len)
|
||||||
&& (*(param + len + 1) == '=')
|
&& (*(param + len + 1) == '=')
|
||||||
&& !ap_strchr_c(param + len + 2, '/')) {
|
&& !ap_strchr_c(param + len + 2, '/')) {
|
||||||
path = apr_pstrmemdup(p, path, param - path);
|
kpath = apr_pstrmemdup(p, kpath, param - kpath);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Check if the identifier is in the querystring and cut it out.
|
* Check if the identifier is in the query string and cut it out.
|
||||||
*/
|
*/
|
||||||
if (querystring && *querystring) {
|
if (kquery && *kquery) {
|
||||||
/*
|
/*
|
||||||
* First check if the identifier is at the beginning of the
|
* First check if the identifier is at the beginning of the
|
||||||
* querystring and followed by a '='
|
* query string and followed by a '='
|
||||||
*/
|
*/
|
||||||
if (!strncmp(querystring, *identifier, len)
|
if (!strncmp(kquery, *identifier, len) && kquery[len] == '=') {
|
||||||
&& (*(querystring + len) == '=')) {
|
param = kquery;
|
||||||
param = querystring;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
char *complete;
|
char *complete;
|
||||||
@ -607,7 +606,7 @@ static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p,
|
|||||||
* identifier with a '&' and append a '='
|
* identifier with a '&' and append a '='
|
||||||
*/
|
*/
|
||||||
complete = apr_pstrcat(p, "&", *identifier, "=", NULL);
|
complete = apr_pstrcat(p, "&", *identifier, "=", NULL);
|
||||||
param = ap_strstr_c(querystring, complete);
|
param = ap_strstr_c(kquery, complete);
|
||||||
/* If we found something we are sitting on the '&' */
|
/* If we found something we are sitting on the '&' */
|
||||||
if (param) {
|
if (param) {
|
||||||
param++;
|
param++;
|
||||||
@ -615,28 +614,28 @@ static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p,
|
|||||||
}
|
}
|
||||||
if (param) {
|
if (param) {
|
||||||
const char *amp;
|
const char *amp;
|
||||||
|
char *dup = NULL;
|
||||||
|
|
||||||
if (querystring != param) {
|
if (kquery != param) {
|
||||||
querystring = apr_pstrndup(p, querystring,
|
dup = apr_pstrmemdup(p, kquery, param - kquery);
|
||||||
param - querystring);
|
kquery = dup;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
querystring = "";
|
kquery = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((amp = ap_strchr_c(param + len + 1, '&'))) {
|
if ((amp = ap_strchr_c(param + len + 1, '&'))) {
|
||||||
querystring = apr_pstrcat(p, querystring, amp + 1,
|
kquery = apr_pstrcat(p, kquery, amp + 1, NULL);
|
||||||
NULL);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/*
|
/*
|
||||||
* If querystring is not "", then we have the case
|
* If query string is not "", then we have the case
|
||||||
* that the identifier parameter we removed was the
|
* that the identifier parameter we removed was the
|
||||||
* last one in the original querystring. Hence we have
|
* last one in the original query string. Hence we have
|
||||||
* a trailing '&' which needs to be removed.
|
* a trailing '&' which needs to be removed.
|
||||||
*/
|
*/
|
||||||
if (*querystring) {
|
if (dup) {
|
||||||
querystring[strlen(querystring) - 1] = '\0';
|
dup[strlen(dup) - 1] = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -644,15 +643,11 @@ static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Key format is a URI, optionally without the query-string */
|
/* Key format is a URI, optionally without the query-string (NULL
|
||||||
if (conf->ignorequerystring) {
|
* per above if conf->ignorequerystring)
|
||||||
*key = apr_pstrcat(p, scheme, "://", hostname, port_str, path, "?",
|
*/
|
||||||
NULL);
|
*key = apr_pstrcat(p, scheme, "://", hostname, port_str,
|
||||||
}
|
kpath, "?", kquery, NULL);
|
||||||
else {
|
|
||||||
*key = apr_pstrcat(p, scheme, "://", hostname, port_str, path, "?",
|
|
||||||
querystring, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Store the key in the request_config for the cache as r->parsed_uri
|
* Store the key in the request_config for the cache as r->parsed_uri
|
||||||
@ -662,20 +657,26 @@ static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p,
|
|||||||
* resource in the cache under a key where it is never found by the quick
|
* resource in the cache under a key where it is never found by the quick
|
||||||
* handler during following requests.
|
* handler during following requests.
|
||||||
*/
|
*/
|
||||||
ap_log_rerror(
|
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(00698)
|
||||||
APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(00698) "cache: Key for entity %s?%s is %s", uri, parsed_uri->query, *key);
|
"cache: Key for entity %s?%s is %s", path, query, *key);
|
||||||
|
|
||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_status_t cache_generate_key_default(request_rec *r, apr_pool_t* p,
|
apr_status_t cache_generate_key_default(request_rec *r, apr_pool_t* p,
|
||||||
const char **key)
|
const char **key)
|
||||||
{
|
{
|
||||||
/* We want the actual query-string, which may differ from
|
/* In early processing (quick-handler, forward proxy), we want the initial
|
||||||
* r->parsed_uri.query (immutable), so use "" (not NULL).
|
* query-string from r->parsed_uri, since any change before CACHE_SAVE
|
||||||
|
* shouldn't modify the key. Otherwise we want the actual query-string.
|
||||||
*/
|
*/
|
||||||
const char *args = r->args ? r->args : "";
|
const char *path = r->uri;
|
||||||
return cache_canonicalise_key(r, p, r->uri, args, &r->parsed_uri, key);
|
const char *query = r->args;
|
||||||
|
if (cache_use_early_url(r)) {
|
||||||
|
path = r->parsed_uri.path;
|
||||||
|
query = r->parsed_uri.query;
|
||||||
|
}
|
||||||
|
return cache_canonicalise_key(r, p, path, query, &r->parsed_uri, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -717,7 +718,8 @@ int cache_invalidate(cache_request_rec *cache, request_rec *r)
|
|||||||
if (location) {
|
if (location) {
|
||||||
if (apr_uri_parse(r->pool, location, &location_uri)
|
if (apr_uri_parse(r->pool, location, &location_uri)
|
||||||
|| cache_canonicalise_key(r, r->pool,
|
|| cache_canonicalise_key(r, r->pool,
|
||||||
location, NULL,
|
location_uri.path,
|
||||||
|
location_uri.query,
|
||||||
&location_uri, &location_key)
|
&location_uri, &location_key)
|
||||||
|| !(r->parsed_uri.hostname
|
|| !(r->parsed_uri.hostname
|
||||||
&& location_uri.hostname
|
&& location_uri.hostname
|
||||||
@ -732,7 +734,8 @@ int cache_invalidate(cache_request_rec *cache, request_rec *r)
|
|||||||
if (apr_uri_parse(r->pool, content_location,
|
if (apr_uri_parse(r->pool, content_location,
|
||||||
&content_location_uri)
|
&content_location_uri)
|
||||||
|| cache_canonicalise_key(r, r->pool,
|
|| cache_canonicalise_key(r, r->pool,
|
||||||
content_location, NULL,
|
content_location_uri.path,
|
||||||
|
content_location_uri.query,
|
||||||
&content_location_uri,
|
&content_location_uri,
|
||||||
&content_location_key)
|
&content_location_key)
|
||||||
|| !(r->parsed_uri.hostname
|
|| !(r->parsed_uri.hostname
|
||||||
|
33
modules/cache/cache_util.c
vendored
33
modules/cache/cache_util.c
vendored
@ -31,10 +31,8 @@ extern module AP_MODULE_DECLARE_DATA cache_module;
|
|||||||
* in "filter". All but the path comparisons are case-insensitive.
|
* in "filter". All but the path comparisons are case-insensitive.
|
||||||
*/
|
*/
|
||||||
static int uri_meets_conditions(const apr_uri_t *filter, const int pathlen,
|
static int uri_meets_conditions(const apr_uri_t *filter, const int pathlen,
|
||||||
request_rec *r)
|
const apr_uri_t *url, const char *path)
|
||||||
{
|
{
|
||||||
const apr_uri_t *url = &r->parsed_uri;
|
|
||||||
|
|
||||||
/* Scheme, hostname port and local part. The filter URI and the
|
/* Scheme, hostname port and local part. The filter URI and the
|
||||||
* URI we test may have the following shapes:
|
* URI we test may have the following shapes:
|
||||||
* /<path>
|
* /<path>
|
||||||
@ -114,7 +112,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
|
/* For HTTP caching purposes, an empty (NULL) path is equivalent to
|
||||||
* a single "/" path. RFCs 3986/2396
|
* a single "/" path. RFCs 3986/2396
|
||||||
*/
|
*/
|
||||||
if (!r->uri) {
|
if (!path) {
|
||||||
if (*filter->path == '/' && pathlen == 1) {
|
if (*filter->path == '/' && pathlen == 1) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -126,7 +124,23 @@ static int uri_meets_conditions(const apr_uri_t *filter, const int pathlen,
|
|||||||
/* Url has met all of the filter conditions so far, determine
|
/* Url has met all of the filter conditions so far, determine
|
||||||
* if the paths match.
|
* if the paths match.
|
||||||
*/
|
*/
|
||||||
return !strncmp(filter->path, r->uri, pathlen);
|
return !strncmp(filter->path, path, pathlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cache_use_early_url(request_rec *r)
|
||||||
|
{
|
||||||
|
cache_server_conf *conf;
|
||||||
|
|
||||||
|
if (r->proxyreq == PROXYREQ_PROXY) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
conf = ap_get_module_config(r->server->module_config, &cache_module);
|
||||||
|
if (conf->quick) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static cache_provider_list *get_provider(request_rec *r, struct cache_enable *ent,
|
static cache_provider_list *get_provider(request_rec *r, struct cache_enable *ent,
|
||||||
@ -172,6 +186,7 @@ cache_provider_list *cache_get_providers(request_rec *r,
|
|||||||
{
|
{
|
||||||
cache_dir_conf *dconf = ap_get_module_config(r->per_dir_config, &cache_module);
|
cache_dir_conf *dconf = ap_get_module_config(r->per_dir_config, &cache_module);
|
||||||
cache_provider_list *providers = NULL;
|
cache_provider_list *providers = NULL;
|
||||||
|
const char *path;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* per directory cache disable */
|
/* per directory cache disable */
|
||||||
@ -179,11 +194,14 @@ cache_provider_list *cache_get_providers(request_rec *r,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
path = cache_use_early_url(r) ? r->parsed_uri.path : r->uri;
|
||||||
|
|
||||||
/* global cache disable */
|
/* global cache disable */
|
||||||
for (i = 0; i < conf->cachedisable->nelts; i++) {
|
for (i = 0; i < conf->cachedisable->nelts; i++) {
|
||||||
struct cache_disable *ent =
|
struct cache_disable *ent =
|
||||||
(struct cache_disable *)conf->cachedisable->elts;
|
(struct cache_disable *)conf->cachedisable->elts;
|
||||||
if (uri_meets_conditions(&ent[i].url, ent[i].pathlen, r)) {
|
if (uri_meets_conditions(&ent[i].url, ent[i].pathlen,
|
||||||
|
&r->parsed_uri, path)) {
|
||||||
/* Stop searching now. */
|
/* Stop searching now. */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -200,7 +218,8 @@ cache_provider_list *cache_get_providers(request_rec *r,
|
|||||||
for (i = 0; i < conf->cacheenable->nelts; i++) {
|
for (i = 0; i < conf->cacheenable->nelts; i++) {
|
||||||
struct cache_enable *ent =
|
struct cache_enable *ent =
|
||||||
(struct cache_enable *)conf->cacheenable->elts;
|
(struct cache_enable *)conf->cacheenable->elts;
|
||||||
if (uri_meets_conditions(&ent[i].url, ent[i].pathlen, r)) {
|
if (uri_meets_conditions(&ent[i].url, ent[i].pathlen,
|
||||||
|
&r->parsed_uri, path)) {
|
||||||
providers = get_provider(r, &ent[i], providers);
|
providers = get_provider(r, &ent[i], providers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
6
modules/cache/cache_util.h
vendored
6
modules/cache/cache_util.h
vendored
@ -327,6 +327,12 @@ char *cache_strqtok(char *str, const char *sep, char **last);
|
|||||||
*/
|
*/
|
||||||
apr_table_t *cache_merge_headers_out(request_rec *r);
|
apr_table_t *cache_merge_headers_out(request_rec *r);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether to use request's path/query from early stage (r->parsed_uri)
|
||||||
|
* or the current/rewritable ones (r->uri/r->args).
|
||||||
|
*/
|
||||||
|
int cache_use_early_url(request_rec *r);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
5
modules/cache/mod_cache.c
vendored
5
modules/cache/mod_cache.c
vendored
@ -823,6 +823,7 @@ static apr_status_t cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in)
|
|||||||
apr_pool_t *p;
|
apr_pool_t *p;
|
||||||
apr_bucket *e;
|
apr_bucket *e;
|
||||||
apr_table_t *headers;
|
apr_table_t *headers;
|
||||||
|
const char *query;
|
||||||
|
|
||||||
conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
|
conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
|
||||||
&cache_module);
|
&cache_module);
|
||||||
@ -927,6 +928,8 @@ static apr_status_t cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query = cache_use_early_url(r) ? r->parsed_uri.query : r->args;
|
||||||
|
|
||||||
/* read expiry date; if a bad date, then leave it so the client can
|
/* read expiry date; if a bad date, then leave it so the client can
|
||||||
* read it
|
* read it
|
||||||
*/
|
*/
|
||||||
@ -1057,7 +1060,7 @@ static apr_status_t cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in)
|
|||||||
reason
|
reason
|
||||||
= "s-maxage or max-age zero and no Last-Modified or Etag; not cacheable";
|
= "s-maxage or max-age zero and no Last-Modified or Etag; not cacheable";
|
||||||
}
|
}
|
||||||
else if (!conf->ignorequerystring && r->parsed_uri.query && exps == NULL
|
else if (!conf->ignorequerystring && query && exps == NULL
|
||||||
&& !control.max_age && !control.s_maxage) {
|
&& !control.max_age && !control.s_maxage) {
|
||||||
/* if a query string is present but no explicit expiration time,
|
/* if a query string is present but no explicit expiration time,
|
||||||
* don't cache it (RFC 2616/13.9 & 13.2.1)
|
* don't cache it (RFC 2616/13.9 & 13.2.1)
|
||||||
|
Reference in New Issue
Block a user