summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorRoman Arutyunyan <arut@nginx.com>2020-03-27 19:41:06 +0300
committerRoman Arutyunyan <arut@nginx.com>2020-03-27 19:41:06 +0300
commitfa1e1beadca8b1ea900ec654919aea58762ab746 (patch)
tree772a9443d24831a11fae49b2493a87fa6f6d4a94 /src
parent84a783501590e13ab27277e11f179067c08d38b3 (diff)
downloadnginx-fa1e1beadca8b1ea900ec654919aea58762ab746.tar.gz
nginx-fa1e1beadca8b1ea900ec654919aea58762ab746.tar.bz2
Parsing HTTP/3 request body.
Diffstat (limited to 'src')
-rw-r--r--src/http/ngx_http.h3
-rw-r--r--src/http/ngx_http_parse.c11
-rw-r--r--src/http/ngx_http_request.c1
-rw-r--r--src/http/ngx_http_request_body.c29
-rw-r--r--src/http/v3/ngx_http_v3.h2
-rw-r--r--src/http/v3/ngx_http_v3_parse.c58
-rw-r--r--src/http/v3/ngx_http_v3_parse.h10
-rw-r--r--src/http/v3/ngx_http_v3_request.c63
8 files changed, 167 insertions, 10 deletions
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h
index 8772001c0..a0946c95a 100644
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -63,6 +63,9 @@ struct ngx_http_chunked_s {
ngx_uint_t state;
off_t size;
off_t length;
+#if (NGX_HTTP_V3)
+ void *h3_parse;
+#endif
};
diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
index 28aa8b0dd..92bcf12ad 100644
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -2185,6 +2185,12 @@ ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b,
sw_trailer_header_almost_done
} state;
+#if (NGX_HTTP_V3)
+ if (r->http_version == NGX_HTTP_VERSION_30) {
+ return ngx_http_v3_parse_request_body(r, b, ctx);
+ }
+#endif
+
state = ctx->state;
if (state == sw_chunk_data && ctx->size == 0) {
@@ -2371,6 +2377,11 @@ ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b,
}
}
+ if (b->last_buf) {
+ /* XXX client prematurely closed connection */
+ return NGX_ERROR;
+ }
+
data:
ctx->state = state;
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 6f168c8bd..4368e79c0 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -709,6 +709,7 @@ ngx_http_alloc_request(ngx_connection_t *c)
#if (NGX_HTTP_V3)
if (hc->quic) {
r->http_version = NGX_HTTP_VERSION_30;
+ r->headers_in.chunked = 1;
}
#endif
diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c
index c4f092e59..b07d8562f 100644
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -343,11 +343,10 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
}
if (n == 0) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "client prematurely closed connection");
+ rb->buf->last_buf = 1;
}
- if (n == 0 || n == NGX_ERROR) {
+ if (n == NGX_ERROR) {
c->error = 1;
return NGX_HTTP_BAD_REQUEST;
}
@@ -355,7 +354,7 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
rb->buf->last += n;
r->request_length += n;
- if (n == rest) {
+ if (n == rest || n == 0) {
/* pass buffer to request body filter chain */
out.buf = rb->buf;
@@ -805,11 +804,7 @@ ngx_http_test_expect(ngx_http_request_t *r)
if (r->expect_tested
|| r->headers_in.expect == NULL
- || r->http_version < NGX_HTTP_VERSION_11
-#if (NGX_HTTP_V2)
- || r->stream != NULL
-#endif
- )
+ || r->http_version != NGX_HTTP_VERSION_11)
{
return NGX_OK;
}
@@ -914,6 +909,11 @@ ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in)
b->last_buf = 1;
}
+ if (cl->buf->last_buf && rb->rest > 0) {
+ /* XXX client prematurely closed connection */
+ return NGX_ERROR;
+ }
+
*ll = tl;
ll = &tl->next;
}
@@ -950,7 +950,16 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
}
r->headers_in.content_length_n = 0;
- rb->rest = 3;
+
+#if (NGX_HTTP_V3)
+ if (r->http_version == NGX_HTTP_VERSION_30) {
+ rb->rest = 1;
+
+ } else
+#endif
+ {
+ rb->rest = 3;
+ }
}
out = NULL;
diff --git a/src/http/v3/ngx_http_v3.h b/src/http/v3/ngx_http_v3.h
index d28074d37..3f35e985e 100644
--- a/src/http/v3/ngx_http_v3.h
+++ b/src/http/v3/ngx_http_v3.h
@@ -68,6 +68,8 @@ typedef struct {
ngx_int_t ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b);
+ngx_int_t ngx_http_v3_parse_request_body(ngx_http_request_t *r, ngx_buf_t *b,
+ ngx_http_chunked_t *ctx);
ngx_chain_t *ngx_http_v3_create_header(ngx_http_request_t *r);
ngx_chain_t *ngx_http_v3_create_trailers(ngx_http_request_t *r);
diff --git a/src/http/v3/ngx_http_v3_parse.c b/src/http/v3/ngx_http_v3_parse.c
index 0fd44bc40..3be3802ed 100644
--- a/src/http/v3/ngx_http_v3_parse.c
+++ b/src/http/v3/ngx_http_v3_parse.c
@@ -1421,3 +1421,61 @@ done:
st->state = sw_start;
return NGX_DONE;
}
+
+
+ngx_int_t
+ngx_http_v3_parse_data(ngx_connection_t *c, ngx_http_v3_parse_data_t *st,
+ u_char ch)
+{
+ enum {
+ sw_start = 0,
+ sw_type,
+ sw_length
+ };
+
+ switch (st->state) {
+
+ case sw_start:
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse data");
+
+ st->state = sw_type;
+
+ /* fall through */
+
+ case sw_type:
+
+ if (ngx_http_v3_parse_varlen_int(c, &st->vlint, ch) != NGX_DONE) {
+ break;
+ }
+
+ if (st->vlint.value != NGX_HTTP_V3_FRAME_DATA) {
+ return NGX_ERROR;
+ }
+
+ st->state = sw_length;
+ break;
+
+ case sw_length:
+
+ if (ngx_http_v3_parse_varlen_int(c, &st->vlint, ch) != NGX_DONE) {
+ break;
+ }
+
+ st->length = st->vlint.value;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "http3 parse data frame len:%ui", st->length);
+
+ goto done;
+ }
+
+ return NGX_AGAIN;
+
+done:
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse data done");
+
+ st->state = sw_start;
+ return NGX_DONE;
+}
diff --git a/src/http/v3/ngx_http_v3_parse.h b/src/http/v3/ngx_http_v3_parse.h
index 959da7941..ec78c7c35 100644
--- a/src/http/v3/ngx_http_v3_parse.h
+++ b/src/http/v3/ngx_http_v3_parse.h
@@ -105,6 +105,13 @@ typedef struct {
} ngx_http_v3_parse_control_t;
+typedef struct {
+ ngx_uint_t state;
+ ngx_uint_t length;
+ ngx_http_v3_parse_varlen_int_t vlint;
+} ngx_http_v3_parse_data_t;
+
+
ngx_int_t ngx_http_v3_parse_varlen_int(ngx_connection_t *c,
ngx_http_v3_parse_varlen_int_t *st, u_char ch);
ngx_int_t ngx_http_v3_parse_prefix_int(ngx_connection_t *c,
@@ -141,5 +148,8 @@ ngx_int_t ngx_http_v3_parse_header_iwnr(ngx_connection_t *c,
ngx_int_t ngx_http_v3_parse_decoder(ngx_connection_t *c, void *data, u_char ch);
+ngx_int_t ngx_http_v3_parse_data(ngx_connection_t *c,
+ ngx_http_v3_parse_data_t *st, u_char ch);
+
#endif /* _NGX_HTTP_V3_PARSE_H_INCLUDED_ */
diff --git a/src/http/v3/ngx_http_v3_request.c b/src/http/v3/ngx_http_v3_request.c
index 756a6f90d..911dbab36 100644
--- a/src/http/v3/ngx_http_v3_request.c
+++ b/src/http/v3/ngx_http_v3_request.c
@@ -241,6 +241,69 @@ ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name,
}
+ngx_int_t
+ngx_http_v3_parse_request_body(ngx_http_request_t *r, ngx_buf_t *b,
+ ngx_http_chunked_t *ctx)
+{
+ ngx_int_t rc;
+ ngx_connection_t *c;
+ ngx_http_v3_parse_data_t *st;
+
+ c = r->connection;
+ st = ctx->h3_parse;
+
+ if (st == NULL) {
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "http3 parse request body");
+
+ st = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_parse_data_t));
+ if (st == NULL) {
+ goto failed;
+ }
+
+ r->h3_parse = st;
+ }
+
+ if (ctx->size) {
+ return NGX_OK;
+ }
+
+ while (b->pos < b->last) {
+ rc = ngx_http_v3_parse_data(c, st, *b->pos++);
+
+ if (rc == NGX_ERROR) {
+ goto failed;
+ }
+
+ if (rc == NGX_AGAIN) {
+ continue;
+ }
+
+ /* rc == NGX_DONE */
+
+ ctx->size = st->length;
+ return NGX_OK;
+ }
+
+ if (!b->last_buf) {
+ ctx->length = 1;
+ return NGX_AGAIN;
+ }
+
+ if (st->state) {
+ goto failed;
+ }
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header done");
+
+ return NGX_DONE;
+
+failed:
+
+ return NGX_ERROR;
+}
+
+
ngx_chain_t *
ngx_http_v3_create_header(ngx_http_request_t *r)
{