From b9ff619c79fa42a87ebf4d74ad9d581df363591d Mon Sep 17 00:00:00 2001 From: srujan-rai Date: Sun, 17 May 2026 01:19:53 +0530 Subject: [PATCH] HTTP: fix error_page handling for 413 with HTTP/2 and HTTP/3 When client_max_body_size is exceeded, ngx_http_discard_request_body() is called to signal body discarding. For HTTP/2 it set stream->skip_data but left r->discard_body unset; for HTTP/3 it returned immediately without setting any discard flag. The phase handler in ngx_http_core_find_config_phase() checks !r->discard_body to avoid re-evaluating the body size limit during subsequent internal redirects. Since the flag was never set for HTTP/2 and HTTP/3, the check triggered again during the error_page redirect, detected r->error_page already set, and fell back to the built-in 413 response instead of serving the configured custom page. Fix by setting r->discard_body = 1 in the HTTP/2 and HTTP/3 paths of ngx_http_discard_request_body(), matching existing HTTP/1 behaviour. Since r->discard_body may now be set for HTTP/2 and HTTP/3 requests, guard ngx_http_set_write_handler() to always use ngx_http_test_reading() for these protocols. The HTTP/1-specific ngx_http_discarded_request_body_handler() must not be used there: HTTP/2 fake connections share the real socket recv handler, while HTTP/3 would incorrectly invoke QUIC stream recv callbacks. Fixes #1356 --- src/http/ngx_http_request.c | 12 +++++++++--- src/http/ngx_http_request_body.c | 2 ++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index a5cd44dcc..7b77770fc 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -3008,9 +3008,15 @@ ngx_http_set_write_handler(ngx_http_request_t *r) r->http_state = NGX_HTTP_WRITING_REQUEST_STATE; - r->read_event_handler = r->discard_body ? - ngx_http_discarded_request_body_handler: - ngx_http_test_reading; + r->read_event_handler = +#if (NGX_HTTP_V2) + r->stream ? ngx_http_test_reading : +#endif +#if (NGX_HTTP_V3) + r->connection->quic ? ngx_http_test_reading : +#endif + r->discard_body ? ngx_http_discarded_request_body_handler : + ngx_http_test_reading; r->write_event_handler = ngx_http_writer; wev = r->connection->write; diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c index 1d8e4081a..9c26d5211 100644 --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -642,12 +642,14 @@ ngx_http_discard_request_body(ngx_http_request_t *r) #if (NGX_HTTP_V2) if (r->stream) { r->stream->skip_data = 1; + r->discard_body = 1; return NGX_OK; } #endif #if (NGX_HTTP_V3) if (r->http_version == NGX_HTTP_VERSION_30) { + r->discard_body = 1; return NGX_OK; } #endif