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
This commit is contained in:
Smeet23 2026-06-02 13:30:06 +05:30
parent d3a76322cf
commit ab079c72bc
2 changed files with 30 additions and 0 deletions

View file

@ -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;

View file

@ -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;