# HG changeset patch # User Roman Arutyunyan # Date 1623407064 -10800 # Node ID 1fec68e322d0193b8b5aa28ddba94d30ac3266f7 # Parent 278ab0ed24f2cf9a8fc7fe740aadfad0901fc6e1 HTTP/3: client GOAWAY support. diff --git a/src/http/v3/ngx_http_v3.c b/src/http/v3/ngx_http_v3.c --- a/src/http/v3/ngx_http_v3.c +++ b/src/http/v3/ngx_http_v3.c @@ -37,6 +37,7 @@ ngx_http_v3_init_session(ngx_connection_ } h3c->max_push_id = (uint64_t) -1; + h3c->goaway_push_id = (uint64_t) -1; ngx_queue_init(&h3c->blocked); ngx_queue_init(&h3c->pushing); diff --git a/src/http/v3/ngx_http_v3.h b/src/http/v3/ngx_http_v3.h --- a/src/http/v3/ngx_http_v3.h +++ b/src/http/v3/ngx_http_v3.h @@ -129,6 +129,7 @@ struct ngx_http_v3_session_s { ngx_uint_t npushing; uint64_t next_push_id; uint64_t max_push_id; + uint64_t goaway_push_id; ngx_uint_t goaway; /* unsigned goaway:1; */ diff --git a/src/http/v3/ngx_http_v3_filter_module.c b/src/http/v3/ngx_http_v3_filter_module.c --- a/src/http/v3/ngx_http_v3_filter_module.c +++ b/src/http/v3/ngx_http_v3_filter_module.c @@ -805,6 +805,12 @@ ngx_http_v3_push_resource(ngx_http_reque return NGX_ABORT; } + if (h3c->goaway_push_id != (uint64_t) -1) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http3 abort pushes due to goaway"); + return NGX_ABORT; + } + if (h3c->npushing >= h3scf->max_concurrent_pushes) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 abort pushes due to max_concurrent_pushes"); diff --git a/src/http/v3/ngx_http_v3_parse.c b/src/http/v3/ngx_http_v3_parse.c --- a/src/http/v3/ngx_http_v3_parse.c +++ b/src/http/v3/ngx_http_v3_parse.c @@ -1012,6 +1012,7 @@ ngx_http_v3_parse_control(ngx_connection sw_cancel_push, sw_settings, sw_max_push_id, + sw_goaway, sw_skip }; @@ -1091,6 +1092,10 @@ ngx_http_v3_parse_control(ngx_connection st->state = sw_max_push_id; break; + case NGX_HTTP_V3_FRAME_GOAWAY: + st->state = sw_goaway; + break; + default: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse skip unknown frame"); @@ -1157,6 +1162,26 @@ ngx_http_v3_parse_control(ngx_connection st->state = sw_type; break; + case sw_goaway: + + rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, ch); + + if (--st->length == 0 && rc == NGX_AGAIN) { + return NGX_HTTP_V3_ERR_FRAME_ERROR; + } + + if (rc != NGX_DONE) { + return rc; + } + + rc = ngx_http_v3_goaway(c, st->vlint.value); + if (rc != NGX_OK) { + return rc; + } + + st->state = sw_type; + break; + case sw_skip: if (--st->length == 0) { diff --git a/src/http/v3/ngx_http_v3_streams.c b/src/http/v3/ngx_http_v3_streams.c --- a/src/http/v3/ngx_http_v3_streams.c +++ b/src/http/v3/ngx_http_v3_streams.c @@ -704,6 +704,21 @@ ngx_http_v3_set_max_push_id(ngx_connecti ngx_int_t +ngx_http_v3_goaway(ngx_connection_t *c, uint64_t push_id) +{ + ngx_http_v3_session_t *h3c; + + h3c = ngx_http_v3_get_session(c); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 GOAWAY:%uL", push_id); + + h3c->goaway_push_id = push_id; + + return NGX_OK; +} + + +ngx_int_t ngx_http_v3_cancel_push(ngx_connection_t *c, uint64_t push_id) { ngx_queue_t *q; diff --git a/src/http/v3/ngx_http_v3_streams.h b/src/http/v3/ngx_http_v3_streams.h --- a/src/http/v3/ngx_http_v3_streams.h +++ b/src/http/v3/ngx_http_v3_streams.h @@ -21,6 +21,7 @@ ngx_connection_t *ngx_http_v3_create_pus uint64_t push_id); ngx_int_t ngx_http_v3_set_max_push_id(ngx_connection_t *c, uint64_t max_push_id); +ngx_int_t ngx_http_v3_goaway(ngx_connection_t *c, uint64_t push_id); ngx_int_t ngx_http_v3_cancel_push(ngx_connection_t *c, uint64_t push_id); ngx_int_t ngx_http_v3_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id);