mirror of
https://github.com/nginx/nginx.git
synced 2024-12-03 21:18:59 +08:00
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Previously errors led only to closing streams. To simplify closing QUIC connection from a QUIC stream context, new macro ngx_http_v3_finalize_connection() is introduced. It calls ngx_quic_finalize_connection() for the parent connection.
This commit is contained in:
parent
fd35d92232
commit
707117276e
@ -416,19 +416,21 @@ static void
|
||||
ngx_http_quic_stream_handler(ngx_connection_t *c)
|
||||
{
|
||||
ngx_event_t *rev;
|
||||
ngx_connection_t *pc;
|
||||
ngx_http_log_ctx_t *ctx;
|
||||
ngx_http_connection_t *hc;
|
||||
ngx_http_v3_connection_t *h3c;
|
||||
|
||||
pc = c->qs->parent;
|
||||
h3c = pc->data;
|
||||
h3c = c->qs->parent->data;
|
||||
|
||||
if (!h3c->settings_sent) {
|
||||
h3c->settings_sent = 1;
|
||||
|
||||
/* TODO close QUIC connection on error */
|
||||
(void) ngx_http_v3_send_settings(c);
|
||||
if (ngx_http_v3_send_settings(c) != NGX_OK) {
|
||||
ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
|
||||
"could not send settings");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (c->qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) {
|
||||
|
@ -80,6 +80,9 @@
|
||||
((ngx_http_v3_connection_t *) c->qs->parent->data)->hc.conf_ctx, \
|
||||
module)
|
||||
|
||||
#define ngx_http_v3_finalize_connection(c, code, reason) \
|
||||
ngx_quic_finalize_connection(c->qs->parent, code, reason)
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_quic_tp_t quic;
|
||||
|
@ -160,7 +160,7 @@ ngx_http_v3_parse_headers(ngx_connection_t *c, ngx_http_v3_parse_headers_t *st,
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse headers");
|
||||
|
||||
if (ch != NGX_HTTP_V3_FRAME_HEADERS) {
|
||||
return NGX_ERROR;
|
||||
return NGX_HTTP_V3_ERR_FRAME_UNEXPECTED;
|
||||
}
|
||||
|
||||
st->state = sw_length;
|
||||
@ -183,21 +183,21 @@ ngx_http_v3_parse_headers(ngx_connection_t *c, ngx_http_v3_parse_headers_t *st,
|
||||
case sw_prefix:
|
||||
|
||||
if (st->length-- == 0) {
|
||||
return NGX_ERROR;
|
||||
return NGX_HTTP_V3_ERR_FRAME_ERROR;
|
||||
}
|
||||
|
||||
rc = ngx_http_v3_parse_header_block_prefix(c, &st->prefix, ch);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (rc != NGX_DONE) {
|
||||
if (rc == NGX_AGAIN) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc != NGX_DONE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (st->length == 0) {
|
||||
return NGX_ERROR;
|
||||
return NGX_HTTP_V3_ERR_FRAME_ERROR;
|
||||
}
|
||||
|
||||
st->state = sw_verify;
|
||||
@ -218,24 +218,25 @@ ngx_http_v3_parse_headers(ngx_connection_t *c, ngx_http_v3_parse_headers_t *st,
|
||||
|
||||
rc = ngx_http_v3_parse_header_rep(c, &st->header_rep, st->prefix.base,
|
||||
ch);
|
||||
st->length--;
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (--st->length == 0) {
|
||||
if (rc != NGX_DONE) {
|
||||
return NGX_ERROR;
|
||||
if (rc == NGX_AGAIN) {
|
||||
if (st->length == 0) {
|
||||
return NGX_HTTP_V3_ERR_FRAME_ERROR;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc != NGX_DONE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (st->length == 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
break;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
return NGX_AGAIN;
|
||||
@ -259,6 +260,7 @@ ngx_int_t
|
||||
ngx_http_v3_parse_header_block_prefix(ngx_connection_t *c,
|
||||
ngx_http_v3_parse_header_block_prefix_t *st, u_char ch)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
enum {
|
||||
sw_start = 0,
|
||||
sw_req_insert_count,
|
||||
@ -308,8 +310,9 @@ ngx_http_v3_parse_header_block_prefix(ngx_connection_t *c,
|
||||
|
||||
done:
|
||||
|
||||
if (ngx_http_v3_decode_insert_count(c, &st->insert_count) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
rc = ngx_http_v3_decode_insert_count(c, &st->insert_count);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (st->sign) {
|
||||
@ -404,16 +407,10 @@ ngx_http_v3_parse_header_rep(ngx_connection_t *c,
|
||||
rc = NGX_OK;
|
||||
}
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
if (rc != NGX_DONE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
/* rc == NGX_DONE */
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
||||
"http3 parse header representation done");
|
||||
|
||||
@ -448,7 +445,7 @@ ngx_http_v3_parse_literal(ngx_connection_t *c, ngx_http_v3_parse_literal_t *st,
|
||||
if (n > v3cf->max_field_size) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||
"client exceeded http3_max_field_size limit");
|
||||
return NGX_ERROR;
|
||||
return NGX_HTTP_V3_ERR_EXCESSIVE_LOAD;
|
||||
}
|
||||
|
||||
if (st->huffman) {
|
||||
@ -505,6 +502,7 @@ ngx_int_t
|
||||
ngx_http_v3_parse_header_ri(ngx_connection_t *c, ngx_http_v3_parse_header_t *st,
|
||||
u_char ch)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
enum {
|
||||
sw_start = 0,
|
||||
sw_index
|
||||
@ -543,11 +541,10 @@ done:
|
||||
st->index = st->base - st->index - 1;
|
||||
}
|
||||
|
||||
if (ngx_http_v3_parse_lookup(c, st->dynamic, st->index, &st->name,
|
||||
&st->value)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
rc = ngx_http_v3_parse_lookup(c, st->dynamic, st->index, &st->name,
|
||||
&st->value);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
st->state = sw_start;
|
||||
@ -614,15 +611,15 @@ ngx_http_v3_parse_header_lri(ngx_connection_t *c,
|
||||
|
||||
rc = ngx_http_v3_parse_literal(c, &st->literal, ch);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
st->value = st->literal.value;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (rc != NGX_AGAIN) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -639,10 +636,9 @@ done:
|
||||
st->index = st->base - st->index - 1;
|
||||
}
|
||||
|
||||
if (ngx_http_v3_parse_lookup(c, st->dynamic, st->index, &st->name, NULL)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
rc = ngx_http_v3_parse_lookup(c, st->dynamic, st->index, &st->name, NULL);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
st->state = sw_start;
|
||||
@ -693,13 +689,14 @@ ngx_http_v3_parse_header_l(ngx_connection_t *c,
|
||||
|
||||
rc = ngx_http_v3_parse_literal(c, &st->literal, ch);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
st->name = st->literal.value;
|
||||
st->state = sw_value_len;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc != NGX_AGAIN) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -729,15 +726,15 @@ ngx_http_v3_parse_header_l(ngx_connection_t *c,
|
||||
|
||||
rc = ngx_http_v3_parse_literal(c, &st->literal, ch);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
st->value = st->literal.value;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (rc != NGX_AGAIN) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -758,6 +755,7 @@ ngx_int_t
|
||||
ngx_http_v3_parse_header_pbi(ngx_connection_t *c,
|
||||
ngx_http_v3_parse_header_t *st, u_char ch)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
enum {
|
||||
sw_start = 0,
|
||||
sw_index
|
||||
@ -790,11 +788,10 @@ done:
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
||||
"http3 parse header pbi done dynamic[+%ui]", st->index);
|
||||
|
||||
if (ngx_http_v3_parse_lookup(c, 1, st->base + st->index, &st->name,
|
||||
&st->value)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
rc = ngx_http_v3_parse_lookup(c, 1, st->base + st->index, &st->name,
|
||||
&st->value);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
st->state = sw_start;
|
||||
@ -861,15 +858,15 @@ ngx_http_v3_parse_header_lpbi(ngx_connection_t *c,
|
||||
|
||||
rc = ngx_http_v3_parse_literal(c, &st->literal, ch);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
st->value = st->literal.value;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (rc != NGX_AGAIN) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -881,10 +878,9 @@ done:
|
||||
"http3 parse header lpbi done dynamic[+%ui] \"%V\"",
|
||||
st->index, &st->value);
|
||||
|
||||
if (ngx_http_v3_parse_lookup(c, 1, st->base + st->index, &st->name, NULL)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
rc = ngx_http_v3_parse_lookup(c, 1, st->base + st->index, &st->name, NULL);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
st->state = sw_start;
|
||||
@ -899,11 +895,15 @@ ngx_http_v3_parse_lookup(ngx_connection_t *c, ngx_uint_t dynamic,
|
||||
u_char *p;
|
||||
|
||||
if (!dynamic) {
|
||||
return ngx_http_v3_lookup_static(c, index, name, value);
|
||||
if (ngx_http_v3_lookup_static(c, index, name, value) != NGX_OK) {
|
||||
return NGX_HTTP_V3_ERR_DECOMPRESSION_FAILED;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (ngx_http_v3_lookup(c, index, name, value) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
return NGX_HTTP_V3_ERR_DECOMPRESSION_FAILED;
|
||||
}
|
||||
|
||||
if (name) {
|
||||
@ -940,6 +940,7 @@ ngx_http_v3_parse_control(ngx_connection_t *c, void *data, u_char ch)
|
||||
ngx_int_t rc;
|
||||
enum {
|
||||
sw_start = 0,
|
||||
sw_first_type,
|
||||
sw_type,
|
||||
sw_length,
|
||||
sw_settings,
|
||||
@ -953,10 +954,11 @@ ngx_http_v3_parse_control(ngx_connection_t *c, void *data, u_char ch)
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse control");
|
||||
|
||||
st->state = sw_type;
|
||||
st->state = sw_first_type;
|
||||
|
||||
/* fall through */
|
||||
|
||||
case sw_first_type:
|
||||
case sw_type:
|
||||
|
||||
if (ngx_http_v3_parse_varlen_int(c, &st->vlint, ch) != NGX_DONE) {
|
||||
@ -968,6 +970,12 @@ ngx_http_v3_parse_control(ngx_connection_t *c, void *data, u_char ch)
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
||||
"http3 parse frame type:%ui", st->type);
|
||||
|
||||
if (st->state == sw_first_type
|
||||
&& st->type != NGX_HTTP_V3_FRAME_SETTINGS)
|
||||
{
|
||||
return NGX_HTTP_V3_ERR_MISSING_SETTINGS;
|
||||
}
|
||||
|
||||
st->state = sw_length;
|
||||
break;
|
||||
|
||||
@ -1008,19 +1016,24 @@ ngx_http_v3_parse_control(ngx_connection_t *c, void *data, u_char ch)
|
||||
|
||||
rc = ngx_http_v3_parse_settings(c, &st->settings, ch);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
st->length--;
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
if (st->length == 0) {
|
||||
return NGX_HTTP_V3_ERR_SETTINGS_ERROR;
|
||||
}
|
||||
|
||||
if (--st->length > 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc != NGX_DONE) {
|
||||
return NGX_ERROR;
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (st->length == 0) {
|
||||
st->state = sw_type;
|
||||
}
|
||||
|
||||
st->state = sw_type;
|
||||
break;
|
||||
|
||||
case sw_max_push_id:
|
||||
@ -1085,7 +1098,7 @@ ngx_http_v3_parse_settings(ngx_connection_t *c,
|
||||
}
|
||||
|
||||
if (ngx_http_v3_set_param(c, st->id, st->vlint.value) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
return NGX_HTTP_V3_ERR_SETTINGS_ERROR;
|
||||
}
|
||||
|
||||
goto done;
|
||||
@ -1149,12 +1162,12 @@ ngx_http_v3_parse_encoder(ngx_connection_t *c, void *data, u_char ch)
|
||||
|
||||
rc = ngx_http_v3_parse_header_inr(c, &st->header, ch);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
if (rc == NGX_AGAIN) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc != NGX_DONE) {
|
||||
break;
|
||||
return rc;
|
||||
}
|
||||
|
||||
goto done;
|
||||
@ -1163,12 +1176,12 @@ ngx_http_v3_parse_encoder(ngx_connection_t *c, void *data, u_char ch)
|
||||
|
||||
rc = ngx_http_v3_parse_header_iwnr(c, &st->header, ch);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
if (rc == NGX_AGAIN) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc != NGX_DONE) {
|
||||
break;
|
||||
return rc;
|
||||
}
|
||||
|
||||
goto done;
|
||||
@ -1179,8 +1192,9 @@ ngx_http_v3_parse_encoder(ngx_connection_t *c, void *data, u_char ch)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ngx_http_v3_set_capacity(c, st->pint.value) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
rc = ngx_http_v3_set_capacity(c, st->pint.value);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
goto done;
|
||||
@ -1191,8 +1205,9 @@ ngx_http_v3_parse_encoder(ngx_connection_t *c, void *data, u_char ch)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ngx_http_v3_duplicate(c, st->pint.value) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
rc = ngx_http_v3_duplicate(c, st->pint.value);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
goto done;
|
||||
@ -1269,15 +1284,15 @@ ngx_http_v3_parse_header_inr(ngx_connection_t *c,
|
||||
|
||||
rc = ngx_http_v3_parse_literal(c, &st->literal, ch);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
st->value = st->literal.value;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (rc != NGX_AGAIN) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1290,9 +1305,9 @@ done:
|
||||
st->dynamic ? "dynamic" : "static",
|
||||
st->index, &st->value);
|
||||
|
||||
if (ngx_http_v3_ref_insert(c, st->dynamic, st->index, &st->value) != NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
rc = ngx_http_v3_ref_insert(c, st->dynamic, st->index, &st->value);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
st->state = sw_start;
|
||||
@ -1344,13 +1359,14 @@ ngx_http_v3_parse_header_iwnr(ngx_connection_t *c,
|
||||
|
||||
rc = ngx_http_v3_parse_literal(c, &st->literal, ch);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
st->name = st->literal.value;
|
||||
st->state = sw_value_len;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc != NGX_AGAIN) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -1380,15 +1396,15 @@ ngx_http_v3_parse_header_iwnr(ngx_connection_t *c,
|
||||
|
||||
rc = ngx_http_v3_parse_literal(c, &st->literal, ch);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
st->value = st->literal.value;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (rc != NGX_AGAIN) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1400,8 +1416,9 @@ done:
|
||||
"http3 parse header iwnr done \"%V\":\"%V\"",
|
||||
&st->name, &st->value);
|
||||
|
||||
if (ngx_http_v3_insert(c, &st->name, &st->value) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
rc = ngx_http_v3_insert(c, &st->name, &st->value);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
st->state = sw_start;
|
||||
@ -1414,6 +1431,7 @@ ngx_http_v3_parse_decoder(ngx_connection_t *c, void *data, u_char ch)
|
||||
{
|
||||
ngx_http_v3_parse_decoder_t *st = data;
|
||||
|
||||
ngx_int_t rc;
|
||||
enum {
|
||||
sw_start = 0,
|
||||
sw_ack_header,
|
||||
@ -1451,8 +1469,9 @@ ngx_http_v3_parse_decoder(ngx_connection_t *c, void *data, u_char ch)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ngx_http_v3_ack_header(c, st->pint.value) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
rc = ngx_http_v3_ack_header(c, st->pint.value);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
goto done;
|
||||
@ -1463,8 +1482,9 @@ ngx_http_v3_parse_decoder(ngx_connection_t *c, void *data, u_char ch)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ngx_http_v3_cancel_stream(c, st->pint.value) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
rc = ngx_http_v3_cancel_stream(c, st->pint.value);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
goto done;
|
||||
@ -1475,8 +1495,9 @@ ngx_http_v3_parse_decoder(ngx_connection_t *c, void *data, u_char ch)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ngx_http_v3_inc_insert_count(c, st->pint.value) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
rc = ngx_http_v3_inc_insert_count(c, st->pint.value);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
goto done;
|
||||
@ -1521,7 +1542,7 @@ ngx_http_v3_parse_data(ngx_connection_t *c, ngx_http_v3_parse_data_t *st,
|
||||
}
|
||||
|
||||
if (st->vlint.value != NGX_HTTP_V3_FRAME_DATA) {
|
||||
return NGX_ERROR;
|
||||
return NGX_HTTP_V3_ERR_FRAME_UNEXPECTED;
|
||||
}
|
||||
|
||||
st->state = sw_length;
|
||||
|
@ -112,6 +112,16 @@ typedef struct {
|
||||
} ngx_http_v3_parse_data_t;
|
||||
|
||||
|
||||
/*
|
||||
* Parse functions return codes:
|
||||
* NGX_DONE - parsing done
|
||||
* NGX_OK - sub-element done
|
||||
* NGX_AGAIN - more data expected
|
||||
* NGX_BUSY - waiting for external event
|
||||
* NGX_ERROR - internal error
|
||||
* NGX_HTTP_V3_ERROR_XXX - HTTP/3 or QPACK error
|
||||
*/
|
||||
|
||||
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,
|
||||
|
@ -66,6 +66,12 @@ ngx_http_v3_parse_request(ngx_http_request_t *r, ngx_buf_t *b)
|
||||
while (b->pos < b->last) {
|
||||
rc = ngx_http_v3_parse_headers(c, st, *b->pos);
|
||||
|
||||
if (rc > 0) {
|
||||
ngx_http_v3_finalize_connection(c, rc,
|
||||
"could not parse request headers");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
goto failed;
|
||||
}
|
||||
@ -180,6 +186,12 @@ ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b,
|
||||
while (b->pos < b->last) {
|
||||
rc = ngx_http_v3_parse_headers(c, st, *b->pos++);
|
||||
|
||||
if (rc > 0) {
|
||||
ngx_http_v3_finalize_connection(c, rc,
|
||||
"could not parse request headers");
|
||||
return NGX_HTTP_PARSE_INVALID_HEADER;
|
||||
}
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_HTTP_PARSE_INVALID_HEADER;
|
||||
}
|
||||
@ -359,6 +371,12 @@ ngx_http_v3_parse_request_body(ngx_http_request_t *r, ngx_buf_t *b,
|
||||
while (b->pos < b->last) {
|
||||
rc = ngx_http_v3_parse_data(c, st, *b->pos++);
|
||||
|
||||
if (rc > 0) {
|
||||
ngx_http_v3_finalize_connection(c, rc,
|
||||
"could not parse request body");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
goto failed;
|
||||
}
|
||||
|
@ -39,6 +39,8 @@ ngx_http_v3_handle_client_uni_stream(ngx_connection_t *c)
|
||||
|
||||
us = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_uni_stream_t));
|
||||
if (us == NULL) {
|
||||
ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
|
||||
NULL);
|
||||
ngx_http_v3_close_uni_stream(c);
|
||||
return;
|
||||
}
|
||||
@ -85,7 +87,7 @@ ngx_http_v3_read_uni_stream_type(ngx_event_t *rev)
|
||||
{
|
||||
u_char ch;
|
||||
ssize_t n;
|
||||
ngx_int_t index;
|
||||
ngx_int_t index, rc;
|
||||
ngx_connection_t *c;
|
||||
ngx_http_v3_connection_t *h3c;
|
||||
ngx_http_v3_uni_stream_t *us;
|
||||
@ -100,12 +102,18 @@ ngx_http_v3_read_uni_stream_type(ngx_event_t *rev)
|
||||
|
||||
n = c->recv(c, &ch, 1);
|
||||
|
||||
if (n == NGX_ERROR) {
|
||||
if (n == NGX_AGAIN) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
rc = NGX_HTTP_V3_ERR_GENERAL_PROTOCOL_ERROR;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (n == NGX_AGAIN || n != 1) {
|
||||
break;
|
||||
if (n != 1) {
|
||||
rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
switch (ch) {
|
||||
@ -154,6 +162,7 @@ ngx_http_v3_read_uni_stream_type(ngx_event_t *rev)
|
||||
if (index >= 0) {
|
||||
if (h3c->known_streams[index]) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0, "stream exists");
|
||||
rc = NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
@ -164,6 +173,7 @@ ngx_http_v3_read_uni_stream_type(ngx_event_t *rev)
|
||||
if (n) {
|
||||
us->data = ngx_pcalloc(c->pool, n);
|
||||
if (us->data == NULL) {
|
||||
rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
@ -174,6 +184,7 @@ ngx_http_v3_read_uni_stream_type(ngx_event_t *rev)
|
||||
}
|
||||
|
||||
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
|
||||
rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
@ -181,6 +192,7 @@ ngx_http_v3_read_uni_stream_type(ngx_event_t *rev)
|
||||
|
||||
failed:
|
||||
|
||||
ngx_http_v3_finalize_connection(c, rc, "could not read stream type");
|
||||
ngx_http_v3_close_uni_stream(c);
|
||||
}
|
||||
|
||||
@ -203,10 +215,22 @@ ngx_http_v3_uni_read_handler(ngx_event_t *rev)
|
||||
|
||||
n = c->recv(c, buf, sizeof(buf));
|
||||
|
||||
if (n == NGX_ERROR || n == 0) {
|
||||
if (n == NGX_ERROR) {
|
||||
rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
if (us->index >= 0) {
|
||||
rc = NGX_HTTP_V3_ERR_CLOSED_CRITICAL_STREAM;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 read eof");
|
||||
ngx_http_v3_close_uni_stream(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (n == NGX_AGAIN) {
|
||||
break;
|
||||
}
|
||||
@ -219,30 +243,34 @@ ngx_http_v3_uni_read_handler(ngx_event_t *rev)
|
||||
|
||||
rc = us->handler(c, us->data, buf[i]);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
||||
"http3 read done");
|
||||
ngx_http_v3_close_uni_stream(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc > 0) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
goto done;
|
||||
if (rc != NGX_AGAIN) {
|
||||
rc = NGX_HTTP_V3_ERR_GENERAL_PROTOCOL_ERROR;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* rc == NGX_AGAIN */
|
||||
}
|
||||
}
|
||||
|
||||
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
|
||||
rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
done:
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 read done");
|
||||
|
||||
failed:
|
||||
|
||||
ngx_http_v3_finalize_connection(c, rc, "stream error");
|
||||
ngx_http_v3_close_uni_stream(c);
|
||||
}
|
||||
|
||||
@ -257,6 +285,8 @@ ngx_http_v3_dummy_write_handler(ngx_event_t *wev)
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 dummy write handler");
|
||||
|
||||
if (ngx_handle_write_event(wev, 0) != NGX_OK) {
|
||||
ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
|
||||
NULL);
|
||||
ngx_http_v3_close_uni_stream(c);
|
||||
}
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ ngx_http_v3_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic,
|
||||
"http3 ref insert dynamic[%ui] \"%V\"", index, value);
|
||||
|
||||
if (ngx_http_v3_lookup(c, index, &name, NULL) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR;
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -175,7 +175,7 @@ ngx_http_v3_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic,
|
||||
"http3 ref insert static[%ui] \"%V\"", index, value);
|
||||
|
||||
if (ngx_http_v3_lookup_static(c, index, &name, NULL) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,7 +195,7 @@ ngx_http_v3_insert(ngx_connection_t *c, ngx_str_t *name, ngx_str_t *value)
|
||||
size = ngx_http_v3_table_entry_size(name, value);
|
||||
|
||||
if (ngx_http_v3_evict(c, size) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR;
|
||||
}
|
||||
|
||||
h3c = c->qs->parent->data;
|
||||
@ -257,14 +257,14 @@ ngx_http_v3_set_capacity(ngx_connection_t *c, ngx_uint_t capacity)
|
||||
if (capacity > v3cf->max_table_capacity) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||
"client exceeded http3_max_table_capacity limit");
|
||||
return NGX_ERROR;
|
||||
return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR;
|
||||
}
|
||||
|
||||
dt = &h3c->table;
|
||||
|
||||
if (dt->size > capacity) {
|
||||
if (ngx_http_v3_evict(c, dt->size - capacity) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@ -371,13 +371,13 @@ ngx_http_v3_duplicate(ngx_connection_t *c, ngx_uint_t index)
|
||||
dt = &h3c->table;
|
||||
|
||||
if (dt->base + dt->nelts <= index) {
|
||||
return NGX_ERROR;
|
||||
return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR;
|
||||
}
|
||||
|
||||
index = dt->base + dt->nelts - 1 - index;
|
||||
|
||||
if (ngx_http_v3_lookup(c, index, &name, &value) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
return NGX_HTTP_V3_ERR_ENCODER_STREAM_ERROR;
|
||||
}
|
||||
|
||||
return ngx_http_v3_insert(c, &name, &value);
|
||||
@ -515,7 +515,7 @@ ngx_http_v3_decode_insert_count(ngx_connection_t *c, ngx_uint_t *insert_count)
|
||||
full_range = 2 * max_entries;
|
||||
|
||||
if (*insert_count > full_range) {
|
||||
return NGX_ERROR;
|
||||
return NGX_HTTP_V3_ERR_DECOMPRESSION_FAILED;
|
||||
}
|
||||
|
||||
max_value = dt->base + dt->nelts + max_entries;
|
||||
@ -524,14 +524,14 @@ ngx_http_v3_decode_insert_count(ngx_connection_t *c, ngx_uint_t *insert_count)
|
||||
|
||||
if (req_insert_count > max_value) {
|
||||
if (req_insert_count <= full_range) {
|
||||
return NGX_ERROR;
|
||||
return NGX_HTTP_V3_ERR_DECOMPRESSION_FAILED;
|
||||
}
|
||||
|
||||
req_insert_count -= full_range;
|
||||
}
|
||||
|
||||
if (req_insert_count == 0) {
|
||||
return NGX_ERROR;
|
||||
return NGX_HTTP_V3_ERR_DECOMPRESSION_FAILED;
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
||||
@ -601,7 +601,7 @@ ngx_http_v3_check_insert_count(ngx_connection_t *c, ngx_uint_t insert_count)
|
||||
if (h3c->nblocked == v3cf->max_blocked_streams) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||
"client exceeded http3_max_blocked_streams limit");
|
||||
return NGX_ERROR;
|
||||
return NGX_HTTP_V3_ERR_DECOMPRESSION_FAILED;
|
||||
}
|
||||
|
||||
h3c->nblocked++;
|
||||
|
Loading…
Reference in New Issue
Block a user