# HG changeset patch # User Maxim Dounin # Date 1714231327 -10800 # Node ID ac5635650bc6d3bff1414a65eaa22be266a778b3 # Parent 81082b5521ddb55a55028468544d30283bc198d7 Request body: handling of body after unbuffered reading. As long as unbuffered reading of the request body was used, and an attempt to read the request body is made again, such as when redirecting the request to an error page, the request body is now cleared to make sure it can be used safely. Further, the r->reading_body flag, if it is still set, is cleared (along with disabling keepalive and enabling lingering close), so the code which uses the request body, such as when proxying, is not confused and doesn't try to use "Transfer-Encoding: chunked". Note that this change makes the workaround for HTTP/2 issues with unbuffered proxying and error pages, as introduced in 7561:9f1f9d6e056a, ineffective (since r->reading_body now cleared along with r->reading_body_no_buffering). Though the workaround is anyway not needed after 7924:d9e009b39596, hence it is removed. This makes it safer to use complex processing of error pages with unbuffered proxying. diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -305,6 +305,7 @@ typedef struct { ngx_chain_t *busy; ngx_http_chunked_t *chunked; ngx_http_client_body_handler_pt post_handler; + unsigned no_buffering:1; unsigned filter_need_buffering:1; unsigned last_sent:1; unsigned last_saved:1; 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 @@ -44,6 +44,18 @@ ngx_http_read_client_request_body(ngx_ht if (r != r->main || r->request_body || r->discard_body) { r->request_body_no_buffering = 0; + + if (r->request_body && r->request_body->no_buffering) { + r->headers_in.content_length_n = 0; + r->request_body->bufs = NULL; + + if (r->reading_body) { + r->reading_body = 0; + r->keepalive = 0; + r->lingering_close = 1; + } + } + post_handler(r); return NGX_OK; } @@ -72,6 +84,7 @@ ngx_http_read_client_request_body(ngx_ht * rb->busy = NULL; * rb->chunked = NULL; * rb->received = 0; + * rb->no_buffering = 0; * rb->filter_need_buffering = 0; * rb->last_sent = 0; * rb->last_saved = 0; @@ -220,6 +233,7 @@ done: } else { /* rc == NGX_AGAIN */ r->reading_body = 1; + r->request_body->no_buffering = 1; } r->read_event_handler = ngx_http_block_reading; 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 @@ -1078,13 +1078,6 @@ ngx_http_v2_state_read_data(ngx_http_v2_ r = stream->request; fc = r->connection; - if (r->reading_body && !r->request_body_no_buffering) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "skipping http2 DATA frame"); - - return ngx_http_v2_state_skip_padded(h2c, pos, end); - } - if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, "skipping http2 DATA frame");