[PATCH 4 of 4] HTTP/2: support for unbuffered upload of request body
Valentin V. Bartenev
vbart at nginx.com
Fri Feb 26 15:45:59 UTC 2016
src/http/ngx_http_request_body.c | 7 +-
src/http/v2/ngx_http_v2.c | 132 +++++++++++++++++++++++++++++++++++++-
src/http/v2/ngx_http_v2.h | 1 +
3 files changed, 134 insertions(+), 6 deletions(-)
# HG changeset patch
# User Valentin Bartenev <vbart at nginx.com>
# Date 1456500171 -10800
# Fri Feb 26 18:22:51 2016 +0300
# Node ID d0745c528544d1297ba11cc8d3660929a2bce557
# Parent 8933cfd2fb603a65f5ed8b49922abc9b03840375
HTTP/2: support for unbuffered upload of request body.
diff -r 8933cfd2fb60 -r d0745c528544 src/http/ngx_http_request_body.c
--- a/src/http/ngx_http_request_body.c Fri Feb 26 18:22:26 2016 +0300
+++ b/src/http/ngx_http_request_body.c Fri Feb 26 18:22:51 2016 +0300
@@ -48,7 +48,6 @@ ngx_http_read_client_request_body(ngx_ht
#if (NGX_HTTP_V2)
if (r->stream) {
- r->request_body_no_buffering = 0;
rc = ngx_http_v2_read_request_body(r, post_handler);
goto done;
}
@@ -215,6 +214,12 @@ ngx_http_read_unbuffered_request_body(ng
{
ngx_int_t rc;
+#if (NGX_HTTP_V2)
+ if (r->stream) {
+ return ngx_http_v2_read_unbuffered_request_body(r);
+ }
+#endif
+
if (r->connection->read->timedout) {
r->connection->timedout = 1;
return NGX_HTTP_REQUEST_TIME_OUT;
diff -r 8933cfd2fb60 -r d0745c528544 src/http/v2/ngx_http_v2.c
--- a/src/http/v2/ngx_http_v2.c Fri Feb 26 18:22:26 2016 +0300
+++ b/src/http/v2/ngx_http_v2.c Fri Feb 26 18:22:51 2016 +0300
@@ -3403,6 +3403,8 @@ ngx_http_v2_run_request(ngx_http_request
return;
}
+ r->headers_in.chunked = (r->headers_in.content_length_n == -1);
+
ngx_http_process_request(r);
}
@@ -3449,6 +3451,14 @@ ngx_http_v2_read_request_body(ngx_http_r
len = 0;
}
+ if (r->request_body_no_buffering) {
+ r->request_body_in_file_only = 0;
+
+ if (len < 0 || len > (off_t) clcf->client_body_buffer_size) {
+ len = clcf->client_body_buffer_size;
+ }
+ }
+
if (len != 0) {
if (len < 0
|| len > (off_t) clcf->client_body_buffer_size
@@ -3471,10 +3481,15 @@ ngx_http_v2_read_request_body(ngx_http_r
}
if (stream->in_closed) {
+ r->request_body_no_buffering = 0;
return ngx_http_v2_process_request_body(r, NULL, 0, 1);
}
- stream->recv_window = NGX_HTTP_V2_MAX_WINDOW;
+ rb->rest = 1;
+
+ stream->recv_window = r->request_body_no_buffering
+ ? clcf->client_body_buffer_size
+ : NGX_HTTP_V2_MAX_WINDOW;
if (ngx_http_v2_send_window_update(stream->connection, stream->node->id,
stream->recv_window)
@@ -3483,7 +3498,7 @@ ngx_http_v2_read_request_body(ngx_http_r
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
- stream->no_flow_control = 1;
+ stream->no_flow_control = !r->request_body_no_buffering;
ngx_add_timer(r->connection->read, clcf->client_body_timeout);
@@ -3557,7 +3572,7 @@ ngx_http_v2_process_request_body(ngx_htt
{
ngx_buf_t *buf;
ngx_int_t rc;
- ngx_chain_t out;
+ ngx_chain_t out, *cl;
ngx_connection_t *fc;
ngx_http_request_body_t *rb;
ngx_http_core_loc_conf_t *clcf;
@@ -3596,6 +3611,32 @@ ngx_http_v2_process_request_body(ngx_htt
} else {
buf->last = ngx_cpymem(buf->last, pos, size);
+
+ if (r->request_body_no_buffering && !last) {
+ cl = ngx_chain_get_free_buf(r->pool, &rb->free);
+ if (cl == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ ngx_memcpy(cl->buf, buf, sizeof(ngx_buf_t));
+
+ cl->buf->flush = 1;
+ cl->buf->tag =
+ (ngx_buf_tag_t) &ngx_http_v2_process_request_body;
+
+ rc = ngx_http_top_request_body_filter(r, cl);
+
+ ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &cl,
+ (ngx_buf_tag_t) &ngx_http_v2_process_request_body);
+
+ if (rc != NGX_OK) {
+ return rc;
+ }
+
+ buf->pos = buf->last;
+
+ ngx_post_event(fc->read, &ngx_posted_events);
+ }
}
}
@@ -3632,8 +3673,13 @@ ngx_http_v2_process_request_body(ngx_htt
ngx_del_timer(fc->read);
}
- r->read_event_handler = ngx_http_block_reading;
- rb->post_handler(r);
+ if (r->request_body_no_buffering) {
+ r->read_event_handler(r);
+
+ } else {
+ r->read_event_handler = ngx_http_block_reading;
+ rb->post_handler(r);
+ }
return NGX_OK;
}
@@ -3677,6 +3723,82 @@ ngx_http_v2_read_client_request_body_han
}
+ngx_int_t
+ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r)
+{
+ size_t available;
+ ngx_buf_t *buf;
+ ngx_connection_t *fc;
+ ngx_http_v2_stream_t *stream;
+ ngx_http_v2_connection_t *h2c;
+ ngx_http_core_loc_conf_t *clcf;
+
+ stream = r->stream;
+ fc = r->connection;
+
+ if (fc->read->timedout) {
+ if (stream->recv_window == 0) {
+ return NGX_AGAIN;
+ }
+
+ stream->skip_data = 1;
+ fc->timedout = 1;
+
+ return NGX_HTTP_REQUEST_TIME_OUT;
+ }
+
+ if (fc->error) {
+ stream->skip_data = 1;
+ return NGX_ERROR;
+ }
+
+ if (!r->request_body->rest) {
+ r->reading_body = 0;
+ return NGX_OK;
+ }
+
+ buf = r->request_body->buf;
+
+ if (buf->pos != buf->last) {
+ return NGX_AGAIN;
+ }
+
+ buf->pos = buf->start;
+ buf->last = buf->start;
+
+ available = buf->end - buf->start;
+
+ h2c = stream->connection;
+
+ if (h2c->state.stream == stream) {
+ available -= h2c->state.length;
+ }
+
+ if (available > stream->recv_window && !stream->in_closed) {
+
+ if (ngx_http_v2_send_window_update(h2c, stream->node->id,
+ available - stream->recv_window)
+ == NGX_ERROR)
+ {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ if (stream->recv_window == 0) {
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+ ngx_add_timer(fc->read, clcf->client_body_timeout);
+ }
+
+ stream->recv_window = available;
+
+ if (!h2c->blocked && ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+ }
+
+ return NGX_AGAIN;
+}
+
+
static ngx_int_t
ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c,
ngx_http_v2_stream_t *stream, ngx_uint_t status)
diff -r 8933cfd2fb60 -r d0745c528544 src/http/v2/ngx_http_v2.h
--- a/src/http/v2/ngx_http_v2.h Fri Feb 26 18:22:26 2016 +0300
+++ b/src/http/v2/ngx_http_v2.h Fri Feb 26 18:22:51 2016 +0300
@@ -263,6 +263,7 @@ void ngx_http_v2_request_headers_init(vo
ngx_int_t ngx_http_v2_read_request_body(ngx_http_request_t *r,
ngx_http_client_body_handler_pt post_handler);
+ngx_int_t ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r);
void ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc);
More information about the nginx-devel
mailing list