aboutsummaryrefslogtreecommitdiff
path: root/src/http/ngx_http_request_body.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/http/ngx_http_request_body.c')
-rw-r--r--src/http/ngx_http_request_body.c204
1 files changed, 149 insertions, 55 deletions
diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c
index 568f11f02..204253ca2 100644
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -12,6 +12,8 @@
static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r);
static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
+static ngx_int_t ngx_http_copy_pipelined_header(ngx_http_request_t *r,
+ ngx_buf_t *buf);
static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r);
static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r);
static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r,
@@ -282,28 +284,12 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
for ( ;; ) {
if (rb->buf->last == rb->buf->end) {
- if (rb->buf->pos != rb->buf->last) {
+ /* update chains */
- /* pass buffer to request body filter chain */
+ rc = ngx_http_request_body_filter(r, NULL);
- out.buf = rb->buf;
- out.next = NULL;
-
- rc = ngx_http_request_body_filter(r, &out);
-
- if (rc != NGX_OK) {
- return rc;
- }
-
- } else {
-
- /* update chains */
-
- rc = ngx_http_request_body_filter(r, NULL);
-
- if (rc != NGX_OK) {
- return rc;
- }
+ if (rc != NGX_OK) {
+ return rc;
}
if (rb->busy != NULL) {
@@ -354,17 +340,15 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
rb->buf->last += n;
r->request_length += n;
- if (n == rest || n == 0) {
- /* pass buffer to request body filter chain */
+ /* pass buffer to request body filter chain */
- out.buf = rb->buf;
- out.next = NULL;
+ out.buf = rb->buf;
+ out.next = NULL;
- rc = ngx_http_request_body_filter(r, &out);
+ rc = ngx_http_request_body_filter(r, &out);
- if (rc != NGX_OK) {
- return rc;
- }
+ if (rc != NGX_OK) {
+ return rc;
}
if (rb->rest == 0) {
@@ -385,21 +369,6 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
if (!c->read->ready) {
- if (r->request_body_no_buffering
- && rb->buf->pos != rb->buf->last)
- {
- /* pass buffer to request body filter chain */
-
- out.buf = rb->buf;
- out.next = NULL;
-
- rc = ngx_http_request_body_filter(r, &out);
-
- if (rc != NGX_OK) {
- return rc;
- }
- }
-
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
ngx_add_timer(c->read, clcf->client_body_timeout);
@@ -411,6 +380,10 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
}
}
+ if (ngx_http_copy_pipelined_header(r, rb->buf) != NGX_OK) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
if (c->read->timer_set) {
ngx_del_timer(c->read);
}
@@ -425,6 +398,88 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
static ngx_int_t
+ngx_http_copy_pipelined_header(ngx_http_request_t *r, ngx_buf_t *buf)
+{
+ size_t n;
+ ngx_buf_t *b;
+ ngx_chain_t *cl;
+ ngx_http_connection_t *hc;
+ ngx_http_core_srv_conf_t *cscf;
+
+ b = r->header_in;
+ n = buf->last - buf->pos;
+
+ if (buf == b || n == 0) {
+ return NGX_OK;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http body pipelined header: %uz", n);
+
+ /*
+ * if there is a pipelined request in the client body buffer,
+ * copy it to the r->header_in buffer if there is enough room,
+ * or allocate a large client header buffer
+ */
+
+ if (n > (size_t) (b->end - b->last)) {
+
+ hc = r->http_connection;
+
+ if (hc->free) {
+ cl = hc->free;
+ hc->free = cl->next;
+
+ b = cl->buf;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http large header free: %p %uz",
+ b->pos, b->end - b->last);
+
+ } else {
+ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+
+ b = ngx_create_temp_buf(r->connection->pool,
+ cscf->large_client_header_buffers.size);
+ if (b == NULL) {
+ return NGX_ERROR;
+ }
+
+ cl = ngx_alloc_chain_link(r->connection->pool);
+ if (cl == NULL) {
+ return NGX_ERROR;
+ }
+
+ cl->buf = b;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http large header alloc: %p %uz",
+ b->pos, b->end - b->last);
+ }
+
+ cl->next = hc->busy;
+ hc->busy = cl;
+ hc->nbusy++;
+
+ r->header_in = b;
+
+ if (n > (size_t) (b->end - b->last)) {
+ ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+ "too large pipelined header after reading body");
+ return NGX_ERROR;
+ }
+ }
+
+ ngx_memcpy(b->last, buf->pos, n);
+
+ b->last += n;
+ r->request_length -= n;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_write_request_body(ngx_http_request_t *r)
{
ssize_t n;
@@ -669,8 +724,7 @@ ngx_http_read_discarded_request_body(ngx_http_request_t *r)
for ( ;; ) {
if (r->headers_in.content_length_n == 0) {
- r->read_event_handler = ngx_http_block_reading;
- return NGX_OK;
+ break;
}
if (!r->connection->read->ready) {
@@ -704,15 +758,24 @@ ngx_http_read_discarded_request_body(ngx_http_request_t *r)
return rc;
}
}
+
+ if (ngx_http_copy_pipelined_header(r, &b) != NGX_OK) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ r->read_event_handler = ngx_http_block_reading;
+
+ return NGX_OK;
}
static ngx_int_t
ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b)
{
- size_t size;
- ngx_int_t rc;
- ngx_http_request_body_t *rb;
+ size_t size;
+ ngx_int_t rc;
+ ngx_http_request_body_t *rb;
+ ngx_http_core_srv_conf_t *cscf;
if (r->headers_in.chunked) {
@@ -776,7 +839,10 @@ ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b)
/* set amount of data we want to see next time */
- r->headers_in.content_length_n = rb->chunked->length;
+ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+
+ r->headers_in.content_length_n = ngx_max(rb->chunked->length,
+ (off_t) cscf->large_client_header_buffers.size);
break;
}
@@ -945,6 +1011,7 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
ngx_chain_t *cl, *out, *tl, **ll;
ngx_http_request_body_t *rb;
ngx_http_core_loc_conf_t *clcf;
+ ngx_http_core_srv_conf_t *cscf;
rb = r->request_body;
@@ -958,17 +1025,16 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
+ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+
r->headers_in.content_length_n = 0;
+ rb->rest = cscf->large_client_header_buffers.size;
#if (NGX_HTTP_V3)
if (r->http_version == NGX_HTTP_VERSION_30) {
rb->rest = 1;
-
- } else
-#endif
- {
- rb->rest = 3;
}
+#endif
}
out = NULL;
@@ -976,6 +1042,8 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
for (cl = in; cl; cl = cl->next) {
+ b = NULL;
+
for ( ;; ) {
ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
@@ -1019,6 +1087,29 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
}
+ if (b
+ && rb->chunked->size <= 128
+ && cl->buf->last - cl->buf->pos >= rb->chunked->size)
+ {
+ r->headers_in.content_length_n += rb->chunked->size;
+
+ if (rb->chunked->size < 8) {
+
+ while (rb->chunked->size) {
+ *b->last++ = *cl->buf->pos++;
+ rb->chunked->size--;
+ }
+
+ } else {
+ ngx_memmove(b->last, cl->buf->pos, rb->chunked->size);
+ b->last += rb->chunked->size;
+ cl->buf->pos += rb->chunked->size;
+ rb->chunked->size = 0;
+ }
+
+ continue;
+ }
+
tl = ngx_chain_get_free_buf(r->pool, &rb->free);
if (tl == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -1084,7 +1175,10 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
/* set rb->rest, amount of data we want to see next time */
- rb->rest = rb->chunked->length;
+ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+
+ rb->rest = ngx_max(rb->chunked->length,
+ (off_t) cscf->large_client_header_buffers.size);
break;
}