Parsing HTTP/3 request body.
This commit is contained in:
parent
732e383dd1
commit
48a1eeb5c2
8 changed files with 167 additions and 10 deletions
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue