# HG changeset patch # User Maxim Dounin # Date 1714231298 -10800 # Node ID 81082b5521ddb55a55028468544d30283bc198d7 # Parent c9550e77186caecff6ae146dedd216fc9558652b Request body: body is now cleared on errors. Previously, after errors the request body was left in a potentially inconsistent state, with r->headers_in.content_length_n which might be larger than buffers actually stored in r->request_body->bufs (or not set at all, in case of HTTP/2 and HTTP/3). This can cause issues if the request body is subsequently used during error_page handling, such as when proxying. Fix is to clear r->request_body->bufs if this happens, and set r->headers_in.content_length_n to 0, much like it happens when ngx_http_discard_request_body() is called when returning 413 from ngx_http_core_find_config_phase() for requests with Content-Length. diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -228,6 +228,11 @@ done: } if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + + r->lingering_close = 1; + r->headers_in.content_length_n = 0; + r->request_body->bufs = NULL; + r->main->count--; r->read_event_handler = ngx_http_block_reading; } @@ -298,6 +303,11 @@ ngx_http_read_client_request_body_handle rc = ngx_http_do_read_client_request_body(r); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + + r->lingering_close = 1; + r->headers_in.content_length_n = 0; + r->request_body->bufs = NULL; + r->read_event_handler = ngx_http_block_reading; ngx_http_finalize_request(r, rc); } @@ -1161,8 +1171,6 @@ ngx_http_request_body_chunked_filter(ngx ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent too many chunk extensions"); - r->lingering_close = 1; - return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; } @@ -1176,8 +1184,6 @@ ngx_http_request_body_chunked_filter(ngx r->headers_in.content_length_n, rb->chunked->size); - r->lingering_close = 1; - return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; } @@ -1276,8 +1282,6 @@ ngx_http_request_body_chunked_filter(ngx "client sent too many chunk extensions " "or trailer headers"); - r->lingering_close = 1; - return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; } diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -1106,7 +1106,11 @@ ngx_http_v2_state_read_data(ngx_http_v2_ stream->in_closed, 0); if (rc != NGX_OK && rc != NGX_AGAIN) { + stream->skip_data = 1; + r->headers_in.content_length_n = 0; + r->request_body->bufs = NULL; + ngx_http_finalize_request(r, rc); } @@ -3768,6 +3772,7 @@ ngx_http_v2_run_request(ngx_http_request "client prematurely closed stream"); r->stream->skip_data = 1; + r->headers_in.content_length_n = 0; ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); goto failed; @@ -4199,7 +4204,11 @@ ngx_http_v2_read_client_request_body_han rc = ngx_http_v2_process_request_body(r, NULL, 0, r->stream->in_closed, 1); if (rc != NGX_OK && rc != NGX_AGAIN) { + r->stream->skip_data = 1; + r->headers_in.content_length_n = 0; + r->request_body->bufs = NULL; + ngx_http_finalize_request(r, rc); return; } @@ -4262,6 +4271,8 @@ ngx_http_v2_read_client_request_body_han error: stream->skip_data = 1; + r->headers_in.content_length_n = 0; + r->request_body->bufs = NULL; ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; diff --git a/src/http/v3/ngx_http_v3_request.c b/src/http/v3/ngx_http_v3_request.c --- a/src/http/v3/ngx_http_v3_request.c +++ b/src/http/v3/ngx_http_v3_request.c @@ -1291,6 +1291,10 @@ ngx_http_v3_read_client_request_body_han rc = ngx_http_v3_do_read_client_request_body(r); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + + r->headers_in.content_length_n = 0; + r->request_body->bufs = NULL; + ngx_http_finalize_request(r, rc); } }