From ab079c72bc270857c44cdf76d62c94e2f99b84be Mon Sep 17 00:00:00 2001 From: Smeet23 Date: Tue, 2 Jun 2026 13:30:06 +0530 Subject: [PATCH] HTTP/2, HTTP/3: fix error_page for 413 Request Entity Too Large. When a request body exceeds client_max_body_size with a Content-Length header, the size violation is normally caught in the find config phase before any body is read. For HTTP/2 and HTTP/3, however, the error propagated through ngx_http_finalize_connection(), which immediately calls ngx_http_close_request() without the lingering-close logic used for HTTP/1.x. If the error_page 413 redirect queued a response but no frames had yet been written (stream->queued == 0, stream->out_closed == 0), ngx_http_v2_close_stream() would send RST_STREAM before the response reached the client, so the custom error page was never delivered. The fix adds an early client_max_body_size check at the entry of ngx_http_v2_read_request_body() and ngx_http_v3_read_request_body(), mirroring the HTTP/1.x check in ngx_http_core_find_config_phase(). Returning NGX_HTTP_REQUEST_ENTITY_TOO_LARGE before any stream or body state is modified lets the error propagate back through ngx_http_read_client_request_body() to the content handler, which calls ngx_http_finalize_request() while r->count is still elevated. The stream therefore defers its close until queued frames are flushed, giving the error_page response time to reach the client. Closes: https://github.com/nginx/nginx/issues/1356 --- src/http/v2/ngx_http_v2.c | 15 +++++++++++++++ src/http/v3/ngx_http_v3_request.c | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 336718bad..760353cb0 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -3956,6 +3956,21 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r) ngx_http_core_loc_conf_t *clcf; ngx_http_v2_connection_t *h2c; + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (r->headers_in.content_length_n != -1 + && !r->discard_body + && clcf->client_max_body_size + && clcf->client_max_body_size < r->headers_in.content_length_n) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "client intended to send too large body: %O bytes", + r->headers_in.content_length_n); + + r->expect_tested = 1; + return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; + } + stream = r->stream; rb = r->request_body; diff --git a/src/http/v3/ngx_http_v3_request.c b/src/http/v3/ngx_http_v3_request.c index 3b0fdbe98..d85f1275a 100644 --- a/src/http/v3/ngx_http_v3_request.c +++ b/src/http/v3/ngx_http_v3_request.c @@ -1284,6 +1284,21 @@ ngx_http_v3_read_request_body(ngx_http_request_t *r) ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (r->headers_in.content_length_n != -1 + && !r->discard_body + && clcf->client_max_body_size + && clcf->client_max_body_size < r->headers_in.content_length_n) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "client intended to send too large body: %O bytes", + r->headers_in.content_length_n); + + r->expect_tested = 1; + return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; + } + rb = r->request_body; preread = r->header_in->last - r->header_in->pos;