comparison src/http/ngx_http_upstream.c @ 9217:6765e5f6d991

Upstream: fixed X-Accel-Redirect handling from cache files. The X-Accel-Redirect header might appear in cache files if its handling is ignored with the "proxy_ignore_headers" directive. If the cache file is later served with different settings, ngx_http_upstream_process_headers() used to call ngx_http_upstream_finalize_request(NGX_DECLINED), which is not expected to happen before the cleanup handler is installed and resulted in ngx_http_finalize_request(NGX_DONE) (after 5994:5abf5af257a7, nginx 1.7.11), leading to unexpected request counter decrement, "request count is zero" alerts, and segmentation faults. Similarly, errors in ngx_http_upstream_process_headers() resulted in ngx_http_upstream_finalize_request(NGX_HTTP_INTERNAL_SERVER_ERROR) being called. This is also not expected to happen before the cleanup handler is installed, and resulted in ngx_http_finalize_request(NGX_DONE) without proper request finalization. Fix is to avoid calling ngx_http_upstream_finalize_request() from ngx_http_upstream_process_headers(), notably when the cleanup handler is not yet installed. Errors are now simply return NGX_ERROR, so the caller is responsible for proper finalization by calling either ngx_http_finalize_request() or ngx_http_upstream_finalize_request(). And X-Accel-Redirect handling now does not call ngx_http_upstream_finalize_request(NGX_DECLINED) if no cleanup handler is installed. Reported by Jiří Setnička (https://mailman.nginx.org/pipermail/nginx-devel/2024-February/HWLYHOO3DDB3XTFT6X3GRMXIEJ3SJRUA.html).
author Maxim Dounin <mdounin@mdounin.ru>
date Tue, 20 Feb 2024 01:23:43 +0300
parents 631ee3c6d38c
children 41db21d1ca7c
comparison
equal deleted inserted replaced
9216:de20142f5046 9217:6765e5f6d991
1085 1085
1086 rc = u->process_header(r); 1086 rc = u->process_header(r);
1087 1087
1088 if (rc == NGX_OK) { 1088 if (rc == NGX_OK) {
1089 1089
1090 if (ngx_http_upstream_process_headers(r, u) != NGX_OK) { 1090 rc = ngx_http_upstream_process_headers(r, u);
1091 return NGX_DONE; 1091
1092 if (rc != NGX_OK) {
1093 return rc;
1092 } 1094 }
1093 1095
1094 return ngx_http_cache_send(r); 1096 return ngx_http_cache_send(r);
1095 } 1097 }
1096 1098
2514 if (ngx_http_upstream_intercept_errors(r, u) == NGX_OK) { 2516 if (ngx_http_upstream_intercept_errors(r, u) == NGX_OK) {
2515 return; 2517 return;
2516 } 2518 }
2517 } 2519 }
2518 2520
2519 if (ngx_http_upstream_process_headers(r, u) != NGX_OK) { 2521 rc = ngx_http_upstream_process_headers(r, u);
2522
2523 if (rc == NGX_DONE) {
2524 return;
2525 }
2526
2527 if (rc == NGX_ERROR) {
2528 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2520 return; 2529 return;
2521 } 2530 }
2522 2531
2523 ngx_http_upstream_send_response(r, u); 2532 ngx_http_upstream_send_response(r, u);
2524 } 2533 }
2827 } 2836 }
2828 2837
2829 if (u->headers_in.x_accel_redirect 2838 if (u->headers_in.x_accel_redirect
2830 && !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT)) 2839 && !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT))
2831 { 2840 {
2832 ngx_http_upstream_finalize_request(r, u, NGX_DECLINED); 2841 if (u->cleanup) {
2842 ngx_http_upstream_finalize_request(r, u, NGX_DECLINED);
2843 }
2833 2844
2834 part = &u->headers_in.headers.part; 2845 part = &u->headers_in.headers.part;
2835 h = part->elts; 2846 h = part->elts;
2836 2847
2837 for (i = 0; /* void */; i++) { 2848 for (i = 0; /* void */; i++) {
2916 hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash, 2927 hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
2917 h[i].lowcase_key, h[i].key.len); 2928 h[i].lowcase_key, h[i].key.len);
2918 2929
2919 if (hh) { 2930 if (hh) {
2920 if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) { 2931 if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
2921 ngx_http_upstream_finalize_request(r, u, 2932 return NGX_ERROR;
2922 NGX_HTTP_INTERNAL_SERVER_ERROR);
2923 return NGX_DONE;
2924 } 2933 }
2925 2934
2926 continue; 2935 continue;
2927 } 2936 }
2928 2937
2929 if (ngx_http_upstream_copy_header_line(r, &h[i], 0) != NGX_OK) { 2938 if (ngx_http_upstream_copy_header_line(r, &h[i], 0) != NGX_OK) {
2930 ngx_http_upstream_finalize_request(r, u, 2939 return NGX_ERROR;
2931 NGX_HTTP_INTERNAL_SERVER_ERROR);
2932 return NGX_DONE;
2933 } 2940 }
2934 } 2941 }
2935 2942
2936 if (r->headers_out.server && r->headers_out.server->value.data == NULL) { 2943 if (r->headers_out.server && r->headers_out.server->value.data == NULL) {
2937 r->headers_out.server->hash = 0; 2944 r->headers_out.server->hash = 0;