diff options
Diffstat (limited to 'src/http')
| -rw-r--r-- | src/http/modules/ngx_http_grpc_module.c | 12 | ||||
| -rw-r--r-- | src/http/modules/ngx_http_proxy_module.c | 12 | ||||
| -rw-r--r-- | src/http/modules/ngx_http_ssl_module.c | 14 | ||||
| -rw-r--r-- | src/http/modules/ngx_http_uwsgi_module.c | 12 | ||||
| -rw-r--r-- | src/http/ngx_http_request.c | 8 | ||||
| -rw-r--r-- | src/http/ngx_http_request.h | 3 | ||||
| -rw-r--r-- | src/http/ngx_http_request_body.c | 124 | ||||
| -rw-r--r-- | src/http/ngx_http_upstream.c | 4 | ||||
| -rw-r--r-- | src/http/v2/ngx_http_v2.c | 315 |
9 files changed, 382 insertions, 122 deletions
diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c index 65bd1e6c3..6842b7c6e 100644 --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -4896,6 +4896,12 @@ ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf) cln->handler = ngx_ssl_cleanup_ctx; cln->data = glcf->upstream.ssl; + if (ngx_ssl_ciphers(cf, glcf->upstream.ssl, &glcf->ssl_ciphers, 0) + != NGX_OK) + { + return NGX_ERROR; + } + if (glcf->upstream.ssl_certificate) { if (glcf->upstream.ssl_certificate_key == NULL) { @@ -4927,12 +4933,6 @@ ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf) } } - if (ngx_ssl_ciphers(cf, glcf->upstream.ssl, &glcf->ssl_ciphers, 0) - != NGX_OK) - { - return NGX_ERROR; - } - if (glcf->upstream.ssl_verify) { if (glcf->ssl_trusted_certificate.len == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 368297e77..084462746 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -4944,6 +4944,12 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) cln->handler = ngx_ssl_cleanup_ctx; cln->data = plcf->upstream.ssl; + if (ngx_ssl_ciphers(cf, plcf->upstream.ssl, &plcf->ssl_ciphers, 0) + != NGX_OK) + { + return NGX_ERROR; + } + if (plcf->upstream.ssl_certificate) { if (plcf->upstream.ssl_certificate_key == NULL) { @@ -4975,12 +4981,6 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) } } - if (ngx_ssl_ciphers(cf, plcf->upstream.ssl, &plcf->ssl_ciphers, 0) - != NGX_OK) - { - return NGX_ERROR; - } - if (plcf->upstream.ssl_verify) { if (plcf->ssl_trusted_certificate.len == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index e6ce126ae..efbc4594c 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -830,6 +830,13 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_ssl_npn_advertised, NULL); #endif + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, + conf->prefer_server_ciphers) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + if (ngx_http_ssl_compile_certificates(cf, conf) != NGX_OK) { return NGX_CONF_ERROR; } @@ -862,13 +869,6 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) } } - if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, - conf->prefer_server_ciphers) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - conf->ssl.buffer_size = conf->buffer_size; if (conf->verify) { diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index 40a06c78e..4f9c349c2 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -2432,6 +2432,12 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf) cln->handler = ngx_ssl_cleanup_ctx; cln->data = uwcf->upstream.ssl; + if (ngx_ssl_ciphers(cf, uwcf->upstream.ssl, &uwcf->ssl_ciphers, 0) + != NGX_OK) + { + return NGX_ERROR; + } + if (uwcf->upstream.ssl_certificate) { if (uwcf->upstream.ssl_certificate_key == NULL) { @@ -2463,12 +2469,6 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf) } } - if (ngx_ssl_ciphers(cf, uwcf->upstream.ssl, &uwcf->ssl_ciphers, 0) - != NGX_OK) - { - return NGX_ERROR; - } - if (uwcf->upstream.ssl_verify) { if (uwcf->ssl_trusted_certificate.len == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index a27d29368..30200075e 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1992,6 +1992,14 @@ ngx_http_process_request_header(ngx_http_request_t *r) } if (r->headers_in.transfer_encoding) { + if (r->http_version < NGX_HTTP_VERSION_11) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent HTTP/1.0 request with " + "\"Transfer-Encoding\" header"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; + } + if (r->headers_in.transfer_encoding->value.len == 7 && ngx_strncasecmp(r->headers_in.transfer_encoding->value.data, (u_char *) "chunked", 7) == 0) diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index cd6bd6618..aee9109c3 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -303,6 +303,9 @@ typedef struct { ngx_chain_t *busy; ngx_http_chunked_t *chunked; ngx_http_client_body_handler_pt post_handler; + unsigned filter_need_buffering:1; + unsigned last_sent:1; + unsigned last_saved:1; } ngx_http_request_body_t; diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c index 05e990bfc..e4d9ff5be 100644 --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -62,11 +62,16 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, /* * set by ngx_pcalloc(): * + * rb->temp_file = NULL; * rb->bufs = NULL; * rb->buf = NULL; * rb->free = NULL; * rb->busy = NULL; * rb->chunked = NULL; + * rb->received = 0; + * rb->filter_need_buffering = 0; + * rb->last_sent = 0; + * rb->last_saved = 0; */ rb->rest = -1; @@ -151,7 +156,7 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, } } - if (rb->rest == 0) { + if (rb->rest == 0 && rb->last_saved) { /* the whole request body was pre-read */ r->request_body_no_buffering = 0; post_handler(r); @@ -179,6 +184,10 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, size += preread; } + if (size == 0) { + size++; + } + } else { size = clcf->client_body_buffer_size; } @@ -289,6 +298,7 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) size_t size; ssize_t n; ngx_int_t rc; + ngx_uint_t flush; ngx_chain_t out; ngx_connection_t *c; ngx_http_request_body_t *rb; @@ -296,12 +306,17 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) c = r->connection; rb = r->request_body; + flush = 1; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http read client request body"); for ( ;; ) { for ( ;; ) { + if (rb->rest == 0) { + break; + } + if (rb->buf->last == rb->buf->end) { /* update chains */ @@ -325,12 +340,25 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) return NGX_AGAIN; } + if (rb->filter_need_buffering) { + clcf = ngx_http_get_module_loc_conf(r, + ngx_http_core_module); + ngx_add_timer(c->read, clcf->client_body_timeout); + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + return NGX_AGAIN; + } + ngx_log_error(NGX_LOG_ALERT, c->log, 0, "busy buffers after request body flush"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } + flush = 0; rb->buf->pos = rb->buf->start; rb->buf->last = rb->buf->start; } @@ -342,6 +370,10 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) size = (size_t) rest; } + if (size == 0) { + break; + } + n = c->recv(c, rb->buf->last, size); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, @@ -366,6 +398,7 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) /* pass buffer to request body filter chain */ + flush = 0; out.buf = rb->buf; out.next = NULL; @@ -387,11 +420,19 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http client request body rest %O", rb->rest); - if (rb->rest == 0) { + if (flush) { + rc = ngx_http_request_body_filter(r, NULL); + + if (rc != NGX_OK) { + return rc; + } + } + + if (rb->rest == 0 && rb->last_saved) { break; } - if (!c->read->ready) { + if (!c->read->ready || rb->rest == 0) { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_add_timer(c->read, clcf->client_body_timeout); @@ -960,15 +1001,32 @@ ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in) rb = r->request_body; + out = NULL; + ll = &out; + if (rb->rest == -1) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http request body content length filter"); rb->rest = r->headers_in.content_length_n; - } - out = NULL; - ll = &out; + if (rb->rest == 0) { + + tl = ngx_chain_get_free_buf(r->pool, &rb->free); + if (tl == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + b = tl->buf; + + ngx_memzero(b, sizeof(ngx_buf_t)); + + b->last_buf = 1; + + *ll = tl; + ll = &tl->next; + } + } for (cl = in; cl; cl = cl->next) { @@ -1032,6 +1090,9 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) rb = r->request_body; + out = NULL; + ll = &out; + if (rb->rest == -1) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -1048,9 +1109,6 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) rb->rest = cscf->large_client_header_buffers.size; } - out = NULL; - ll = &out; - for (cl = in; cl; cl = cl->next) { b = NULL; @@ -1207,15 +1265,16 @@ ngx_int_t ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_buf_t *b; - ngx_chain_t *cl; + ngx_chain_t *cl, *tl, **ll; ngx_http_request_body_t *rb; rb = r->request_body; -#if (NGX_DEBUG) + ll = &rb->bufs; -#if 0 for (cl = rb->bufs; cl; cl = cl->next) { + +#if 0 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "http body old buf t:%d f:%d %p, pos %p, size: %z " "file: %O, size: %O", @@ -1224,10 +1283,13 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) cl->buf->last - cl->buf->pos, cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); - } #endif + ll = &cl->next; + } + for (cl = in; cl; cl = cl->next) { + ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "http body new buf t:%d f:%d %p, pos %p, size: %z " "file: %O, size: %O", @@ -1236,16 +1298,32 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) cl->buf->last - cl->buf->pos, cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); - } -#endif + if (cl->buf->last_buf) { - /* TODO: coalesce neighbouring buffers */ + if (rb->last_saved) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "duplicate last buf in save filter"); + *ll = NULL; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } - if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + rb->last_saved = 1; + } + + tl = ngx_alloc_chain_link(r->pool); + if (tl == NULL) { + *ll = NULL; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + tl->buf = cl->buf; + *ll = tl; + ll = &tl->next; } + *ll = NULL; + if (r->request_body_no_buffering) { return NGX_OK; } @@ -1261,10 +1339,18 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) return NGX_OK; } - /* rb->rest == 0 */ + if (!rb->last_saved) { + return NGX_OK; + } if (rb->temp_file || r->request_body_in_file_only) { + if (rb->bufs && rb->bufs->buf->in_file) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "body already in file"); + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + if (ngx_http_write_request_body(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 4ba35d518..7ca75d3b7 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -2133,6 +2133,10 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u, c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; } + if (c->read->ready) { + ngx_post_event(c->read, &ngx_posted_events); + } + return; } diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 3bef002bd..79c4f17c2 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -173,7 +173,7 @@ static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r); static void ngx_http_v2_run_request(ngx_http_request_t *r); static void ngx_http_v2_run_request_handler(ngx_event_t *ev); static ngx_int_t ngx_http_v2_process_request_body(ngx_http_request_t *r, - u_char *pos, size_t size, ngx_uint_t last); + u_char *pos, size_t size, ngx_uint_t last, ngx_uint_t flush); static ngx_int_t ngx_http_v2_filter_request_body(ngx_http_request_t *r); static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r); @@ -1092,7 +1092,7 @@ static u_char * ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) { - size_t size; + size_t size, window; ngx_buf_t *buf; ngx_int_t rc; ngx_connection_t *fc; @@ -1140,13 +1140,40 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, h2c->payload_bytes += size; if (r->request_body) { - rc = ngx_http_v2_process_request_body(r, pos, size, stream->in_closed); + rc = ngx_http_v2_process_request_body(r, pos, size, + stream->in_closed, 0); - if (rc != NGX_OK) { + if (rc != NGX_OK && rc != NGX_AGAIN) { stream->skip_data = 1; ngx_http_finalize_request(r, rc); } + if (rc == NGX_AGAIN && !stream->no_flow_control) { + buf = r->request_body->buf; + window = buf->end - buf->last; + + window -= h2c->state.length - size; + + if (window < stream->recv_window) { + ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, + "http2 negative window update"); + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + if (window > stream->recv_window) { + if (ngx_http_v2_send_window_update(h2c, stream->node->id, + window - stream->recv_window) + == NGX_ERROR) + { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + + stream->recv_window = window; + } + } + ngx_http_run_posted_requests(fc); } else if (size) { @@ -4027,16 +4054,30 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r) return NGX_OK; } + rb->rest = 1; + + /* set rb->filter_need_buffering */ + + rc = ngx_http_top_request_body_filter(r, NULL); + + if (rc != NGX_OK) { + stream->skip_data = 1; + return rc; + } + h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); len = r->headers_in.content_length_n; - if (r->request_body_no_buffering && !stream->in_closed) { + if (len < 0 || len > (off_t) clcf->client_body_buffer_size) { + len = clcf->client_body_buffer_size; - if (len < 0 || len > (off_t) clcf->client_body_buffer_size) { - len = clcf->client_body_buffer_size; - } + } else { + len++; + } + + if (r->request_body_no_buffering || rb->filter_need_buffering) { /* * We need a room to store data up to the stream's initial window size, @@ -4050,57 +4091,54 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r) if (len > NGX_HTTP_V2_MAX_WINDOW) { len = NGX_HTTP_V2_MAX_WINDOW; } - - rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); - - } else if (len >= 0 && len <= (off_t) clcf->client_body_buffer_size - && !r->request_body_in_file_only) - { - rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); - - } else { - rb->buf = ngx_calloc_buf(r->pool); - - if (rb->buf != NULL) { - rb->buf->sync = 1; - } } + rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); + if (rb->buf == NULL) { stream->skip_data = 1; return NGX_HTTP_INTERNAL_SERVER_ERROR; } - rb->rest = 1; - buf = stream->preread; if (stream->in_closed) { - r->request_body_no_buffering = 0; + if (!rb->filter_need_buffering) { + r->request_body_no_buffering = 0; + } if (buf) { rc = ngx_http_v2_process_request_body(r, buf->pos, - buf->last - buf->pos, 1); + buf->last - buf->pos, 1, 0); ngx_pfree(r->pool, buf->start); + + } else { + rc = ngx_http_v2_process_request_body(r, NULL, 0, 1, 0); + } + + if (rc != NGX_AGAIN) { return rc; } - return ngx_http_v2_process_request_body(r, NULL, 0, 1); + r->read_event_handler = ngx_http_v2_read_client_request_body_handler; + r->write_event_handler = ngx_http_request_empty_handler; + + return NGX_AGAIN; } if (buf) { rc = ngx_http_v2_process_request_body(r, buf->pos, - buf->last - buf->pos, 0); + buf->last - buf->pos, 0, 0); ngx_pfree(r->pool, buf->start); - if (rc != NGX_OK) { + if (rc != NGX_OK && rc != NGX_AGAIN) { stream->skip_data = 1; return rc; } } - if (r->request_body_no_buffering) { + if (r->request_body_no_buffering || rb->filter_need_buffering) { size = (size_t) len - h2scf->preread_size; } else { @@ -4142,9 +4180,9 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r) static ngx_int_t ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, - size_t size, ngx_uint_t last) + size_t size, ngx_uint_t last, ngx_uint_t flush) { - ngx_buf_t *buf; + size_t n; ngx_int_t rc; ngx_connection_t *fc; ngx_http_request_body_t *rb; @@ -4152,77 +4190,128 @@ ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, fc = r->connection; rb = r->request_body; - buf = rb->buf; - if (size) { - if (buf->sync) { - buf->pos = buf->start = pos; - buf->last = buf->end = pos + size; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 process request body"); - r->request_body_in_file_only = 1; + if (size == 0 && !last && !flush) { + return NGX_AGAIN; + } - } else { - if (size > (size_t) (buf->end - buf->last)) { - ngx_log_error(NGX_LOG_INFO, fc->log, 0, - "client intended to send body data " - "larger than declared"); + for ( ;; ) { + for ( ;; ) { + if (rb->buf->last == rb->buf->end && size) { - return NGX_HTTP_BAD_REQUEST; + if (r->request_body_no_buffering) { + + /* should never happen due to flow control */ + + ngx_log_error(NGX_LOG_ALERT, fc->log, 0, + "no space in http2 body buffer"); + + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + /* update chains */ + + ngx_log_error(NGX_LOG_DEBUG, fc->log, 0, + "http2 body update chains"); + + rc = ngx_http_v2_filter_request_body(r); + + if (rc != NGX_OK) { + return rc; + } + + if (rb->busy != NULL) { + ngx_log_error(NGX_LOG_ALERT, fc->log, 0, + "busy buffers after request body flush"); + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + rb->buf->pos = rb->buf->start; + rb->buf->last = rb->buf->start; } - buf->last = ngx_cpymem(buf->last, pos, size); - } - } + /* copy body data to the buffer */ - if (last) { - rb->rest = 0; + n = rb->buf->end - rb->buf->last; - if (fc->read->timer_set) { - ngx_del_timer(fc->read); - } + if (n > size) { + n = size; + } - if (r->request_body_no_buffering) { - ngx_post_event(fc->read, &ngx_posted_events); - return NGX_OK; - } + if (n > 0) { + rb->buf->last = ngx_cpymem(rb->buf->last, pos, n); + } - rc = ngx_http_v2_filter_request_body(r); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 request body recv %uz", n); - if (rc != NGX_OK) { - return rc; - } + pos += n; + size -= n; + + if (size == 0 && last) { + rb->rest = 0; + } + + if (r->request_body_no_buffering) { + break; + } + + /* pass buffer to request body filter chain */ + + rc = ngx_http_v2_filter_request_body(r); + + if (rc != NGX_OK) { + return rc; + } - if (buf->sync) { - /* prevent reusing this buffer in the upstream module */ - rb->buf = NULL; + if (rb->rest == 0) { + break; + } + + if (size == 0) { + break; + } } - if (r->headers_in.chunked) { - r->headers_in.content_length_n = rb->received; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 request body rest %O", rb->rest); + + if (rb->rest == 0 && rb->last_saved) { + break; } - r->read_event_handler = ngx_http_block_reading; - rb->post_handler(r); + if (size == 0) { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + ngx_add_timer(fc->read, clcf->client_body_timeout); - return NGX_OK; - } + if (r->request_body_no_buffering) { + ngx_post_event(fc->read, &ngx_posted_events); + return NGX_AGAIN; + } - if (size == 0) { - return NGX_OK; + return NGX_AGAIN; + } } - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_add_timer(fc->read, clcf->client_body_timeout); + if (fc->read->timer_set) { + ngx_del_timer(fc->read); + } if (r->request_body_no_buffering) { ngx_post_event(fc->read, &ngx_posted_events); return NGX_OK; } - if (buf->sync) { - return ngx_http_v2_filter_request_body(r); + if (r->headers_in.chunked) { + r->headers_in.content_length_n = rb->received; } + r->read_event_handler = ngx_http_block_reading; + rb->post_handler(r); + return NGX_OK; } @@ -4239,7 +4328,7 @@ ngx_http_v2_filter_request_body(ngx_http_request_t *r) rb = r->request_body; buf = rb->buf; - if (buf->pos == buf->last && rb->rest) { + if (buf->pos == buf->last && (rb->rest || rb->last_sent)) { cl = NULL; goto update; } @@ -4302,6 +4391,7 @@ ngx_http_v2_filter_request_body(ngx_http_request_t *r) } b->last_buf = 1; + rb->last_sent = 1; } b->tag = (ngx_buf_tag_t) &ngx_http_v2_filter_request_body; @@ -4321,7 +4411,12 @@ update: static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r) { - ngx_connection_t *fc; + size_t window; + ngx_buf_t *buf; + ngx_int_t rc; + ngx_connection_t *fc; + ngx_http_v2_stream_t *stream; + ngx_http_v2_connection_t *h2c; fc = r->connection; @@ -4347,6 +4442,63 @@ ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r) ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); return; } + + rc = ngx_http_v2_process_request_body(r, NULL, 0, r->stream->in_closed, 1); + + if (rc != NGX_OK && rc != NGX_AGAIN) { + r->stream->skip_data = 1; + ngx_http_finalize_request(r, rc); + return; + } + + if (rc == NGX_OK) { + return; + } + + if (r->request_body->rest == 0) { + return; + } + + stream = r->stream; + h2c = stream->connection; + + buf = r->request_body->buf; + window = buf->end - buf->start; + + if (h2c->state.stream == stream) { + window -= h2c->state.length; + } + + if (window <= stream->recv_window) { + if (window < stream->recv_window) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "http2 negative window update"); + + stream->skip_data = 1; + + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + return; + } + + if (ngx_http_v2_send_window_update(h2c, stream->node->id, + window - stream->recv_window) + == NGX_ERROR) + { + stream->skip_data = 1; + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + stream->recv_window = window; + + if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) { + stream->skip_data = 1; + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } } @@ -4364,6 +4516,9 @@ ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r) stream = r->stream; fc = r->connection; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 read unbuffered request body"); + if (fc->read->timedout) { if (stream->recv_window) { stream->skip_data = 1; @@ -4387,10 +4542,14 @@ ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r) return rc; } - if (!r->request_body->rest) { + if (r->request_body->rest == 0 && r->request_body->last_saved) { return NGX_OK; } + if (r->request_body->rest == 0) { + return NGX_AGAIN; + } + if (r->request_body->busy != NULL) { return NGX_AGAIN; } |
