Mercurial > hg > nginx
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; |