mirror of
https://github.com/nginx/nginx.git
synced 2025-07-25 06:37:58 +08:00
Upstream: fixed X-Accel-Expires/Cache-Control/Expires handling.
Previously, if caching was disabled due to Expires in the past, nginx failed to cache the response even if it was cacheable as per subsequently parsed Cache-Control header (ticket #964). Similarly, if caching was disabled due to Expires in the past, "Cache-Control: no-cache" or "Cache-Control: max-age=0", caching was not used if it was cacheable as per subsequently parsed X-Accel-Expires header. Fix is to avoid disabling caching immediately after parsing Expires in the past or Cache-Control, but rather set flags which are later checked by ngx_http_upstream_process_headers() (and cleared by "Cache-Control: max-age" and X-Accel-Expires). Additionally, now X-Accel-Expires does not prevent parsing of cache control extensions, notably stale-while-revalidate and stale-if-error. This ensures that order of the X-Accel-Expires and Cache-Control headers is not important. Prodded by Vadim Fedorenko and Yugo Horie.
This commit is contained in:
parent
bfc5b35827
commit
8df3ad13c5
@ -2702,6 +2702,10 @@ ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
|
|||||||
|
|
||||||
if (r->cache) {
|
if (r->cache) {
|
||||||
|
|
||||||
|
if (u->headers_in.no_cache || u->headers_in.expired) {
|
||||||
|
u->cacheable = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (u->cacheable) {
|
if (u->cacheable) {
|
||||||
time_t valid;
|
time_t valid;
|
||||||
|
|
||||||
@ -2796,6 +2800,10 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
|
|||||||
|
|
||||||
umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
|
umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
|
||||||
|
|
||||||
|
if (u->headers_in.no_cache || u->headers_in.expired) {
|
||||||
|
u->cacheable = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (u->headers_in.x_accel_redirect
|
if (u->headers_in.x_accel_redirect
|
||||||
&& !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT))
|
&& !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT))
|
||||||
{
|
{
|
||||||
@ -4791,18 +4799,18 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
|
|||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r->cache->valid_sec != 0 && u->headers_in.x_accel_expires != NULL) {
|
|
||||||
return NGX_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
start = h->value.data;
|
start = h->value.data;
|
||||||
last = start + h->value.len;
|
last = start + h->value.len;
|
||||||
|
|
||||||
|
if (r->cache->valid_sec != 0 && u->headers_in.x_accel_expires != NULL) {
|
||||||
|
goto extensions;
|
||||||
|
}
|
||||||
|
|
||||||
if (ngx_strlcasestrn(start, last, (u_char *) "no-cache", 8 - 1) != NULL
|
if (ngx_strlcasestrn(start, last, (u_char *) "no-cache", 8 - 1) != NULL
|
||||||
|| ngx_strlcasestrn(start, last, (u_char *) "no-store", 8 - 1) != NULL
|
|| ngx_strlcasestrn(start, last, (u_char *) "no-store", 8 - 1) != NULL
|
||||||
|| ngx_strlcasestrn(start, last, (u_char *) "private", 7 - 1) != NULL)
|
|| ngx_strlcasestrn(start, last, (u_char *) "private", 7 - 1) != NULL)
|
||||||
{
|
{
|
||||||
u->cacheable = 0;
|
u->headers_in.no_cache = 1;
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4832,13 +4840,16 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
u->cacheable = 0;
|
u->headers_in.no_cache = 1;
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
r->cache->valid_sec = ngx_time() + n;
|
r->cache->valid_sec = ngx_time() + n;
|
||||||
|
u->headers_in.expired = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extensions:
|
||||||
|
|
||||||
p = ngx_strlcasestrn(start, last, (u_char *) "stale-while-revalidate=",
|
p = ngx_strlcasestrn(start, last, (u_char *) "stale-while-revalidate=",
|
||||||
23 - 1);
|
23 - 1);
|
||||||
|
|
||||||
@ -4932,7 +4943,7 @@ ngx_http_upstream_process_expires(ngx_http_request_t *r, ngx_table_elt_t *h,
|
|||||||
expires = ngx_parse_http_time(h->value.data, h->value.len);
|
expires = ngx_parse_http_time(h->value.data, h->value.len);
|
||||||
|
|
||||||
if (expires == NGX_ERROR || expires < ngx_time()) {
|
if (expires == NGX_ERROR || expires < ngx_time()) {
|
||||||
u->cacheable = 0;
|
u->headers_in.expired = 1;
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4996,6 +5007,8 @@ ngx_http_upstream_process_accel_expires(ngx_http_request_t *r,
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
r->cache->valid_sec = ngx_time() + n;
|
r->cache->valid_sec = ngx_time() + n;
|
||||||
|
u->headers_in.no_cache = 0;
|
||||||
|
u->headers_in.expired = 0;
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5007,6 +5020,8 @@ ngx_http_upstream_process_accel_expires(ngx_http_request_t *r,
|
|||||||
|
|
||||||
if (n != NGX_ERROR) {
|
if (n != NGX_ERROR) {
|
||||||
r->cache->valid_sec = n;
|
r->cache->valid_sec = n;
|
||||||
|
u->headers_in.no_cache = 0;
|
||||||
|
u->headers_in.expired = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -293,6 +293,8 @@ typedef struct {
|
|||||||
|
|
||||||
unsigned connection_close:1;
|
unsigned connection_close:1;
|
||||||
unsigned chunked:1;
|
unsigned chunked:1;
|
||||||
|
unsigned no_cache:1;
|
||||||
|
unsigned expired:1;
|
||||||
} ngx_http_upstream_headers_in_t;
|
} ngx_http_upstream_headers_in_t;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user