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) {