# HG changeset patch # User Roman Arutyunyan # Date 1595362162 -10800 # Node ID 0d2b2664b41c11a3632fbbb26548001f66ae233d # Parent f537f99b86ee5155b9bc55dc8806275e7694f614 QUIC: added "quic" listen parameter. The parameter allows processing HTTP/0.9-2 over QUIC. Also, introduced ngx_http_quic_module and moved QUIC settings there diff --git a/auto/lib/openssl/conf b/auto/lib/openssl/conf --- a/auto/lib/openssl/conf +++ b/auto/lib/openssl/conf @@ -166,6 +166,7 @@ END exit 1 fi + have=NGX_QUIC . auto/have fi diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -404,12 +404,9 @@ if [ $HTTP = YES ]; then ngx_module_type=HTTP if [ $HTTP_V3 = YES ]; then - USE_OPENSSL=YES - USE_OPENSSL_QUIC=YES have=NGX_HTTP_V3 . auto/have have=NGX_HTTP_HEADERS . auto/have - - HTTP_SSL=YES + HTTP_QUIC=YES # XXX for Huffman HTTP_V2=YES @@ -696,6 +693,21 @@ if [ $HTTP = YES ]; then . auto/module fi + if [ $HTTP_QUIC = YES ]; then + USE_OPENSSL_QUIC=YES + have=NGX_HTTP_QUIC . auto/have + HTTP_SSL=YES + + ngx_module_name=ngx_http_quic_module + ngx_module_incs= + ngx_module_deps=src/http/modules/ngx_http_quic_module.h + ngx_module_srcs=src/http/modules/ngx_http_quic_module.c + ngx_module_libs= + ngx_module_link=$HTTP_QUIC + + . auto/module + fi + if [ $HTTP_SSL = YES ]; then USE_OPENSSL=YES have=NGX_HTTP_SSL . auto/have diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -58,6 +58,7 @@ HTTP_CACHE=YES HTTP_CHARSET=YES HTTP_GZIP=YES HTTP_SSL=NO +HTTP_QUIC=NO HTTP_V2=NO HTTP_V3=NO HTTP_SSI=YES @@ -225,6 +226,7 @@ do --http-scgi-temp-path=*) NGX_HTTP_SCGI_TEMP_PATH="$value" ;; --with-http_ssl_module) HTTP_SSL=YES ;; + --with-http_quic_module) HTTP_QUIC=YES ;; --with-http_v2_module) HTTP_V2=YES ;; --with-http_v3_module) HTTP_V3=YES ;; --with-http_realip_module) HTTP_REALIP=YES ;; @@ -441,6 +443,7 @@ cat << END --with-file-aio enable file AIO support --with-http_ssl_module enable ngx_http_ssl_module + --with-http_quic_module enable ngx_http_quic_module --with-http_v2_module enable ngx_http_v2_module --with-http_v3_module enable ngx_http_v3_module --with-http_realip_module enable ngx_http_realip_module diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -1034,9 +1034,11 @@ ngx_close_listening_sockets(ngx_cycle_t ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { +#if (NGX_QUIC) if (ls[i].quic) { continue; } +#endif c = ls[i].connection; diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -150,9 +150,12 @@ struct ngx_connection_s { ngx_proxy_protocol_t *proxy_protocol; -#if (NGX_SSL || NGX_COMPAT) +#if (NGX_QUIC || NGX_COMPAT) ngx_quic_connection_t *quic; ngx_quic_stream_t *qs; +#endif + +#if (NGX_SSL || NGX_COMPAT) ngx_ssl_connection_t *ssl; #endif diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -268,6 +268,8 @@ ngx_process_events_and_timers(ngx_cycle_ ngx_int_t ngx_handle_read_event(ngx_event_t *rev, ngx_uint_t flags) { +#if (NGX_QUIC) + ngx_connection_t *c; c = rev->data; @@ -284,6 +286,8 @@ ngx_handle_read_event(ngx_event_t *rev, return NGX_OK; } +#endif + if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { /* kqueue, epoll */ @@ -362,6 +366,8 @@ ngx_handle_write_event(ngx_event_t *wev, } } +#if (NGX_QUIC) + if (c->qs) { if (!wev->active && !wev->ready) { @@ -374,6 +380,8 @@ ngx_handle_write_event(ngx_event_t *wev, return NGX_OK; } +#endif + if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { /* kqueue, epoll */ @@ -944,9 +952,11 @@ ngx_send_lowat(ngx_connection_t *c, size { int sndlowat; +#if (NGX_QUIC) if (c->qs) { return NGX_OK; } +#endif #if (NGX_HAVE_LOWAT_EVENT) diff --git a/src/event/ngx_event_quic.c b/src/event/ngx_event_quic.c --- a/src/event/ngx_event_quic.c +++ b/src/event/ngx_event_quic.c @@ -93,6 +93,8 @@ struct ngx_quic_connection_s { ngx_quic_secrets_t next_key; ngx_quic_frames_stream_t crypto[NGX_QUIC_ENCRYPTION_LAST]; + ngx_quic_conf_t *conf; + ngx_ssl_t *ssl; ngx_event_t push; @@ -160,7 +162,7 @@ static int ngx_quic_send_alert(ngx_ssl_c static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, - ngx_quic_tp_t *tp, ngx_quic_header_t *pkt, + ngx_quic_conf_t *conf, ngx_quic_header_t *pkt, ngx_connection_handler_pt handler); static ngx_int_t ngx_quic_new_dcid(ngx_connection_t *c, ngx_str_t *odcid); static ngx_int_t ngx_quic_retry(ngx_connection_t *c); @@ -585,7 +587,7 @@ ngx_quic_send_alert(ngx_ssl_conn_t *ssl_ void -ngx_quic_run(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_tp_t *tp, +ngx_quic_run(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_conf_t *conf, ngx_connection_handler_pt handler) { ngx_buf_t *b; @@ -604,7 +606,7 @@ ngx_quic_run(ngx_connection_t *c, ngx_ss pkt.data = b->start; pkt.len = b->last - b->start; - if (ngx_quic_new_connection(c, ssl, tp, &pkt, handler) != NGX_OK) { + if (ngx_quic_new_connection(c, ssl, conf, &pkt, handler) != NGX_OK) { ngx_quic_close_connection(c, NGX_ERROR); return; } @@ -619,8 +621,9 @@ ngx_quic_run(ngx_connection_t *c, ngx_ss static ngx_int_t -ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_tp_t *tp, - ngx_quic_header_t *pkt, ngx_connection_handler_pt handler) +ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, + ngx_quic_conf_t *conf, ngx_quic_header_t *pkt, + ngx_connection_handler_pt handler) { ngx_int_t rc; ngx_uint_t i; @@ -703,7 +706,8 @@ ngx_quic_new_connection(ngx_connection_t c->quic = qc; qc->ssl = ssl; - qc->tp = *tp; + qc->conf = conf; + qc->tp = conf->tp; qc->streams.handler = handler; ctp = &qc->ctp; @@ -767,7 +771,7 @@ ngx_quic_new_connection(ngx_connection_t /* NGX_OK */ qc->validated = 1; - } else if (tp->retry) { + } else if (conf->retry) { return ngx_quic_retry(c); } @@ -949,7 +953,7 @@ ngx_quic_new_token(ngx_connection_t *c, return NGX_ERROR; } - key = c->quic->tp.token_key; + key = c->quic->conf->token_key; iv = token->data; if (RAND_bytes(iv, iv_len) <= 0 @@ -1023,7 +1027,7 @@ ngx_quic_validate_token(ngx_connection_t /* NEW_TOKEN in a previous connection */ cipher = EVP_aes_256_cbc(); - key = c->quic->tp.token_key; + key = c->quic->conf->token_key; iv = pkt->token.data; iv_len = EVP_CIPHER_iv_length(cipher); @@ -2237,7 +2241,7 @@ ngx_quic_send_new_token(ngx_connection_t ngx_str_t token; ngx_quic_frame_t *frame; - if (!c->quic->tp.retry) { + if (!c->quic->conf->retry) { return NGX_OK; } diff --git a/src/event/ngx_event_quic.h b/src/event/ngx_event_quic.h --- a/src/event/ngx_event_quic.h +++ b/src/event/ngx_event_quic.h @@ -78,9 +78,6 @@ typedef struct { ngx_str_t initial_scid; ngx_str_t retry_scid; - ngx_flag_t retry; - u_char token_key[32]; /* AES 256 */ - /* TODO */ u_char stateless_reset_token[16]; void *preferred_address; @@ -88,6 +85,13 @@ typedef struct { typedef struct { + ngx_quic_tp_t tp; + ngx_flag_t retry; + u_char token_key[32]; /* AES 256 */ +} ngx_quic_conf_t; + + +typedef struct { uint64_t sent; uint64_t received; ngx_queue_t frames; /* reorder queue */ @@ -107,7 +111,7 @@ struct ngx_quic_stream_s { }; -void ngx_quic_run(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_tp_t *tp, +void ngx_quic_run(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_conf_t *conf, ngx_connection_handler_pt handler); ngx_connection_t *ngx_quic_create_uni_stream(ngx_connection_t *c); void ngx_quic_finalize_connection(ngx_connection_t *c, ngx_uint_t err, diff --git a/src/http/modules/ngx_http_quic_module.c b/src/http/modules/ngx_http_quic_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_quic_module.c @@ -0,0 +1,344 @@ + +/* + * Copyright (C) Nginx, Inc. + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include + + +static ngx_int_t ngx_http_variable_quic(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_quic_add_variables(ngx_conf_t *cf); +static void *ngx_http_quic_create_srv_conf(ngx_conf_t *cf); +static char *ngx_http_quic_merge_srv_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_http_quic_max_ack_delay(ngx_conf_t *cf, void *post, + void *data); +static char *ngx_http_quic_max_udp_payload_size(ngx_conf_t *cf, void *post, + void *data); + + +static ngx_conf_post_t ngx_http_quic_max_ack_delay_post = + { ngx_http_quic_max_ack_delay }; +static ngx_conf_post_t ngx_http_quic_max_udp_payload_size_post = + { ngx_http_quic_max_udp_payload_size }; +static ngx_conf_num_bounds_t ngx_http_quic_ack_delay_exponent_bounds = + { ngx_conf_check_num_bounds, 0, 20 }; +static ngx_conf_num_bounds_t ngx_http_quic_active_connection_id_limit_bounds = + { ngx_conf_check_num_bounds, 2, -1 }; + + +static ngx_command_t ngx_http_quic_commands[] = { + + { ngx_string("quic_max_idle_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_quic_conf_t, tp.max_idle_timeout), + NULL }, + + { ngx_string("quic_max_ack_delay"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_quic_conf_t, tp.max_ack_delay), + &ngx_http_quic_max_ack_delay_post }, + + { ngx_string("quic_max_udp_payload_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_quic_conf_t, tp.max_udp_payload_size), + &ngx_http_quic_max_udp_payload_size_post }, + + { ngx_string("quic_initial_max_data"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_quic_conf_t, tp.initial_max_data), + NULL }, + + { ngx_string("quic_initial_max_stream_data_bidi_local"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_quic_conf_t, tp.initial_max_stream_data_bidi_local), + NULL }, + + { ngx_string("quic_initial_max_stream_data_bidi_remote"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_quic_conf_t, tp.initial_max_stream_data_bidi_remote), + NULL }, + + { ngx_string("quic_initial_max_stream_data_uni"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_quic_conf_t, tp.initial_max_stream_data_uni), + NULL }, + + { ngx_string("quic_initial_max_streams_bidi"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_quic_conf_t, tp.initial_max_streams_bidi), + NULL }, + + { ngx_string("quic_initial_max_streams_uni"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_quic_conf_t, tp.initial_max_streams_uni), + NULL }, + + { ngx_string("quic_ack_delay_exponent"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_quic_conf_t, tp.ack_delay_exponent), + &ngx_http_quic_ack_delay_exponent_bounds }, + + { ngx_string("quic_active_migration"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_quic_conf_t, tp.disable_active_migration), + NULL }, + + { ngx_string("quic_active_connection_id_limit"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_quic_conf_t, tp.active_connection_id_limit), + &ngx_http_quic_active_connection_id_limit_bounds }, + + { ngx_string("quic_retry"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_quic_conf_t, retry), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_quic_module_ctx = { + ngx_http_quic_add_variables, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_http_quic_create_srv_conf, /* create server configuration */ + ngx_http_quic_merge_srv_conf, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_quic_module = { + NGX_MODULE_V1, + &ngx_http_quic_module_ctx, /* module context */ + ngx_http_quic_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_http_variable_t ngx_http_quic_vars[] = { + + { ngx_string("quic"), NULL, ngx_http_variable_quic, 0, 0, 0 }, + + ngx_http_null_variable +}; + + +static ngx_int_t +ngx_http_variable_quic(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + if (r->connection->qs) { + + v->len = 4; + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + v->data = (u_char *) "quic"; + return NGX_OK; + } + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_quic_add_variables(ngx_conf_t *cf) +{ + ngx_http_variable_t *var, *v; + + for (v = ngx_http_quic_vars; v->name.len; v++) { + var = ngx_http_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = v->get_handler; + var->data = v->data; + } + + return NGX_OK; +} + + +static void * +ngx_http_quic_create_srv_conf(ngx_conf_t *cf) +{ + ngx_quic_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_quic_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * conf->tp.original_dcid = { 0, NULL }; + * conf->tp.initial_scid = { 0, NULL }; + * conf->tp.retry_scid = { 0, NULL }; + * conf->tp.stateless_reset_token = { 0 } + * conf->tp.preferred_address = NULL + */ + + conf->tp.max_idle_timeout = NGX_CONF_UNSET_MSEC; + conf->tp.max_ack_delay = NGX_CONF_UNSET_MSEC; + conf->tp.max_udp_payload_size = NGX_CONF_UNSET_SIZE; + conf->tp.initial_max_data = NGX_CONF_UNSET_SIZE; + conf->tp.initial_max_stream_data_bidi_local = NGX_CONF_UNSET_SIZE; + conf->tp.initial_max_stream_data_bidi_remote = NGX_CONF_UNSET_SIZE; + conf->tp.initial_max_stream_data_uni = NGX_CONF_UNSET_SIZE; + conf->tp.initial_max_streams_bidi = NGX_CONF_UNSET_UINT; + conf->tp.initial_max_streams_uni = NGX_CONF_UNSET_UINT; + conf->tp.ack_delay_exponent = NGX_CONF_UNSET_UINT; + conf->tp.disable_active_migration = NGX_CONF_UNSET_UINT; + conf->tp.active_connection_id_limit = NGX_CONF_UNSET_UINT; + + conf->retry = NGX_CONF_UNSET; + + return conf; +} + + +static char * +ngx_http_quic_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_quic_conf_t *prev = parent; + ngx_quic_conf_t *conf = child; + + ngx_conf_merge_msec_value(conf->tp.max_idle_timeout, + prev->tp.max_idle_timeout, 60000); + + ngx_conf_merge_msec_value(conf->tp.max_ack_delay, + prev->tp.max_ack_delay, + NGX_QUIC_DEFAULT_MAX_ACK_DELAY); + + ngx_conf_merge_size_value(conf->tp.max_udp_payload_size, + prev->tp.max_udp_payload_size, + NGX_QUIC_MAX_UDP_PAYLOAD_SIZE); + + ngx_conf_merge_size_value(conf->tp.initial_max_data, + prev->tp.initial_max_data, + 16 * NGX_QUIC_STREAM_BUFSIZE); + + ngx_conf_merge_size_value(conf->tp.initial_max_stream_data_bidi_local, + prev->tp.initial_max_stream_data_bidi_local, + NGX_QUIC_STREAM_BUFSIZE); + + ngx_conf_merge_size_value(conf->tp.initial_max_stream_data_bidi_remote, + prev->tp.initial_max_stream_data_bidi_remote, + NGX_QUIC_STREAM_BUFSIZE); + + ngx_conf_merge_size_value(conf->tp.initial_max_stream_data_uni, + prev->tp.initial_max_stream_data_uni, + NGX_QUIC_STREAM_BUFSIZE); + + ngx_conf_merge_uint_value(conf->tp.initial_max_streams_bidi, + prev->tp.initial_max_streams_bidi, 16); + + ngx_conf_merge_uint_value(conf->tp.initial_max_streams_uni, + prev->tp.initial_max_streams_uni, 16); + + ngx_conf_merge_uint_value(conf->tp.ack_delay_exponent, + prev->tp.ack_delay_exponent, + NGX_QUIC_DEFAULT_ACK_DELAY_EXPONENT); + + ngx_conf_merge_uint_value(conf->tp.disable_active_migration, + prev->tp.disable_active_migration, 1); + + ngx_conf_merge_uint_value(conf->tp.active_connection_id_limit, + prev->tp.active_connection_id_limit, 2); + + ngx_conf_merge_value(conf->retry, prev->retry, 0); + + if (conf->retry) { + if (RAND_bytes(conf->token_key, sizeof(conf->token_key)) <= 0) { + return NGX_CONF_ERROR; + } + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_quic_max_ack_delay(ngx_conf_t *cf, void *post, void *data) +{ + ngx_msec_t *sp = data; + + if (*sp > 16384) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"quic_max_ack_delay\" must be less than 16384"); + + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_quic_max_udp_payload_size(ngx_conf_t *cf, void *post, void *data) +{ + size_t *sp = data; + + if (*sp < NGX_QUIC_MIN_INITIAL_SIZE + || *sp > NGX_QUIC_MAX_UDP_PAYLOAD_SIZE) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"quic_max_udp_payload_size\" must be between " + "%d and %d", + NGX_QUIC_MIN_INITIAL_SIZE, + NGX_QUIC_MAX_UDP_PAYLOAD_SIZE); + + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} diff --git a/src/http/modules/ngx_http_quic_module.h b/src/http/modules/ngx_http_quic_module.h new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_quic_module.h @@ -0,0 +1,25 @@ + +/* + * Copyright (C) Nginx, Inc. + * Copyright (C) Roman Arutyunyan + */ + + +#ifndef _NGX_HTTP_QUIC_H_INCLUDED_ +#define _NGX_HTTP_QUIC_H_INCLUDED_ + + +#include +#include +#include + + +#define NGX_HTTP_QUIC_ALPN(s) NGX_HTTP_QUIC_ALPN_DRAFT(s) +#define NGX_HTTP_QUIC_ALPN_DRAFT(s) "\x05hq-" #s +#define NGX_HTTP_QUIC_ALPN_ADVERTISE NGX_HTTP_QUIC_ALPN(NGX_QUIC_DRAFT_VERSION) + + +extern ngx_module_t ngx_http_quic_module; + + +#endif /* _NGX_HTTP_QUIC_H_INCLUDED_ */ 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 @@ -402,7 +402,7 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t #if (NGX_DEBUG) unsigned int i; #endif -#if (NGX_HTTP_V2 || NGX_HTTP_V3) +#if (NGX_HTTP_V2 || NGX_HTTP_QUIC) ngx_http_connection_t *hc; #endif #if (NGX_HTTP_V2 || NGX_DEBUG) @@ -419,7 +419,7 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t } #endif -#if (NGX_HTTP_V2 || NGX_HTTP_V3) +#if (NGX_HTTP_V2 || NGX_HTTP_QUIC) hc = c->data; #endif @@ -437,6 +437,12 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t srvlen = sizeof(NGX_HTTP_V3_ALPN_ADVERTISE) - 1; } else #endif +#if (NGX_HTTP_QUIC) + if (hc->addr_conf->quic) { + srv = (unsigned char *) NGX_HTTP_QUIC_ALPN_ADVERTISE; + srvlen = sizeof(NGX_HTTP_QUIC_ALPN_ADVERTISE) - 1; + } else +#endif { srv = (unsigned char *) NGX_HTTP_NPN_ADVERTISE; srvlen = sizeof(NGX_HTTP_NPN_ADVERTISE) - 1; @@ -1247,6 +1253,7 @@ static ngx_int_t ngx_http_ssl_init(ngx_conf_t *cf) { ngx_uint_t a, p, s; + const char *name; ngx_http_conf_addr_t *addr; ngx_http_conf_port_t *port; ngx_http_ssl_srv_conf_t *sscf; @@ -1296,26 +1303,36 @@ 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"; + + } else if (addr[a].opt.quic) { + name = "quic"; + + } else { + name = "ssl"; + } + cscf = addr[a].default_server; sscf = cscf->ctx->srv_conf[ngx_http_ssl_module.ctx_index]; if (sscf->certificates == NULL) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no \"ssl_certificate\" is defined for " - "the \"listen ... ssl\" directive in %s:%ui", - cscf->file_name, cscf->line); + "the \"listen ... %s\" directive in %s:%ui", + name, cscf->file_name, cscf->line); return NGX_ERROR; } - 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\" did not enable TLSv1.3 for " - "the \"listen ... http3\" directive in %s:%ui", - cscf->file_name, cscf->line); + "the \"listen ... %s\" directives in %s:%ui", + name, cscf->file_name, cscf->line); return NGX_ERROR; } } 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 @@ -1200,10 +1200,13 @@ ngx_http_add_addresses(ngx_conf_t *cf, n #if (NGX_HTTP_SSL) ngx_uint_t ssl; #endif +#if (NGX_HTTP_QUIC) + ngx_uint_t quic; +#endif #if (NGX_HTTP_V2) ngx_uint_t http2; #endif -#if (NGX_HTTP_SSL) +#if (NGX_HTTP_V3) ngx_uint_t http3; #endif @@ -1238,10 +1241,13 @@ ngx_http_add_addresses(ngx_conf_t *cf, n #if (NGX_HTTP_SSL) ssl = lsopt->ssl || addr[i].opt.ssl; #endif +#if (NGX_HTTP_QUIC) + quic = lsopt->quic || addr[i].opt.quic; +#endif #if (NGX_HTTP_V2) http2 = lsopt->http2 || addr[i].opt.http2; #endif -#if (NGX_HTTP_SSL) +#if (NGX_HTTP_V3) http3 = lsopt->http3 || addr[i].opt.http3; #endif @@ -1277,10 +1283,13 @@ ngx_http_add_addresses(ngx_conf_t *cf, n #if (NGX_HTTP_SSL) addr[i].opt.ssl = ssl; #endif +#if (NGX_HTTP_QUIC) + addr[i].opt.quic = quic; +#endif #if (NGX_HTTP_V2) addr[i].opt.http2 = http2; #endif -#if (NGX_HTTP_SSL) +#if (NGX_HTTP_V3) addr[i].opt.http3 = http3; #endif @@ -1326,12 +1335,12 @@ ngx_http_add_address(ngx_conf_t *cf, ngx #endif -#if (NGX_HTTP_SSL && !defined NGX_OPENSSL_QUIC) - - if (lsopt->http3) { +#if (NGX_HTTP_QUIC && !defined NGX_OPENSSL_QUIC) + + if (lsopt->quic) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "nginx was built with OpenSSL that lacks QUIC " - "support, HTTP/3 is not enabled for %V", + "support, QUIC is not enabled for %V", &lsopt->addr_text); } @@ -1797,8 +1806,8 @@ ngx_http_add_listening(ngx_conf_t *cf, n ls->wildcard = addr->opt.wildcard; -#if (NGX_HTTP_SSL) - ls->quic = addr->opt.http3; +#if (NGX_HTTP_QUIC) + ls->quic = addr->opt.quic; #endif return ls; @@ -1830,10 +1839,13 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_h #if (NGX_HTTP_SSL) addrs[i].conf.ssl = addr[i].opt.ssl; #endif +#if (NGX_HTTP_QUIC) + addrs[i].conf.quic = addr[i].opt.quic; +#endif #if (NGX_HTTP_V2) addrs[i].conf.http2 = addr[i].opt.http2; #endif -#if (NGX_HTTP_SSL) +#if (NGX_HTTP_V3) addrs[i].conf.http3 = addr[i].opt.http3; #endif addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; @@ -1898,10 +1910,13 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_ #if (NGX_HTTP_SSL) addrs6[i].conf.ssl = addr[i].opt.ssl; #endif +#if (NGX_HTTP_QUIC) + addrs6[i].conf.quic = addr[i].opt.quic; +#endif #if (NGX_HTTP_V2) addrs6[i].conf.http2 = addr[i].opt.http2; #endif -#if (NGX_HTTP_SSL) +#if (NGX_HTTP_V3) addrs6[i].conf.http3 = addr[i].opt.http3; #endif addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -50,6 +50,9 @@ typedef u_char *(*ngx_http_log_handler_p #if (NGX_HTTP_SSL) #include #endif +#if (NGX_HTTP_QUIC) +#include +#endif struct ngx_http_log_ctx_s { 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 @@ -4079,8 +4079,22 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx #endif } + if (ngx_strcmp(value[n].data, "quic") == 0) { +#if (NGX_HTTP_QUIC) + lsopt.quic = 1; + lsopt.type = SOCK_DGRAM; + continue; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the \"quic\" parameter requires " + "ngx_http_quic_module"); + return NGX_CONF_ERROR; +#endif + } + if (ngx_strcmp(value[n].data, "http3") == 0) { #if (NGX_HTTP_V3) + lsopt.quic = 1; lsopt.http3 = 1; lsopt.type = SOCK_DGRAM; continue; @@ -4201,6 +4215,22 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx return NGX_CONF_ERROR; } +#if (NGX_HTTP_SSL) + +#if (NGX_HTTP_V3) + if (lsopt.ssl && lsopt.http3) { + return "\"ssl\" parameter is incompatible with \"http3\""; + } +#endif + +#if (NGX_HTTP_QUIC) + if (lsopt.ssl && lsopt.quic) { + return "\"ssl\" parameter is incompatible with \"quic\""; + } +#endif + +#endif + for (n = 0; n < u.naddrs; n++) { lsopt.sockaddr = u.addrs[n].sockaddr; lsopt.socklen = u.addrs[n].socklen; 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 @@ -74,6 +74,7 @@ typedef struct { unsigned bind:1; unsigned wildcard:1; unsigned ssl:1; + unsigned quic:1; unsigned http2:1; unsigned http3:1; #if (NGX_HAVE_INET6) @@ -238,6 +239,7 @@ struct ngx_http_addr_conf_s { ngx_http_virtual_names_t *virtual_names; unsigned ssl:1; + unsigned quic:1; unsigned http2:1; unsigned http3: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 @@ -64,9 +64,6 @@ static void ngx_http_ssl_handshake(ngx_e static void ngx_http_ssl_handshake_handler(ngx_connection_t *c); #endif -#if (NGX_HTTP_V3) -static void ngx_http_quic_stream_handler(ngx_connection_t *c); -#endif static char *ngx_http_client_errors[] = { @@ -221,26 +218,7 @@ ngx_http_init_connection(ngx_connection_ ngx_http_in6_addr_t *addr6; #endif -#if (NGX_HTTP_V3) - if (c->type == SOCK_DGRAM) { - ngx_http_v3_connection_t *h3c; - - h3c = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_connection_t)); - if (h3c == NULL) { - ngx_http_close_connection(c); - return; - } - - ngx_queue_init(&h3c->blocked); - - hc = &h3c->hc; - hc->quic = 1; - hc->ssl = 1; - - } else -#endif - hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); - + hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); if (hc == NULL) { ngx_http_close_connection(c); return; @@ -325,6 +303,46 @@ ngx_http_init_connection(ngx_connection_ /* the default server configuration for the address:port */ hc->conf_ctx = hc->addr_conf->default_server->ctx; +#if (NGX_HTTP_QUIC) + + if (hc->addr_conf->quic) { + ngx_quic_conf_t *qcf; + ngx_http_ssl_srv_conf_t *sscf; + +#if (NGX_HTTP_V3) + + if (hc->addr_conf->http3) { + ngx_int_t rc; + + rc = ngx_http_v3_init_connection(c); + + if (rc == NGX_ERROR) { + ngx_http_close_connection(c); + return; + } + + if (rc == NGX_DONE) { + return; + } + } + +#endif + + if (c->qs == NULL) { + c->log->connection = c->number; + + qcf = ngx_http_get_module_srv_conf(hc->conf_ctx, + ngx_http_quic_module); + sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, + ngx_http_ssl_module); + + ngx_quic_run(c, &sscf->ssl, qcf, ngx_http_init_connection); + return; + } + } + +#endif + ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t)); if (ctx == NULL) { ngx_http_close_connection(c); @@ -346,23 +364,6 @@ ngx_http_init_connection(ngx_connection_ rev->handler = ngx_http_wait_request_handler; c->write->handler = ngx_http_empty_handler; - if (c->shared) { - rev->ready = 1; - } - -#if (NGX_HTTP_V3) - if (hc->quic) { - ngx_http_v3_srv_conf_t *v3cf; - ngx_http_ssl_srv_conf_t *sscf; - - v3cf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v3_module); - sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); - - ngx_quic_run(c, &sscf->ssl, &v3cf->quic, ngx_http_quic_stream_handler); - return; - } -#endif - #if (NGX_HTTP_V2) if (hc->addr_conf->http2) { rev->handler = ngx_http_v2_init; @@ -410,72 +411,6 @@ ngx_http_init_connection(ngx_connection_ } -#if (NGX_HTTP_V3) - -static void -ngx_http_quic_stream_handler(ngx_connection_t *c) -{ - ngx_event_t *rev; - ngx_http_log_ctx_t *ctx; - ngx_http_connection_t *hc; - ngx_http_v3_connection_t *h3c; - - h3c = c->qs->parent->data; - - if (!h3c->settings_sent) { - h3c->settings_sent = 1; - - 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) { - ngx_http_v3_handle_client_uni_stream(c); - return; - } - - hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); - if (hc == NULL) { - ngx_http_close_connection(c); - return; - } - - ngx_memcpy(hc, h3c, sizeof(ngx_http_connection_t)); - c->data = hc; - - ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t)); - if (ctx == NULL) { - ngx_http_close_connection(c); - return; - } - - ctx->connection = c; - ctx->request = NULL; - ctx->current_request = NULL; - - c->log->handler = ngx_http_log_error; - c->log->data = ctx; - c->log->action = "waiting for request"; - - c->log_error = NGX_ERROR_INFO; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http3 new stream id:0x%uXL", c->qs->id); - - rev = c->read; - rev->handler = ngx_http_wait_request_handler; - c->write->handler = ngx_http_empty_handler; - - rev->handler(rev); -} - -#endif - - static void ngx_http_wait_request_handler(ngx_event_t *rev) { @@ -725,7 +660,7 @@ ngx_http_alloc_request(ngx_connection_t r->http_version = NGX_HTTP_VERSION_10; #if (NGX_HTTP_V3) - if (hc->quic) { + if (hc->addr_conf->http3) { r->http_version = NGX_HTTP_VERSION_30; } #endif diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -324,7 +324,6 @@ typedef struct { ngx_chain_t *free; unsigned ssl:1; - unsigned quic:1; unsigned proxy_protocol:1; } ngx_http_connection_t; 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 @@ -118,6 +118,8 @@ typedef struct { } ngx_http_v3_connection_t; +ngx_int_t ngx_http_v3_init_connection(ngx_connection_t *c); + ngx_int_t ngx_http_v3_parse_request(ngx_http_request_t *r, ngx_buf_t *b); ngx_int_t ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b, ngx_uint_t allow_underscores); @@ -130,9 +132,6 @@ uintptr_t ngx_http_v3_encode_varlen_int( uintptr_t ngx_http_v3_encode_prefix_int(u_char *p, uint64_t value, ngx_uint_t prefix); -ngx_int_t ngx_http_v3_send_settings(ngx_connection_t *c); -void ngx_http_v3_handle_client_uni_stream(ngx_connection_t *c); - ngx_int_t ngx_http_v3_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic, ngx_uint_t index, ngx_str_t *value); ngx_int_t ngx_http_v3_insert(ngx_connection_t *c, ngx_str_t *name, 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 @@ -10,114 +10,8 @@ #include -static char *ngx_http_v3_max_ack_delay(ngx_conf_t *cf, void *post, void *data); -static char *ngx_http_v3_max_udp_payload_size(ngx_conf_t *cf, void *post, - void *data); - - -static ngx_conf_post_t ngx_http_v3_max_ack_delay_post = - { ngx_http_v3_max_ack_delay }; -static ngx_conf_post_t ngx_http_v3_max_udp_payload_size_post = - { ngx_http_v3_max_udp_payload_size }; -static ngx_conf_num_bounds_t ngx_http_v3_ack_delay_exponent_bounds = - { ngx_conf_check_num_bounds, 0, 20 }; -static ngx_conf_num_bounds_t ngx_http_v3_active_connection_id_limit_bounds = - { ngx_conf_check_num_bounds, 2, -1 }; - - static ngx_command_t ngx_http_v3_commands[] = { - { ngx_string("quic_max_idle_timeout"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v3_srv_conf_t, quic.max_idle_timeout), - NULL }, - - { ngx_string("quic_max_ack_delay"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v3_srv_conf_t, quic.max_ack_delay), - &ngx_http_v3_max_ack_delay_post }, - - { ngx_string("quic_max_udp_payload_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v3_srv_conf_t, quic.max_udp_payload_size), - &ngx_http_v3_max_udp_payload_size_post }, - - { ngx_string("quic_initial_max_data"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v3_srv_conf_t, quic.initial_max_data), - NULL }, - - { ngx_string("quic_initial_max_stream_data_bidi_local"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v3_srv_conf_t, quic.initial_max_stream_data_bidi_local), - NULL }, - - { ngx_string("quic_initial_max_stream_data_bidi_remote"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v3_srv_conf_t, quic.initial_max_stream_data_bidi_remote), - NULL }, - - { ngx_string("quic_initial_max_stream_data_uni"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v3_srv_conf_t, quic.initial_max_stream_data_uni), - NULL }, - - { ngx_string("quic_initial_max_streams_bidi"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v3_srv_conf_t, quic.initial_max_streams_bidi), - NULL }, - - { ngx_string("quic_initial_max_streams_uni"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v3_srv_conf_t, quic.initial_max_streams_uni), - NULL }, - - { ngx_string("quic_ack_delay_exponent"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v3_srv_conf_t, quic.ack_delay_exponent), - &ngx_http_v3_ack_delay_exponent_bounds }, - - { ngx_string("quic_active_migration"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v3_srv_conf_t, quic.disable_active_migration), - NULL }, - - { ngx_string("quic_active_connection_id_limit"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_v3_srv_conf_t, quic.active_connection_id_limit), - &ngx_http_v3_active_connection_id_limit_bounds }, - - { ngx_string("quic_retry"), - 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, quic.retry), - NULL }, - { ngx_string("http3_max_field_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, @@ -143,8 +37,6 @@ static ngx_command_t ngx_http_v3_comman }; -static ngx_int_t ngx_http_variable_quic(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_http3(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_v3_add_variables(ngx_conf_t *cf); @@ -185,8 +77,6 @@ ngx_module_t ngx_http_v3_module = { static ngx_http_variable_t ngx_http_v3_vars[] = { - { ngx_string("quic"), NULL, ngx_http_variable_quic, - 0, 0, 0 }, { ngx_string("http3"), NULL, ngx_http_variable_http3, 0, 0, 0 }, @@ -196,26 +86,6 @@ static ngx_http_variable_t ngx_http_v3_ static ngx_int_t -ngx_http_variable_quic(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data) -{ - if (r->connection->qs) { - - v->len = 4; - v->valid = 1; - v->no_cacheable = 1; - v->not_found = 0; - v->data = (u_char *) "quic"; - return NGX_OK; - } - - v->not_found = 1; - - return NGX_OK; -} - - -static ngx_int_t ngx_http_variable_http3(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { @@ -264,31 +134,6 @@ ngx_http_v3_create_srv_conf(ngx_conf_t * return NULL; } - /* - * set by ngx_pcalloc(): - * v3cf->quic.original_dcid = { 0, NULL }; - * v3cf->quic.initial_scid = { 0, NULL }; - * v3cf->quic.retry_scid = { 0, NULL }; - * v3cf->quic.stateless_reset_token = { 0 } - * conf->quic.preferred_address = NULL - */ - - v3cf->quic.max_idle_timeout = NGX_CONF_UNSET_MSEC; - v3cf->quic.max_ack_delay = NGX_CONF_UNSET_MSEC; - - v3cf->quic.max_udp_payload_size = NGX_CONF_UNSET_SIZE; - v3cf->quic.initial_max_data = NGX_CONF_UNSET_SIZE; - v3cf->quic.initial_max_stream_data_bidi_local = NGX_CONF_UNSET_SIZE; - v3cf->quic.initial_max_stream_data_bidi_remote = NGX_CONF_UNSET_SIZE; - v3cf->quic.initial_max_stream_data_uni = NGX_CONF_UNSET_SIZE; - v3cf->quic.initial_max_streams_bidi = NGX_CONF_UNSET_UINT; - v3cf->quic.initial_max_streams_uni = NGX_CONF_UNSET_UINT; - v3cf->quic.ack_delay_exponent = NGX_CONF_UNSET_UINT; - v3cf->quic.disable_active_migration = NGX_CONF_UNSET_UINT; - v3cf->quic.active_connection_id_limit = NGX_CONF_UNSET_UINT; - - v3cf->quic.retry = NGX_CONF_UNSET; - v3cf->max_field_size = NGX_CONF_UNSET_SIZE; v3cf->max_table_capacity = NGX_CONF_UNSET_SIZE; v3cf->max_blocked_streams = NGX_CONF_UNSET_UINT; @@ -303,57 +148,6 @@ ngx_http_v3_merge_srv_conf(ngx_conf_t *c ngx_http_v3_srv_conf_t *prev = parent; ngx_http_v3_srv_conf_t *conf = child; - ngx_conf_merge_msec_value(conf->quic.max_idle_timeout, - prev->quic.max_idle_timeout, 60000); - - ngx_conf_merge_msec_value(conf->quic.max_ack_delay, - prev->quic.max_ack_delay, - NGX_QUIC_DEFAULT_MAX_ACK_DELAY); - - ngx_conf_merge_size_value(conf->quic.max_udp_payload_size, - prev->quic.max_udp_payload_size, - NGX_QUIC_MAX_UDP_PAYLOAD_SIZE); - - ngx_conf_merge_size_value(conf->quic.initial_max_data, - prev->quic.initial_max_data, - 16 * NGX_QUIC_STREAM_BUFSIZE); - - ngx_conf_merge_size_value(conf->quic.initial_max_stream_data_bidi_local, - prev->quic.initial_max_stream_data_bidi_local, - NGX_QUIC_STREAM_BUFSIZE); - - ngx_conf_merge_size_value(conf->quic.initial_max_stream_data_bidi_remote, - prev->quic.initial_max_stream_data_bidi_remote, - NGX_QUIC_STREAM_BUFSIZE); - - ngx_conf_merge_size_value(conf->quic.initial_max_stream_data_uni, - prev->quic.initial_max_stream_data_uni, - NGX_QUIC_STREAM_BUFSIZE); - - ngx_conf_merge_uint_value(conf->quic.initial_max_streams_bidi, - prev->quic.initial_max_streams_bidi, 16); - - ngx_conf_merge_uint_value(conf->quic.initial_max_streams_uni, - prev->quic.initial_max_streams_uni, 16); - - ngx_conf_merge_uint_value(conf->quic.ack_delay_exponent, - prev->quic.ack_delay_exponent, - NGX_QUIC_DEFAULT_ACK_DELAY_EXPONENT); - - ngx_conf_merge_uint_value(conf->quic.disable_active_migration, - prev->quic.disable_active_migration, 1); - - ngx_conf_merge_uint_value(conf->quic.active_connection_id_limit, - prev->quic.active_connection_id_limit, 2); - - ngx_conf_merge_value(conf->quic.retry, prev->quic.retry, 0); - - if (conf->quic.retry) { - if (RAND_bytes(conf->quic.token_key, sizeof(conf->quic.token_key)) <= 0) { - return NGX_CONF_ERROR; - } - } - ngx_conf_merge_size_value(conf->max_field_size, prev->max_field_size, NGX_HTTP_V3_DEFAULT_MAX_FIELD_SIZE); @@ -368,40 +162,3 @@ ngx_http_v3_merge_srv_conf(ngx_conf_t *c return NGX_CONF_OK; } - - -static char * -ngx_http_v3_max_ack_delay(ngx_conf_t *cf, void *post, void *data) -{ - ngx_msec_t *sp = data; - - if (*sp > 16384) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"quic_max_ack_delay\" must be less than 16384"); - - return NGX_CONF_ERROR; - } - - return NGX_CONF_OK; -} - - -static char * -ngx_http_v3_max_udp_payload_size(ngx_conf_t *cf, void *post, void *data) -{ - size_t *sp = data; - - if (*sp < NGX_QUIC_MIN_INITIAL_SIZE - || *sp > NGX_QUIC_MAX_UDP_PAYLOAD_SIZE) - { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"quic_max_udp_payload_size\" must be between " - "%d and %d", - NGX_QUIC_MIN_INITIAL_SIZE, - NGX_QUIC_MAX_UDP_PAYLOAD_SIZE); - - return NGX_CONF_ERROR; - } - - return NGX_CONF_OK; -} 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 @@ -27,22 +27,55 @@ static void ngx_http_v3_uni_read_handler static void ngx_http_v3_dummy_write_handler(ngx_event_t *wev); static ngx_connection_t *ngx_http_v3_get_uni_stream(ngx_connection_t *c, ngx_uint_t type); +static ngx_int_t ngx_http_v3_send_settings(ngx_connection_t *c); -void -ngx_http_v3_handle_client_uni_stream(ngx_connection_t *c) +ngx_int_t +ngx_http_v3_init_connection(ngx_connection_t *c) { + ngx_http_connection_t *hc; ngx_http_v3_uni_stream_t *us; + ngx_http_v3_connection_t *h3c; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http3 new uni stream id:0x%uxL", c->qs->id); + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init connection"); + + hc = c->data; + + if (c->qs == NULL) { + h3c = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_connection_t)); + if (h3c == NULL) { + return NGX_ERROR; + } + + h3c->hc = *hc; + + ngx_queue_init(&h3c->blocked); + + c->data = h3c; + return NGX_OK; + } + + h3c = c->qs->parent->data; + + if (!h3c->settings_sent) { + h3c->settings_sent = 1; + + 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"); + return NGX_ERROR; + } + } + + if ((c->qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0) { + return NGX_OK; + } 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; + return NGX_ERROR; } us->index = -1; @@ -53,6 +86,8 @@ ngx_http_v3_handle_client_uni_stream(ngx c->write->handler = ngx_http_v3_dummy_write_handler; ngx_http_v3_read_uni_stream_type(c->read); + + return NGX_DONE; } @@ -366,7 +401,7 @@ failed: } -ngx_int_t +static ngx_int_t ngx_http_v3_send_settings(ngx_connection_t *c) { u_char *p, buf[NGX_HTTP_V3_VARLEN_INT_LEN * 6];