Mercurial > hg > nginx
comparison src/http/ngx_http_upstream.c @ 9295:c5623963c29e
Upstream: fixed proxy_no_cache when caching errors.
Caching errors, notably intercepted errors and internally generated
502/504 errors, as well as handling of cache revalidation with 304,
did not take into account u->conf->no_cache predicates configured.
As a result, an error might be cached even if configuration explicitly
says not to. Fix is to check u->conf->no_cache in these cases.
To simplify usage in multiple places, checking u->conf->no_cache is now
done in a separate function. As a minor optimization, u->conf->no_cache
is only checked if u->cacheable is set.
As a side effect, this change also fixes caching errors after
proxy_cache_bypass. Also, during cache revalidation u->cacheable is
now tested, so 304 responses which disable caching won't extend
cacheability of stored responses.
Additionally, when caching internally generated 502/504 errors
u->cacheable is now explicitly updated from u->headers_in.no_cache and
u->headers_in.expired, restoring the behaviour before 8041:0784ab86ad08
(1.23.0) when an error happens while reading the response headers.
Reported by Kirill A. Korinsky,
https://freenginx.org/pipermail/nginx/2024-April/000082.html
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Tue, 25 Jun 2024 21:44:50 +0300 |
parents | 5e7588d2d9cc |
children | 8cdab3d89c44 |
comparison
equal
deleted
inserted
replaced
9294:ea0eef2dd12c | 9295:c5623963c29e |
---|---|
18 static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r, | 18 static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r, |
19 ngx_http_upstream_t *u); | 19 ngx_http_upstream_t *u); |
20 static ngx_int_t ngx_http_upstream_cache_background_update( | 20 static ngx_int_t ngx_http_upstream_cache_background_update( |
21 ngx_http_request_t *r, ngx_http_upstream_t *u); | 21 ngx_http_request_t *r, ngx_http_upstream_t *u); |
22 static ngx_int_t ngx_http_upstream_cache_check_range(ngx_http_request_t *r, | 22 static ngx_int_t ngx_http_upstream_cache_check_range(ngx_http_request_t *r, |
23 ngx_http_upstream_t *u); | |
24 static ngx_int_t ngx_http_upstream_no_cache(ngx_http_request_t *r, | |
23 ngx_http_upstream_t *u); | 25 ngx_http_upstream_t *u); |
24 static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r, | 26 static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r, |
25 ngx_http_variable_value_t *v, uintptr_t data); | 27 ngx_http_variable_value_t *v, uintptr_t data); |
26 static ngx_int_t ngx_http_upstream_cache_key(ngx_http_request_t *r, | 28 static ngx_int_t ngx_http_upstream_cache_key(ngx_http_request_t *r, |
27 ngx_http_variable_value_t *v, uintptr_t data); | 29 ngx_http_variable_value_t *v, uintptr_t data); |
2630 | 2632 |
2631 valid = r->cache->valid_sec; | 2633 valid = r->cache->valid_sec; |
2632 updating = r->cache->updating_sec; | 2634 updating = r->cache->updating_sec; |
2633 error = r->cache->error_sec; | 2635 error = r->cache->error_sec; |
2634 | 2636 |
2637 if (ngx_http_upstream_no_cache(r, u) != NGX_OK) { | |
2638 ngx_http_upstream_finalize_request(r, u, | |
2639 NGX_HTTP_INTERNAL_SERVER_ERROR); | |
2640 return NGX_OK; | |
2641 } | |
2642 | |
2635 rc = u->reinit_request(r); | 2643 rc = u->reinit_request(r); |
2636 | 2644 |
2637 if (rc != NGX_OK) { | 2645 if (rc != NGX_OK) { |
2638 ngx_http_upstream_finalize_request(r, u, rc); | 2646 ngx_http_upstream_finalize_request(r, u, rc); |
2639 return NGX_OK; | 2647 return NGX_OK; |
2648 | 2656 |
2649 if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) { | 2657 if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) { |
2650 rc = NGX_HTTP_INTERNAL_SERVER_ERROR; | 2658 rc = NGX_HTTP_INTERNAL_SERVER_ERROR; |
2651 } | 2659 } |
2652 | 2660 |
2653 if (valid == 0) { | 2661 if (u->cacheable) { |
2654 valid = r->cache->valid_sec; | 2662 |
2655 updating = r->cache->updating_sec; | 2663 if (valid == 0) { |
2656 error = r->cache->error_sec; | 2664 valid = r->cache->valid_sec; |
2657 } | 2665 updating = r->cache->updating_sec; |
2658 | 2666 error = r->cache->error_sec; |
2659 if (valid == 0) { | 2667 } |
2660 valid = ngx_http_file_cache_valid(u->conf->cache_valid, | 2668 |
2661 u->headers_in.status_n); | 2669 if (valid == 0) { |
2670 valid = ngx_http_file_cache_valid(u->conf->cache_valid, | |
2671 u->headers_in.status_n); | |
2672 if (valid) { | |
2673 valid = now + valid; | |
2674 } | |
2675 } | |
2676 | |
2662 if (valid) { | 2677 if (valid) { |
2663 valid = now + valid; | 2678 r->cache->valid_sec = valid; |
2664 } | 2679 r->cache->updating_sec = updating; |
2665 } | 2680 r->cache->error_sec = error; |
2666 | 2681 |
2667 if (valid) { | 2682 r->cache->date = now; |
2668 r->cache->valid_sec = valid; | 2683 |
2669 r->cache->updating_sec = updating; | 2684 ngx_http_file_cache_update_header(r); |
2670 r->cache->error_sec = error; | 2685 } |
2671 | |
2672 r->cache->date = now; | |
2673 | |
2674 ngx_http_file_cache_update_header(r); | |
2675 } | 2686 } |
2676 | 2687 |
2677 ngx_http_upstream_finalize_request(r, u, rc); | 2688 ngx_http_upstream_finalize_request(r, u, rc); |
2678 return NGX_OK; | 2689 return NGX_OK; |
2679 } | 2690 } |
2743 | 2754 |
2744 #if (NGX_HTTP_CACHE) | 2755 #if (NGX_HTTP_CACHE) |
2745 | 2756 |
2746 if (r->cache) { | 2757 if (r->cache) { |
2747 | 2758 |
2748 if (u->headers_in.no_cache || u->headers_in.expired) { | 2759 if (ngx_http_upstream_no_cache(r, u) != NGX_OK) { |
2749 u->cacheable = 0; | 2760 ngx_http_upstream_finalize_request(r, u, |
2761 NGX_HTTP_INTERNAL_SERVER_ERROR); | |
2762 return NGX_OK; | |
2750 } | 2763 } |
2751 | 2764 |
2752 if (u->cacheable) { | 2765 if (u->cacheable) { |
2753 time_t valid; | 2766 time_t valid; |
2754 | 2767 |
3157 if (r->cache && r->cache->file.fd != NGX_INVALID_FILE) { | 3170 if (r->cache && r->cache->file.fd != NGX_INVALID_FILE) { |
3158 ngx_pool_run_cleanup_file(r->pool, r->cache->file.fd); | 3171 ngx_pool_run_cleanup_file(r->pool, r->cache->file.fd); |
3159 r->cache->file.fd = NGX_INVALID_FILE; | 3172 r->cache->file.fd = NGX_INVALID_FILE; |
3160 } | 3173 } |
3161 | 3174 |
3162 switch (ngx_http_test_predicates(r, u->conf->no_cache)) { | 3175 if (ngx_http_upstream_no_cache(r, u) != NGX_OK) { |
3163 | |
3164 case NGX_ERROR: | |
3165 ngx_http_upstream_finalize_request(r, u, NGX_ERROR); | 3176 ngx_http_upstream_finalize_request(r, u, NGX_ERROR); |
3166 return; | |
3167 | |
3168 case NGX_DECLINED: | |
3169 u->cacheable = 0; | |
3170 break; | |
3171 | |
3172 default: /* NGX_OK */ | |
3173 | |
3174 if (u->cache_status == NGX_HTTP_CACHE_BYPASS) { | |
3175 | |
3176 /* create cache if previously bypassed */ | |
3177 | |
3178 if (ngx_http_file_cache_create(r) != NGX_OK) { | |
3179 ngx_http_upstream_finalize_request(r, u, NGX_ERROR); | |
3180 return; | |
3181 } | |
3182 } | |
3183 | |
3184 break; | |
3185 } | 3177 } |
3186 | 3178 |
3187 if (u->cacheable) { | 3179 if (u->cacheable) { |
3188 time_t now, valid; | 3180 time_t now, valid; |
3189 | 3181 |
3370 | 3362 |
3371 ngx_http_upstream_process_upstream(r, u); | 3363 ngx_http_upstream_process_upstream(r, u); |
3372 } | 3364 } |
3373 | 3365 |
3374 | 3366 |
3367 #if (NGX_HTTP_CACHE) | |
3368 | |
3369 static ngx_int_t | |
3370 ngx_http_upstream_no_cache(ngx_http_request_t *r, ngx_http_upstream_t *u) | |
3371 { | |
3372 ngx_int_t rc; | |
3373 | |
3374 if (!u->cacheable) { | |
3375 return NGX_OK; | |
3376 } | |
3377 | |
3378 if (u->headers_in.no_cache || u->headers_in.expired) { | |
3379 u->cacheable = 0; | |
3380 return NGX_OK; | |
3381 } | |
3382 | |
3383 rc = ngx_http_test_predicates(r, u->conf->no_cache); | |
3384 | |
3385 if (rc == NGX_ERROR) { | |
3386 return NGX_ERROR; | |
3387 } | |
3388 | |
3389 if (rc == NGX_DECLINED) { | |
3390 u->cacheable = 0; | |
3391 return NGX_OK; | |
3392 } | |
3393 | |
3394 /* rc == NGX_OK */ | |
3395 | |
3396 if (u->cache_status == NGX_HTTP_CACHE_BYPASS) { | |
3397 | |
3398 /* create cache if previously bypassed */ | |
3399 | |
3400 if (ngx_http_file_cache_create(r) != NGX_OK) { | |
3401 return NGX_ERROR; | |
3402 } | |
3403 } | |
3404 | |
3405 return NGX_OK; | |
3406 } | |
3407 | |
3408 #endif | |
3409 | |
3410 | |
3375 static void | 3411 static void |
3376 ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u) | 3412 ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u) |
3377 { | 3413 { |
3378 ngx_connection_t *c; | 3414 ngx_connection_t *c; |
3379 ngx_http_core_loc_conf_t *clcf; | 3415 ngx_http_core_loc_conf_t *clcf; |
4617 | 4653 |
4618 #if (NGX_HTTP_CACHE) | 4654 #if (NGX_HTTP_CACHE) |
4619 | 4655 |
4620 if (r->cache) { | 4656 if (r->cache) { |
4621 | 4657 |
4622 if (u->cacheable) { | 4658 if (rc == NGX_HTTP_BAD_GATEWAY || rc == NGX_HTTP_GATEWAY_TIME_OUT) { |
4623 | 4659 |
4624 if (rc == NGX_HTTP_BAD_GATEWAY || rc == NGX_HTTP_GATEWAY_TIME_OUT) { | 4660 if (!u->header_sent) { |
4661 if (ngx_http_upstream_no_cache(r, u) != NGX_OK) { | |
4662 u->cacheable = 0; | |
4663 } | |
4664 } | |
4665 | |
4666 if (u->cacheable) { | |
4625 time_t valid; | 4667 time_t valid; |
4626 | 4668 |
4627 valid = ngx_http_file_cache_valid(u->conf->cache_valid, rc); | 4669 valid = ngx_http_file_cache_valid(u->conf->cache_valid, rc); |
4628 | 4670 |
4629 if (valid) { | 4671 if (valid) { |