> On 1 Feb 2023, at 18:01, Roman Arutyunyan <a...@nginx.com> wrote: > > # HG changeset patch > # User Roman Arutyunyan <a...@nginx.com> > # Date 1675254688 -14400 > # Wed Feb 01 16:31:28 2023 +0400 > # Branch quic > # Node ID 2fcc1c60be1c89aad5464bcc06f1189d1adc885a > # Parent def8e398d7c50131f8dac844814fff729da5c86c > HTTP/3: "quic" parameter of "listen" directive. > > Now "listen" directve has a new "quic" parameter which enables QUIC protocol > for the address. Further, to enable HTTP/3, a new directive "http3" is > introduced. The hq-interop protocol is enabled by "http3_hq" as before. > Now application protocol is chosen by ALPN. > > Previously used "http3" parameter of "listen" is deprecated.
Looks good in general, minor comments below. > > diff --git a/README b/README > --- a/README > +++ b/README > @@ -93,13 +93,13 @@ 2. Installing > > 3. Configuration > > - The HTTP "listen" directive got a new option "http3" which enables > - HTTP/3 over QUIC on the specified port. > + The HTTP "listen" directive got a new option "quic" which enables > + QUIC as client transport protocol instead of TCP. > > The Stream "listen" directive got a new option "quic" which enables > QUIC as client transport protocol instead of TCP or plain UDP. > > - Along with "http3" or "quic", it's also possible to specify "reuseport" > + Along with "quic", it's also possible to specify "reuseport" > option [8] to make it work properly with multiple workers. > > To enable address validation: > @@ -133,12 +133,13 @@ 3. Configuration > > A number of directives were added that configure HTTP/3: > > + http3 > + http3_hq > http3_stream_buffer_size > http3_max_concurrent_pushes > http3_max_concurrent_streams > http3_push > http3_push_preload > - http3_hq (requires NGX_HTTP_V3_HQ macro) > > In http, an additional variable is available: $http3. > The value of $http3 is "h3" for HTTP/3 connections, > @@ -160,13 +161,15 @@ Example configuration: > server { > # for better compatibility it's recommended > # to use the same port for quic and https > - listen 8443 http3 reuseport; > + listen 8443 quic reuseport; > listen 8443 ssl; > > ssl_certificate certs/example.com.crt; > ssl_certificate_key certs/example.com.key; > ssl_protocols TLSv1.3; > > + http3 on; > + > location / { > # required for browsers to direct them into quic port > add_header Alt-Svc 'h3=":8443"; ma=86400'; > diff --git a/src/http/modules/ngx_http_ssl_module.c > b/src/http/modules/ngx_http_ssl_module.c > --- a/src/http/modules/ngx_http_ssl_module.c > +++ b/src/http/modules/ngx_http_ssl_module.c > @@ -427,7 +427,7 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t > #if (NGX_HTTP_V2 || NGX_HTTP_V3) > ngx_http_connection_t *hc; > #endif > -#if (NGX_HTTP_V3 && NGX_HTTP_V3_HQ) > +#if (NGX_HTTP_V3) > ngx_http_v3_srv_conf_t *h3scf; > #endif > #if (NGX_HTTP_V2 || NGX_HTTP_V3 || NGX_DEBUG) > @@ -455,19 +455,26 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t > } else > #endif > #if (NGX_HTTP_V3) > - if (hc->addr_conf->http3) { > + if (hc->addr_conf->quic) { > > -#if (NGX_HTTP_V3_HQ) > h3scf = ngx_http_get_module_srv_conf(hc->conf_ctx, > ngx_http_v3_module); > > - if (h3scf->hq) { > + if (h3scf->enable && h3scf->enable_hq) { > + srv = (unsigned char *) NGX_HTTP_V3_ALPN_PROTO > + NGX_HTTP_V3_HQ_ALPN_PROTO; > + srvlen = sizeof(NGX_HTTP_V3_ALPN_PROTO NGX_HTTP_V3_HQ_ALPN_PROTO) > + - 1; > + > + } else if (h3scf->enable_hq) { > srv = (unsigned char *) NGX_HTTP_V3_HQ_ALPN_PROTO; > srvlen = sizeof(NGX_HTTP_V3_HQ_ALPN_PROTO) - 1; > - } else > -#endif > - { > + > + } else if (h3scf->enable || hc->addr_conf->http3) { > srv = (unsigned char *) NGX_HTTP_V3_ALPN_PROTO; > srvlen = sizeof(NGX_HTTP_V3_ALPN_PROTO) - 1; > + > + } else { > + return SSL_TLSEXT_ERR_ALERT_FATAL; > } > > } else > @@ -1313,12 +1320,12 @@ ngx_http_ssl_init(ngx_conf_t *cf) > addr = port[p].addrs.elts; > for (a = 0; a < port[p].addrs.nelts; a++) { > > - if (!addr[a].opt.ssl && !addr[a].opt.http3) { > + if (!addr[a].opt.ssl && !addr[a].opt.quic) { > continue; > } > > - if (addr[a].opt.http3) { > - name = "http3"; > + if (addr[a].opt.quic) { > + name = "quic"; > > } else { > name = "ssl"; > @@ -1329,7 +1336,7 @@ ngx_http_ssl_init(ngx_conf_t *cf) > > if (sscf->certificates) { > > - if (addr[a].opt.http3 && !(sscf->protocols & > NGX_SSL_TLSv1_3)) { > + if (addr[a].opt.quic && !(sscf->protocols & > NGX_SSL_TLSv1_3)) { > ngx_log_error(NGX_LOG_EMERG, cf->log, 0, > "\"ssl_protocols\" must enable TLSv1.3 for " > "the \"listen ... %s\" directive in %s:%ui", > diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c > --- a/src/http/ngx_http.c > +++ b/src/http/ngx_http.c > @@ -1242,6 +1242,7 @@ ngx_http_add_addresses(ngx_conf_t *cf, n > #endif > #if (NGX_HTTP_V3) > ngx_uint_t http3; > + ngx_uint_t quic; > #endif > > /* > @@ -1280,6 +1281,7 @@ ngx_http_add_addresses(ngx_conf_t *cf, n > #endif > #if (NGX_HTTP_V3) > http3 = lsopt->http3 || addr[i].opt.http3; > + quic = lsopt->quic || addr[i].opt.quic; > #endif > > if (lsopt->set) { > @@ -1319,6 +1321,7 @@ ngx_http_add_addresses(ngx_conf_t *cf, n > #endif > #if (NGX_HTTP_V3) > addr[i].opt.http3 = http3; > + addr[i].opt.quic = quic; > #endif > > return NGX_OK; > @@ -1823,7 +1826,7 @@ ngx_http_add_listening(ngx_conf_t *cf, n > > #if (NGX_HTTP_V3) > > - ls->quic = addr->opt.http3; > + ls->quic = addr->opt.quic; > > if (ls->quic) { > ngx_rbtree_init(&ls->rbtree, &ls->sentinel, > @@ -1866,6 +1869,7 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_h > #endif > #if (NGX_HTTP_V3) > addrs[i].conf.http3 = addr[i].opt.http3; > + addrs[i].conf.quic = addr[i].opt.quic; > #endif > addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; > > @@ -1934,6 +1938,7 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_ > #endif > #if (NGX_HTTP_V3) > addrs6[i].conf.http3 = addr[i].opt.http3; > + addrs6[i].conf.quic = addr[i].opt.quic; > #endif > addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; > > diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c > --- a/src/http/ngx_http_core_module.c > +++ b/src/http/ngx_http_core_module.c > @@ -4191,6 +4191,11 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx > > if (ngx_strcmp(value[n].data, "http3") == 0) { > #if (NGX_HTTP_V3) > + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, > + "the \"listen ... http3\" directive " > + "is deprecated, use " > + "the \"http3\" directive instead"); > + lsopt.quic = 1; It can be unclear that we need the "quic" parameter. > lsopt.http3 = 1; > lsopt.type = SOCK_DGRAM; > continue; > @@ -4202,6 +4207,19 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx > #endif > } > > + if (ngx_strcmp(value[n].data, "quic") == 0) { > +#if (NGX_HTTP_V3) > + lsopt.quic = 1; > + lsopt.type = SOCK_DGRAM; > + continue; > +#else > + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, > + "the \"quic\" parameter requires " > + "ngx_http_v3_module"); > + return NGX_CONF_ERROR; > +#endif > + } > + > if (ngx_strncmp(value[n].data, "so_keepalive=", 13) == 0) { > > if (ngx_strcmp(&value[n].data[13], "on") == 0) { > @@ -4304,8 +4322,8 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx > } > > #if (NGX_HTTP_SSL && NGX_HTTP_V3) > - if (lsopt.ssl && lsopt.http3) { > - return "\"ssl\" parameter is incompatible with \"http3\""; > + if (lsopt.ssl && lsopt.quic) { > + return "\"ssl\" parameter is incompatible with \"quic\""; > } > #endif > > diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h > --- a/src/http/ngx_http_core_module.h > +++ b/src/http/ngx_http_core_module.h > @@ -76,6 +76,7 @@ typedef struct { > unsigned ssl:1; > unsigned http2:1; > unsigned http3:1; > + unsigned quic:1; > #if (NGX_HAVE_INET6) > unsigned ipv6only:1; > #endif > @@ -240,6 +241,7 @@ struct ngx_http_addr_conf_s { > unsigned ssl:1; > unsigned http2:1; > unsigned http3:1; > + unsigned quic:1; > unsigned proxy_protocol:1; > }; > > diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c > --- a/src/http/ngx_http_request.c > +++ b/src/http/ngx_http_request.c > @@ -325,7 +325,7 @@ ngx_http_init_connection(ngx_connection_ > #endif > > #if (NGX_HTTP_V3) > - if (hc->addr_conf->http3) { > + if (hc->addr_conf->quic) { > ngx_http_v3_init_stream(c); > return; > } > 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 > @@ -17,12 +17,9 @@ static void ngx_http_v3_cleanup_session( > ngx_int_t > ngx_http_v3_init_session(ngx_connection_t *c) > { > - ngx_pool_cleanup_t *cln; > - ngx_http_connection_t *hc; > - ngx_http_v3_session_t *h3c; > -#if (NGX_HTTP_V3_HQ) > - ngx_http_v3_srv_conf_t *h3scf; > -#endif > + ngx_pool_cleanup_t *cln; > + ngx_http_connection_t *hc; > + ngx_http_v3_session_t *h3c; > > hc = c->data; > > @@ -36,13 +33,6 @@ ngx_http_v3_init_session(ngx_connection_ > h3c->max_push_id = (uint64_t) -1; > h3c->goaway_push_id = (uint64_t) -1; > > -#if (NGX_HTTP_V3_HQ) > - h3scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v3_module); > - if (h3scf->hq) { > - h3c->hq = 1; > - } > -#endif > - > 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 > @@ -21,6 +21,7 @@ > > #define NGX_HTTP_V3_ALPN_PROTO "\x02h3" > #define NGX_HTTP_V3_HQ_ALPN_PROTO "\x0Ahq-interop" > +#define NGX_HTTP_V3_HQ_PROTO "hq-interop" > > #define NGX_HTTP_V3_VARLEN_INT_LEN 4 > #define NGX_HTTP_V3_PREFIX_INT_LEN 11 > @@ -101,13 +102,12 @@ > > > typedef struct { > + ngx_flag_t enable; > + ngx_flag_t enable_hq; > size_t max_table_capacity; > ngx_uint_t max_blocked_streams; > ngx_uint_t max_concurrent_pushes; > ngx_uint_t max_concurrent_streams; > -#if (NGX_HTTP_V3_HQ) > - ngx_flag_t hq; > -#endif > ngx_quic_conf_t quic; > } ngx_http_v3_srv_conf_t; > > @@ -147,9 +147,7 @@ struct ngx_http_v3_session_s { > off_t payload_bytes; > > unsigned goaway:1; > -#if (NGX_HTTP_V3_HQ) > unsigned hq:1; > -#endif > > ngx_connection_t *known_streams[NGX_HTTP_V3_MAX_KNOWN_STREAM]; > }; > diff --git a/src/http/v3/ngx_http_v3_module.c > b/src/http/v3/ngx_http_v3_module.c > --- a/src/http/v3/ngx_http_v3_module.c > +++ b/src/http/v3/ngx_http_v3_module.c > @@ -32,6 +32,20 @@ static ngx_conf_post_t ngx_http_quic_mt > > static ngx_command_t ngx_http_v3_commands[] = { > > + { ngx_string("http3"), > + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, > + ngx_conf_set_flag_slot, > + NGX_HTTP_SRV_CONF_OFFSET, > + offsetof(ngx_http_v3_srv_conf_t, enable), > + NULL }, > + > + { ngx_string("http3_hq"), > + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, > + ngx_conf_set_flag_slot, > + NGX_HTTP_SRV_CONF_OFFSET, > + offsetof(ngx_http_v3_srv_conf_t, enable_hq), > + NULL }, > + > { ngx_string("http3_max_concurrent_pushes"), > NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, > ngx_conf_set_num_slot, > @@ -46,15 +60,6 @@ static ngx_command_t ngx_http_v3_comman > offsetof(ngx_http_v3_srv_conf_t, max_concurrent_streams), > NULL }, > > -#if (NGX_HTTP_V3_HQ) > - { ngx_string("http3_hq"), > - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, > - ngx_conf_set_flag_slot, > - NGX_HTTP_SRV_CONF_OFFSET, > - offsetof(ngx_http_v3_srv_conf_t, hq), > - NULL }, > -#endif > - > { ngx_string("http3_push"), > NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, > ngx_http_v3_push, > @@ -160,14 +165,12 @@ static ngx_int_t > ngx_http_v3_variable(ngx_http_request_t *r, > ngx_http_variable_value_t *v, uintptr_t data) > { > - if (r->connection->quic) { > -#if (NGX_HTTP_V3_HQ) > + ngx_http_v3_session_t *h3c; > > - ngx_http_v3_srv_conf_t *h3scf; > + if (r->connection->quic) { > + h3c = ngx_http_v3_get_session(r->connection); > > - h3scf = ngx_http_get_module_srv_conf(r, ngx_http_v3_module); > - > - if (h3scf->hq) { > + if (h3c->hq) { > v->len = sizeof("hq") - 1; > v->valid = 1; > v->no_cacheable = 0; > @@ -177,8 +180,6 @@ ngx_http_v3_variable(ngx_http_request_t > return NGX_OK; > } > > -#endif > - > v->len = sizeof("h3") - 1; > v->valid = 1; > v->no_cacheable = 0; > @@ -232,12 +233,12 @@ ngx_http_v3_create_srv_conf(ngx_conf_t * > * h3scf->quic.timeout = 0; > * h3scf->max_blocked_streams = 0; > */ > + > + h3scf->enable = NGX_CONF_UNSET; > + h3scf->enable_hq = NGX_CONF_UNSET; > h3scf->max_table_capacity = NGX_HTTP_V3_MAX_TABLE_CAPACITY; > h3scf->max_concurrent_pushes = NGX_CONF_UNSET_UINT; > h3scf->max_concurrent_streams = NGX_CONF_UNSET_UINT; > -#if (NGX_HTTP_V3_HQ) > - h3scf->hq = NGX_CONF_UNSET; > -#endif > > h3scf->quic.mtu = NGX_CONF_UNSET_SIZE; > h3scf->quic.stream_buffer_size = NGX_CONF_UNSET_SIZE; > @@ -264,6 +265,10 @@ ngx_http_v3_merge_srv_conf(ngx_conf_t *c > > ngx_http_ssl_srv_conf_t *sscf; > > + ngx_conf_merge_value(conf->enable, prev->enable, 0); > + > + ngx_conf_merge_value(conf->enable_hq, prev->enable_hq, 0); > + > ngx_conf_merge_uint_value(conf->max_concurrent_pushes, > prev->max_concurrent_pushes, 10); > > @@ -272,11 +277,6 @@ ngx_http_v3_merge_srv_conf(ngx_conf_t *c > > conf->max_blocked_streams = conf->max_concurrent_streams; > > -#if (NGX_HTTP_V3_HQ) > - ngx_conf_merge_value(conf->hq, prev->hq, 0); > -#endif > - > - > ngx_conf_merge_size_value(conf->quic.mtu, prev->quic.mtu, > NGX_QUIC_MAX_UDP_PAYLOAD_SIZE); > > diff --git a/src/http/v3/ngx_http_v3_request.c > b/src/http/v3/ngx_http_v3_request.c > --- a/src/http/v3/ngx_http_v3_request.c > +++ b/src/http/v3/ngx_http_v3_request.c > @@ -110,7 +110,10 @@ ngx_http_v3_init_stream(ngx_connection_t > ngx_int_t > ngx_http_v3_init(ngx_connection_t *c) > { > + unsigned int len; > + const unsigned char *data; > ngx_http_v3_session_t *h3c; > + ngx_http_v3_srv_conf_t *h3scf; > ngx_http_core_loc_conf_t *clcf; > > ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init"); > @@ -119,11 +122,23 @@ ngx_http_v3_init(ngx_connection_t *c) > clcf = ngx_http_v3_get_module_loc_conf(c, ngx_http_core_module); > ngx_add_timer(&h3c->keepalive, clcf->keepalive_timeout); > > -#if (NGX_HTTP_V3_HQ) > - if (h3c->hq) { > - return NGX_OK; > + h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module); > + > + if (h3scf->enable_hq) { > + if (!h3scf->enable) { > + h3c->hq = 1; > + return NGX_OK; > + } > + > + SSL_get0_alpn_selected(c->ssl->connection, &data, &len); > + > + if (len == sizeof(NGX_HTTP_V3_HQ_PROTO) - 1 > + && ngx_strncmp(data, NGX_HTTP_V3_HQ_PROTO, len) == 0) > + { > + h3c->hq = 1; > + return NGX_OK; > + } > } > -#endif > > return ngx_http_v3_send_settings(c); > } > @@ -147,10 +162,7 @@ ngx_http_v3_shutdown(ngx_connection_t *c > if (!h3c->goaway) { > h3c->goaway = 1; > > -#if (NGX_HTTP_V3_HQ) > - if (!h3c->hq) > -#endif > - { > + if (!h3c->hq) { > (void) ngx_http_v3_send_goaway(c, h3c->next_request_id); > } > > @@ -205,10 +217,7 @@ ngx_http_v3_init_request_stream(ngx_conn > { > h3c->goaway = 1; > > -#if (NGX_HTTP_V3_HQ) > - if (!h3c->hq) > -#endif > - { > + if (!h3c->hq) { > if (ngx_http_v3_send_goaway(c, h3c->next_request_id) != NGX_OK) { > ngx_http_close_connection(c); > return; > @@ -236,10 +245,7 @@ ngx_http_v3_init_request_stream(ngx_conn > > rev = c->read; > > -#if (NGX_HTTP_V3_HQ) > - if (!h3c->hq) > -#endif > - { > + if (!h3c->hq) { > rev->handler = ngx_http_v3_wait_request_handler; > c->write->handler = ngx_http_empty_handler; > } > @@ -398,14 +404,14 @@ ngx_http_v3_wait_request_handler(ngx_eve > void > ngx_http_v3_reset_stream(ngx_connection_t *c) > { > + ngx_http_v3_session_t *h3c; > ngx_http_v3_srv_conf_t *h3scf; > > h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module); > > - if (h3scf->max_table_capacity > 0 && !c->read->eof > -#if (NGX_HTTP_V3_HQ) > - && !h3scf->hq > -#endif > + h3c = ngx_http_v3_get_session(c); > + > + if (h3scf->max_table_capacity > 0 && !c->read->eof && !h3c->hq > && (c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0) > { > (void) ngx_http_v3_send_cancel_stream(c, c->quic->id); > @@ -993,9 +999,11 @@ failed: > static ngx_int_t > ngx_http_v3_process_request_header(ngx_http_request_t *r) > { > - ssize_t n; > - ngx_buf_t *b; > - ngx_connection_t *c; > + ssize_t n; > + ngx_buf_t *b; > + ngx_connection_t *c; > + ngx_http_v3_session_t *h3c; > + ngx_http_v3_srv_conf_t *h3scf; > > c = r->connection; > > @@ -1003,6 +1011,19 @@ ngx_http_v3_process_request_header(ngx_h > return NGX_ERROR; > } > > + h3c = ngx_http_v3_get_session(c); > + h3scf = ngx_http_get_module_srv_conf(r, ngx_http_v3_module); > + > + if (!r->http_connection->addr_conf->http3) { > + if ((h3c->hq && !h3scf->enable_hq) || (!h3c->hq && !h3scf->enable)) { can be reduced, hq is always false in the right part: if ((h3c->hq && !h3scf->enable_hq) || !h3scf->enable) { > + ngx_log_error(NGX_LOG_INFO, c->log, 0, > + "client attempted to request the server name " > + "for which the negotitated protocol is > unavailable"); typo: negotiated s/unavailable/disabled/ ? > + ngx_http_finalize_request(r, NGX_HTTP_MISDIRECTED_REQUEST); > + return NGX_ERROR; > + } > + } > + > if (ngx_http_v3_construct_cookie_header(r) != NGX_OK) { > return NGX_ERROR; > } > diff --git a/src/http/v3/ngx_http_v3_uni.c b/src/http/v3/ngx_http_v3_uni.c > --- a/src/http/v3/ngx_http_v3_uni.c > +++ b/src/http/v3/ngx_http_v3_uni.c > @@ -37,12 +37,9 @@ void > ngx_http_v3_init_uni_stream(ngx_connection_t *c) > { > uint64_t n; > -#if (NGX_HTTP_V3_HQ) > ngx_http_v3_session_t *h3c; > -#endif > ngx_http_v3_uni_stream_t *us; > > -#if (NGX_HTTP_V3_HQ) > h3c = ngx_http_v3_get_session(c); > if (h3c->hq) { > ngx_http_v3_finalize_connection(c, > @@ -52,7 +49,6 @@ ngx_http_v3_init_uni_stream(ngx_connecti > ngx_http_v3_close_uni_stream(c); > return; > } > -#endif > > ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init uni stream"); > -- Sergey Kandaurov _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org https://mailman.nginx.org/mailman/listinfo/nginx-devel