diff options
Diffstat (limited to 'src/http/v3/ngx_http_v3_streams.c')
-rw-r--r-- | src/http/v3/ngx_http_v3_streams.c | 692 |
1 files changed, 118 insertions, 574 deletions
diff --git a/src/http/v3/ngx_http_v3_streams.c b/src/http/v3/ngx_http_v3_streams.c index 2b757d81f..18e38a68d 100644 --- a/src/http/v3/ngx_http_v3_streams.c +++ b/src/http/v3/ngx_http_v3_streams.c @@ -10,42 +10,30 @@ #include <ngx_http.h> -#define NGX_HTTP_V3_CONTROL_STREAM 0x00 -#define NGX_HTTP_V3_PUSH_STREAM 0x01 -#define NGX_HTTP_V3_ENCODER_STREAM 0x02 -#define NGX_HTTP_V3_DECODER_STREAM 0x03 +typedef ngx_int_t (*ngx_http_v3_handler_pt)(ngx_connection_t *c, void *data, + u_char ch); typedef struct { - uint32_t signature; /* QSTR */ - u_char buf[4]; + uint32_t signature; /* QSTR */ - ngx_uint_t len; - ngx_uint_t type; - ngx_uint_t state; - ngx_uint_t index; - ngx_uint_t offset; + ngx_http_v3_handler_pt handler; + void *data; - ngx_str_t name; - ngx_str_t value; - - unsigned client:1; - unsigned dynamic:1; - unsigned huffman:1; + ngx_uint_t type; + ngx_uint_t client; /* unsigned client:1; */ } ngx_http_v3_uni_stream_t; static void ngx_http_v3_close_uni_stream(ngx_connection_t *c); static void ngx_http_v3_uni_stream_cleanup(void *data); static void ngx_http_v3_read_uni_stream_type(ngx_event_t *rev); -static void ngx_http_v3_dummy_stream_handler(ngx_event_t *rev); -static void ngx_http_v3_client_encoder_handler(ngx_event_t *rev); -static void ngx_http_v3_client_decoder_handler(ngx_event_t *rev); - +static void ngx_http_v3_uni_read_handler(ngx_event_t *rev); static ngx_connection_t *ngx_http_v3_create_uni_stream(ngx_connection_t *c, ngx_uint_t type); -static ngx_connection_t *ngx_http_v3_get_server_encoder(ngx_connection_t *c); -static ngx_connection_t *ngx_http_v3_get_server_decoder(ngx_connection_t *c); +static ngx_connection_t *ngx_http_v3_get_control(ngx_connection_t *c); +static ngx_connection_t *ngx_http_v3_get_encoder(ngx_connection_t *c); +static ngx_connection_t *ngx_http_v3_get_decoder(ngx_connection_t *c); void @@ -56,8 +44,13 @@ ngx_http_v3_handle_client_uni_stream(ngx_connection_t *c) c->log->connection = c->number; + /* XXX */ + (void) ngx_http_v3_get_control(c); + (void) ngx_http_v3_get_encoder(c); + (void) ngx_http_v3_get_decoder(c); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http3 new uni stream id:0x%uXL", c->qs->id); + "http3 new uni stream id:0x%uxL", c->qs->id); us = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_uni_stream_t)); if (us == NULL) { @@ -81,7 +74,7 @@ ngx_http_v3_handle_client_uni_stream(ngx_connection_t *c) cln->data = c; c->read->handler = ngx_http_v3_read_uni_stream_type; - c->read->handler(c->read); + ngx_http_v3_read_uni_stream_type(c->read); } @@ -115,7 +108,7 @@ ngx_http_v3_uni_stream_cleanup(void *data) switch (us->type) { - case NGX_HTTP_V3_ENCODER_STREAM: + case NGX_HTTP_V3_STREAM_ENCODER: if (us->client) { h3c->client_encoder = NULL; @@ -125,7 +118,7 @@ ngx_http_v3_uni_stream_cleanup(void *data) break; - case NGX_HTTP_V3_DECODER_STREAM: + case NGX_HTTP_V3_STREAM_DECODER: if (us->client) { h3c->client_decoder = NULL; @@ -134,482 +127,114 @@ ngx_http_v3_uni_stream_cleanup(void *data) } break; - } -} - - -static void -ngx_http_v3_read_uni_stream_type(ngx_event_t *rev) -{ - u_char *p; - ssize_t n, len; - ngx_connection_t *c; - ngx_http_v3_connection_t *h3c; - ngx_http_v3_uni_stream_t *us; - - c = rev->data; - us = c->data; - h3c = c->qs->parent->data; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 read stream type"); - - while (rev->ready) { - p = &us->buf[us->len]; + case NGX_HTTP_V3_STREAM_CONTROL: - if (us->len == 0) { - len = 1; + if (us->client) { + h3c->client_control = NULL; } else { - len = (us->buf[0] >> 6) + 1 - us->len; - } - - n = c->recv(c, p, len); - - if (n == NGX_ERROR) { - goto failed; - } - - if (n == NGX_AGAIN) { - break; - } - - us->len += n; - - if (n != len) { - break; - } - - if ((us->buf[0] >> 6) + 1 == us->len) { - us->type = ngx_http_v3_decode_varlen_int(us->buf); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http3 stream type:%ui", us->type); - - switch (us->type) { - - case NGX_HTTP_V3_ENCODER_STREAM: - if (h3c->client_encoder) { - goto failed; - } - - h3c->client_encoder = c; - rev->handler = ngx_http_v3_client_encoder_handler; - break; - - case NGX_HTTP_V3_DECODER_STREAM: - if (h3c->client_decoder) { - goto failed; - } - - h3c->client_decoder = c; - rev->handler = ngx_http_v3_client_decoder_handler; - break; - - case NGX_HTTP_V3_CONTROL_STREAM: - case NGX_HTTP_V3_PUSH_STREAM: - - /* ignore these */ - - default: - rev->handler = ngx_http_v3_dummy_stream_handler; - } - - rev->handler(rev); - return; + h3c->server_control = NULL; } - } - - if (ngx_handle_read_event(rev, 0) != NGX_OK) { - goto failed; - } - - return; -failed: - - ngx_http_v3_close_uni_stream(c); -} - - -static void -ngx_http_v3_dummy_stream_handler(ngx_event_t *rev) -{ - u_char buf[128]; - ngx_connection_t *c; - - /* read out and ignore */ - - c = rev->data; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 dummy stream reader"); - - while (rev->ready) { - if (c->recv(c, buf, sizeof(buf)) == NGX_ERROR) { - goto failed; - } - } - - if (ngx_handle_read_event(rev, 0) != NGX_OK) { - goto failed; + break; } - - return; - -failed: - - ngx_http_v3_close_uni_stream(c); } static void -ngx_http_v3_client_encoder_handler(ngx_event_t *rev) +ngx_http_v3_read_uni_stream_type(ngx_event_t *rev) { - u_char v; + u_char ch; ssize_t n; - ngx_str_t name, value; - ngx_uint_t dynamic, huffman, index, offset; - ngx_connection_t *c, *pc; + ngx_connection_t *c; + ngx_http_v3_connection_t *h3c; ngx_http_v3_uni_stream_t *st; - enum { - sw_start = 0, - sw_inr_name_index, - sw_inr_value_length, - sw_inr_read_value_length, - sw_inr_value, - sw_iwnr_name_length, - sw_iwnr_name, - sw_iwnr_value_length, - sw_iwnr_read_value_length, - sw_iwnr_value, - sw_capacity, - sw_duplicate - } state; c = rev->data; st = c->data; - pc = c->qs->parent; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 client encoder"); + h3c = c->qs->parent->data; - state = st->state; - dynamic = st->dynamic; - huffman = st->huffman; - index = st->index; - offset = st->offset; - name = st->name; - value = st->value; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 read stream type"); while (rev->ready) { - /* XXX limit checks */ - /* XXX buffer input */ - - n = c->recv(c, &v, 1); + n = c->recv(c, &ch, 1); - if (n == NGX_ERROR || n == 0) { + if (n == NGX_ERROR) { goto failed; } - if (n != 1) { + if (n == NGX_AGAIN || n != 1) { break; } - /* XXX v -> ch */ - - switch (state) { - - case sw_start: - - if (v & 0x80) { - /* Insert With Name Reference */ - - dynamic = (v & 0x40) ? 0 : 1; - index = v & 0x3f; - - if (index != 0x3f) { - state = sw_inr_value_length; - break; - } - - index = 0; - state = sw_inr_name_index; - break; - } - - if (v & 0x40) { - /* Insert Without Name Reference */ - - huffman = (v & 0x20) ? 1 : 0; - name.len = v & 0x1f; - - if (name.len != 0x1f) { - offset = 0; - state = sw_iwnr_name; - break; - } - - name.len = 0; - state = sw_iwnr_name_length; - break; - } - - if (v & 0x20) { - /* Set Dynamic Table Capacity */ - - index = v & 0x1f; - - if (index != 0x1f) { - if (ngx_http_v3_set_capacity(c, index) != NGX_OK) { - goto failed; - } - - break; - } - - index = 0; - state = sw_capacity; - break; - } - - /* Duplicate */ - - index = v & 0x1f; - - if (index != 0x1f) { - if (ngx_http_v3_duplicate(c, index) != NGX_OK) { - goto failed; - } - - break; - } - - index = 0; - state = sw_duplicate; - break; - - case sw_inr_name_index: - - index = (index << 7) + (v & 0x7f); - if (v & 0x80) { - break; - } - - index += 0x3f; - state = sw_inr_value_length; - break; - - case sw_inr_value_length: - - huffman = (v & 0x80) ? 1 : 0; - value.len = v & 0x7f; - - if (value.len == 0) { - value.data = NULL; - - if (ngx_http_v3_ref_insert(c, dynamic, index, &value) != NGX_OK) - { - goto failed; - } - - state = sw_start; - break; - } - - if (value.len != 0x7f) { - value.data = ngx_pnalloc(pc->pool, value.len); - if (value.data == NULL) { - goto failed; - } - - state = sw_inr_value; - offset = 0; - break; - } + st->type = ch; - value.len = 0; - state = sw_inr_read_value_length; - break; - - case sw_inr_read_value_length: + switch (st->type) { - value.len = (value.len << 7) + (v & 0x7f); - if (v & 0x80) { - break; - } + case NGX_HTTP_V3_STREAM_ENCODER: - value.len += 0x7f; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 encoder stream"); - value.data = ngx_pnalloc(pc->pool, value.len); - if (value.data == NULL) { + if (h3c->client_encoder) { goto failed; } - state = sw_inr_value; - offset = 0; - break; - - case sw_inr_value: - - value.data[offset++] = v; - if (offset != value.len) { - break; - } - - if (huffman) { - if (ngx_http_v3_decode_huffman(pc, &value) != NGX_OK) { - goto failed; - } - } - - if (ngx_http_v3_ref_insert(c, dynamic, index, &value) != NGX_OK) { - goto failed; - } + h3c->client_encoder = c; + st->handler = ngx_http_v3_parse_encoder; + n = sizeof(ngx_http_v3_parse_encoder_t); - state = sw_start; break; - case sw_iwnr_name_length: + case NGX_HTTP_V3_STREAM_DECODER: - name.len = (name.len << 7) + (v & 0x7f); - if (v & 0x80) { - break; - } - - name.len += 0x1f; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 decoder stream"); - name.data = ngx_pnalloc(pc->pool, name.len); - if (name.data == NULL) { + if (h3c->client_decoder) { goto failed; } - offset = 0; - state = sw_iwnr_name; - break; - - case sw_iwnr_name: - - name.data[offset++] = v; - if (offset != name.len) { - break; - } - - if (huffman) { - if (ngx_http_v3_decode_huffman(pc, &name) != NGX_OK) { - goto failed; - } - } - - state = sw_iwnr_value_length; - break; - - case sw_iwnr_value_length: - - huffman = (v & 0x80) ? 1 : 0; - value.len = v & 0x7f; - - if (value.len == 0) { - value.data = NULL; - - if (ngx_http_v3_insert(c, &name, &value) != NGX_OK) { - goto failed; - } - - state = sw_start; - break; - } - - if (value.len != 0x7f) { - value.data = ngx_pnalloc(pc->pool, value.len); - if (value.data == NULL) { - goto failed; - } - - offset = 0; - state = sw_iwnr_value; - break; - } - - state = sw_iwnr_read_value_length; - break; - - case sw_iwnr_read_value_length: - - value.len = (value.len << 7) + (v & 0x7f); - if (v & 0x80) { - break; - } - - value.data = ngx_pnalloc(pc->pool, value.len); - if (value.data == NULL) { - goto failed; - } + h3c->client_decoder = c; + st->handler = ngx_http_v3_parse_decoder; + n = sizeof(ngx_http_v3_parse_decoder_t); - offset = 0; - state = sw_iwnr_value; break; - case sw_iwnr_value: - - value.data[offset++] = v; - if (offset != value.len) { - break; - } + case NGX_HTTP_V3_STREAM_CONTROL: - if (huffman) { - if (ngx_http_v3_decode_huffman(pc, &value) != NGX_OK) { - goto failed; - } - } + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 control stream"); - if (ngx_http_v3_insert(c, &name, &value) != NGX_OK) { + if (h3c->client_control) { goto failed; } - state = sw_start; - break; - - - case sw_capacity: - - index = (index << 7) + (v & 0x7f); - if (v & 0x80) { - break; - } - - index += 0x1f; + h3c->client_control = c; + st->handler = ngx_http_v3_parse_control; + n = sizeof(ngx_http_v3_parse_control_t); - if (ngx_http_v3_set_capacity(c, index) != NGX_OK) { - goto failed; - } - - state = sw_start; break; - case sw_duplicate: - - index = (index << 7) + (v & 0x7f); - if (v & 0x80) { - break; - } + default: - index += 0x1f; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 stream 0x%02xi", st->type); + n = 0; + } - if (ngx_http_v3_duplicate(c, index) != NGX_OK) { + if (n) { + st->data = ngx_pcalloc(c->pool, n); + if (st->data == NULL) { goto failed; } - - state = sw_start; - break; } - } - st->state = state; - st->dynamic = dynamic; - st->huffman = huffman; - st->index = index; - st->offset = offset; - st->name = name; - st->value = value; + rev->handler = ngx_http_v3_uni_read_handler; + ngx_http_v3_uni_read_handler(rev); + return; + } if (ngx_handle_read_event(rev, 0) != NGX_OK) { goto failed; @@ -624,158 +249,61 @@ failed: static void -ngx_http_v3_client_decoder_handler(ngx_event_t *rev) +ngx_http_v3_uni_read_handler(ngx_event_t *rev) { - u_char v; + u_char buf[128]; ssize_t n; - ngx_uint_t index; + ngx_int_t rc, i; ngx_connection_t *c; ngx_http_v3_uni_stream_t *st; - enum { - sw_start = 0, - sw_ack_header, - sw_cancel_stream, - sw_inc_insert_count - } state; c = rev->data; st = c->data; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 client decoder"); - - state = st->state; - index = st->index; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 read handler"); while (rev->ready) { - /* XXX limit checks */ - /* XXX buffer input */ - - n = c->recv(c, &v, 1); + n = c->recv(c, buf, sizeof(buf)); if (n == NGX_ERROR || n == 0) { goto failed; } - if (n != 1) { + if (n == NGX_AGAIN) { break; } - switch (state) { - - case sw_start: - - if (v & 0x80) { - /* Header Acknowledgement */ - - index = v & 0x7f; - - if (index != 0x7f) { - if (ngx_http_v3_ack_header(c, index) != NGX_OK) { - goto failed; - } - - break; - } - - index = 0; - state = sw_ack_header; - break; - } - - if (v & 0x40) { - /* Stream Cancellation */ - - index = v & 0x3f; - - if (index != 0x3f) { - if (ngx_http_v3_cancel_stream(c, index) != NGX_OK) { - goto failed; - } - - break; - } - - index = 0; - state = sw_cancel_stream; - break; - } - - /* Insert Count Increment */ - - index = v & 0x3f; - - if (index != 0x3f) { - if (ngx_http_v3_inc_insert_count(c, index) != NGX_OK) { - goto failed; - } - - break; - } - - index = 0; - state = sw_inc_insert_count; - break; - - case sw_ack_header: - - index = (index << 7) + (v & 0x7f); - if (v & 0x80) { - break; - } - - index += 0x7f; - - if (ngx_http_v3_ack_header(c, index) != NGX_OK) { - goto failed; - } - - state = sw_start; - break; - - case sw_cancel_stream: + if (st->handler == NULL) { + continue; + } - index = (index << 7) + (v & 0x7f); - if (v & 0x80) { - break; - } + for (i = 0; i < n; i++) { - index += 0x3f; + rc = st->handler(c, st->data, buf[i]); - if (ngx_http_v3_cancel_stream(c, index) != NGX_OK) { + if (rc == NGX_ERROR) { goto failed; } - state = sw_start; - break; - - case sw_inc_insert_count: - - index = (index << 7) + (v & 0x7f); - if (v & 0x80) { - break; - } - - index += 0x3f; - - if (ngx_http_v3_inc_insert_count(c, index) != NGX_OK) { - goto failed; + if (rc == NGX_DONE) { + goto done; } - state = sw_start; - break; + /* rc == NGX_AGAIN */ } } - st->state = state; - st->index = index; - if (ngx_handle_read_event(rev, 0) != NGX_OK) { goto failed; } return; +done: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 read done"); + failed: ngx_http_v3_close_uni_stream(c); @@ -835,7 +363,7 @@ failed: static ngx_connection_t * -ngx_http_v3_get_server_encoder(ngx_connection_t *c) +ngx_http_v3_get_control(ngx_connection_t *c) { ngx_http_v3_connection_t *h3c; @@ -843,7 +371,7 @@ ngx_http_v3_get_server_encoder(ngx_connection_t *c) if (h3c->server_encoder == NULL) { h3c->server_encoder = ngx_http_v3_create_uni_stream(c, - NGX_HTTP_V3_ENCODER_STREAM); + NGX_HTTP_V3_STREAM_CONTROL); } return h3c->server_encoder; @@ -851,18 +379,34 @@ ngx_http_v3_get_server_encoder(ngx_connection_t *c) static ngx_connection_t * -ngx_http_v3_get_server_decoder(ngx_connection_t *c) +ngx_http_v3_get_encoder(ngx_connection_t *c) { ngx_http_v3_connection_t *h3c; h3c = c->qs->parent->data; - if (h3c->server_decoder == NULL) { - h3c->server_decoder = ngx_http_v3_create_uni_stream(c, - NGX_HTTP_V3_DECODER_STREAM); + if (h3c->server_encoder == NULL) { + h3c->server_encoder = ngx_http_v3_create_uni_stream(c, + NGX_HTTP_V3_STREAM_ENCODER); } - return h3c->server_decoder; + return h3c->server_encoder; +} + + +static ngx_connection_t * +ngx_http_v3_get_decoder(ngx_connection_t *c) +{ + ngx_http_v3_connection_t *h3c; + + h3c = c->qs->parent->data; + + if (h3c->server_encoder == NULL) { + h3c->server_encoder = ngx_http_v3_create_uni_stream(c, + NGX_HTTP_V3_STREAM_DECODER); + } + + return h3c->server_encoder; } @@ -878,7 +422,7 @@ ngx_http_v3_client_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic, "http3 client ref insert, %s[%ui] \"%V\"", dynamic ? "dynamic" : "static", index, value); - ec = ngx_http_v3_get_server_encoder(c); + ec = ngx_http_v3_get_encoder(c); if (ec == NULL) { return NGX_ERROR; } @@ -923,7 +467,7 @@ ngx_http_v3_client_insert(ngx_connection_t *c, ngx_str_t *name, ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 client insert \"%V\":\"%V\"", name, value); - ec = ngx_http_v3_get_server_encoder(c); + ec = ngx_http_v3_get_encoder(c); if (ec == NULL) { return NGX_ERROR; } @@ -972,7 +516,7 @@ ngx_http_v3_client_set_capacity(ngx_connection_t *c, ngx_uint_t capacity) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 client set capacity %ui", capacity); - ec = ngx_http_v3_get_server_encoder(c); + ec = ngx_http_v3_get_encoder(c); if (ec == NULL) { return NGX_ERROR; } @@ -999,7 +543,7 @@ ngx_http_v3_client_duplicate(ngx_connection_t *c, ngx_uint_t index) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 client duplicate %ui", index); - ec = ngx_http_v3_get_server_encoder(c); + ec = ngx_http_v3_get_encoder(c); if (ec == NULL) { return NGX_ERROR; } @@ -1026,7 +570,7 @@ ngx_http_v3_client_ack_header(ngx_connection_t *c, ngx_uint_t stream_id) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 client ack header %ui", stream_id); - dc = ngx_http_v3_get_server_decoder(c); + dc = ngx_http_v3_get_decoder(c); if (dc == NULL) { return NGX_ERROR; } @@ -1053,7 +597,7 @@ ngx_http_v3_client_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 client cancel stream %ui", stream_id); - dc = ngx_http_v3_get_server_decoder(c); + dc = ngx_http_v3_get_decoder(c); if (dc == NULL) { return NGX_ERROR; } @@ -1080,7 +624,7 @@ ngx_http_v3_client_inc_insert_count(ngx_connection_t *c, ngx_uint_t inc) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 client increment insert count %ui", inc); - dc = ngx_http_v3_get_server_decoder(c); + dc = ngx_http_v3_get_decoder(c); if (dc == NULL) { return NGX_ERROR; } |