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;
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_AGAIN) {
+ break;
}
if (rc != NGX_DONE) {
- break;
+ return rc;
}
if (st->length == 0) {
- return NGX_ERROR;
+ return NGX_HTTP_V3_ERR_FRAME_ERROR;
}
st->state = sw_verify;
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;
}
- goto done;
+ break;
}
- if (rc == NGX_DONE) {
- return NGX_OK;
+ if (rc != NGX_DONE) {
+ return rc;
}
- break;
+ if (st->length == 0) {
+ goto done;
+ }
+
+ return NGX_OK;
}
return NGX_AGAIN;
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,
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) {
rc = NGX_OK;
}
- if (rc == NGX_ERROR) {
- return NGX_ERROR;
- }
-
- if (rc == NGX_AGAIN) {
- return NGX_AGAIN;
+ if (rc != NGX_DONE) {
+ return rc;
}
- /* rc == NGX_DONE */
-
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http3 parse header representation done");
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) {
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
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;
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;
}
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;
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;
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;
}
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
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;
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;
}
"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;
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) {
ngx_int_t rc;
enum {
sw_start = 0,
+ sw_first_type,
sw_type,
sw_length,
sw_settings,
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) {
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;
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:
}
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;
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;
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;
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;
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;
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;
}
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;
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;
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;
}
"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;
{
ngx_http_v3_parse_decoder_t *st = data;
+ ngx_int_t rc;
enum {
sw_start = 0,
sw_ack_header,
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;
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;
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;
}
if (st->vlint.value != NGX_HTTP_V3_FRAME_DATA) {
- return NGX_ERROR;
+ return NGX_HTTP_V3_ERR_FRAME_UNEXPECTED;
}
st->state = sw_length;
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;
}
{
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;
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) {
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;
}
if (n) {
us->data = ngx_pcalloc(c->pool, n);
if (us->data == NULL) {
+ rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
goto failed;
}
}
}
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
+ rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
goto failed;
}
failed:
+ ngx_http_v3_finalize_connection(c, rc, "could not read stream type");
ngx_http_v3_close_uni_stream(c);
}
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;
}
rc = us->handler(c, us->data, buf[i]);
- if (rc == NGX_ERROR) {
- goto failed;
+ 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 == NGX_DONE) {
- goto done;
+ if (rc > 0) {
+ goto failed;
}
- /* rc == NGX_AGAIN */
+ if (rc != NGX_AGAIN) {
+ rc = NGX_HTTP_V3_ERR_GENERAL_PROTOCOL_ERROR;
+ goto failed;
+ }
}
}
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);
}
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);
}
}
"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 {
"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;
}
}
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;
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;
}
}
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);
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;
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,
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++;