From 731915a0c5e90b79d3cca1a4b0a3c33e1f77631c Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Mon, 6 Dec 2021 13:02:36 +0300 Subject: [PATCH] HTTP/3: merged ngx_http_quic_module into ngx_http_v3_module. --- auto/modules | 19 +- auto/options | 3 - src/http/modules/ngx_http_quic_module.c | 570 ------------------------ src/http/modules/ngx_http_quic_module.h | 28 -- src/http/modules/ngx_http_ssl_module.c | 15 +- src/http/ngx_http.c | 24 +- src/http/ngx_http.h | 3 - src/http/ngx_http_core_module.c | 6 +- src/http/ngx_http_request.c | 18 +- src/http/ngx_http_upstream.c | 4 +- src/http/v3/ngx_http_v3.h | 10 +- src/http/v3/ngx_http_v3_module.c | 431 +++++++++++++++++- src/http/v3/ngx_http_v3_request.c | 125 +++++- 13 files changed, 583 insertions(+), 673 deletions(-) delete mode 100644 src/http/modules/ngx_http_quic_module.c delete mode 100644 src/http/modules/ngx_http_quic_module.h diff --git a/auto/modules b/auto/modules index 09651f32b..f98eeafed 100644 --- a/auto/modules +++ b/auto/modules @@ -437,9 +437,11 @@ if [ $HTTP = YES ]; then fi if [ $HTTP_V3 = YES ]; then + USE_OPENSSL_QUIC=YES + HTTP_SSL=YES + have=NGX_HTTP_V3 . auto/have have=NGX_HTTP_HEADERS . auto/have - HTTP_QUIC=YES ngx_module_name=ngx_http_v3_module ngx_module_incs=src/http/v3 @@ -713,21 +715,6 @@ 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 index d677dd970..51387f412 100644 --- a/auto/options +++ b/auto/options @@ -60,7 +60,6 @@ HTTP_CACHE=YES HTTP_CHARSET=YES HTTP_GZIP=YES HTTP_SSL=NO -HTTP_QUIC=NO HTTP_V2=NO HTTP_V3=NO HTTP_SSI=YES @@ -237,7 +236,6 @@ $0: warning: the \"--with-ipv6\" option is deprecated" --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 ;; @@ -458,7 +456,6 @@ cat << END --without-quic_bpf_module disable ngx_quic_bpf_module --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/http/modules/ngx_http_quic_module.c b/src/http/modules/ngx_http_quic_module.c deleted file mode 100644 index 9470df60e..000000000 --- a/src/http/modules/ngx_http_quic_module.c +++ /dev/null @@ -1,570 +0,0 @@ - -/* - * 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 char *ngx_http_quic_host_key(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - -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_disable_active_migration"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_flag_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_string("quic_gso"), - 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, gso_enabled), - NULL }, - - { ngx_string("quic_host_key"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_http_quic_host_key, - NGX_HTTP_SRV_CONF_OFFSET, - 0, - 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_str_t ngx_http_quic_salt = ngx_string("ngx_quic"); - - -ngx_int_t -ngx_http_quic_init(ngx_connection_t *c) -{ - uint64_t n; - ngx_quic_conf_t *qcf; - ngx_http_connection_t *hc, *phc; - ngx_http_core_loc_conf_t *clcf; - - hc = c->data; - - hc->ssl = 1; - - if (c->quic == NULL) { - qcf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_quic_module); - - ngx_quic_run(c, qcf); - - return NGX_DONE; - } - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http init quic stream"); - -#if (NGX_HTTP_V3) - if (!hc->addr_conf->http3) -#endif - { - /* Use HTTP/3 General Protocol Error Code 0x101 for finalization */ - - if (c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { - ngx_quic_finalize_connection(c->quic->parent, 0x101, - "unexpected uni stream"); - ngx_http_close_connection(c); - return NGX_DONE; - } - - clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, ngx_http_core_module); - - n = c->quic->id >> 2; - - if (n >= clcf->keepalive_requests) { - ngx_quic_finalize_connection(c->quic->parent, 0x101, - "reached maximum number of requests"); - ngx_http_close_connection(c); - return NGX_DONE; - } - - if (ngx_current_msec - c->quic->parent->start_time - > clcf->keepalive_time) - { - ngx_quic_finalize_connection(c->quic->parent, 0x101, - "reached maximum time for requests"); - ngx_http_close_connection(c); - return NGX_DONE; - } - } - - phc = ngx_http_quic_get_connection(c); - - if (phc->ssl_servername) { - hc->ssl_servername = phc->ssl_servername; - hc->conf_ctx = phc->conf_ctx; - - clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, ngx_http_core_module); - ngx_set_connection_log(c, clcf->error_log); - } - - return NGX_OK; -} - - -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->quic) { - - 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.sr_token = { 0 } - * conf->tp.sr_enabled = 0 - * conf->tp.preferred_address = NULL - * conf->host_key = { 0, NULL } - * cong->stream_reject_code_uni = 0; - */ - - 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; - conf->tp.active_connection_id_limit = NGX_CONF_UNSET_UINT; - - conf->retry = NGX_CONF_UNSET; - conf->gso_enabled = NGX_CONF_UNSET; -#if (NGX_HTTP_V3) - conf->stream_close_code = NGX_HTTP_V3_ERR_NO_ERROR; - conf->stream_reject_code_bidi = NGX_HTTP_V3_ERR_REQUEST_REJECTED; -#endif - - 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_http_ssl_srv_conf_t *sscf; - - 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, 3); - - ngx_conf_merge_uint_value(conf->tp.ack_delay_exponent, - prev->tp.ack_delay_exponent, - NGX_QUIC_DEFAULT_ACK_DELAY_EXPONENT); - - ngx_conf_merge_value(conf->tp.disable_active_migration, - prev->tp.disable_active_migration, 0); - - 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); - ngx_conf_merge_value(conf->gso_enabled, prev->gso_enabled, 0); - - ngx_conf_merge_str_value(conf->host_key, prev->host_key, ""); - - if (conf->host_key.len == 0) { - - conf->host_key.len = NGX_QUIC_DEFAULT_HOST_KEY_LEN; - conf->host_key.data = ngx_palloc(cf->pool, conf->host_key.len); - if (conf->host_key.data == NULL) { - return NGX_CONF_ERROR; - } - - if (RAND_bytes(conf->host_key.data, NGX_QUIC_DEFAULT_HOST_KEY_LEN) - <= 0) - { - return NGX_CONF_ERROR; - } - } - - if (ngx_quic_derive_key(cf->log, "av_token_key", - &conf->host_key, &ngx_http_quic_salt, - conf->av_token_key, NGX_QUIC_AV_KEY_LEN) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - - if (ngx_quic_derive_key(cf->log, "sr_token_key", - &conf->host_key, &ngx_http_quic_salt, - conf->sr_token_key, NGX_QUIC_SR_KEY_LEN) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - - sscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_ssl_module); - conf->ssl = &sscf->ssl; - - 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; -} - - -static char * -ngx_http_quic_host_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_quic_conf_t *qcf = conf; - - u_char *buf; - size_t size; - ssize_t n; - ngx_str_t *value; - ngx_file_t file; - ngx_file_info_t fi; - - if (qcf->host_key.len) { - return "is duplicate"; - } - - buf = NULL; -#if (NGX_SUPPRESS_WARN) - size = 0; -#endif - - value = cf->args->elts; - - if (ngx_conf_full_name(cf->cycle, &value[1], 1) != NGX_OK) { - return NGX_CONF_ERROR; - } - - ngx_memzero(&file, sizeof(ngx_file_t)); - file.name = value[1]; - file.log = cf->log; - - file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); - - if (file.fd == NGX_INVALID_FILE) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, - ngx_open_file_n " \"%V\" failed", &file.name); - return NGX_CONF_ERROR; - } - - if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) { - ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, - ngx_fd_info_n " \"%V\" failed", &file.name); - goto failed; - } - - size = ngx_file_size(&fi); - - if (size == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"%V\" zero key size", &file.name); - goto failed; - } - - buf = ngx_pnalloc(cf->pool, size); - if (buf == NULL) { - goto failed; - } - - n = ngx_read_file(&file, buf, size, 0); - - if (n == NGX_ERROR) { - ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, - ngx_read_file_n " \"%V\" failed", &file.name); - goto failed; - } - - if ((size_t) n != size) { - ngx_conf_log_error(NGX_LOG_CRIT, cf, 0, - ngx_read_file_n " \"%V\" returned only " - "%z bytes instead of %uz", &file.name, n, size); - goto failed; - } - - qcf->host_key.data = buf; - qcf->host_key.len = n; - - if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, - ngx_close_file_n " \"%V\" failed", &file.name); - } - - return NGX_CONF_OK; - -failed: - - if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, - ngx_close_file_n " \"%V\" failed", &file.name); - } - - if (buf) { - ngx_explicit_memzero(buf, size); - } - - return NGX_CONF_ERROR; -} diff --git a/src/http/modules/ngx_http_quic_module.h b/src/http/modules/ngx_http_quic_module.h deleted file mode 100644 index 3b96fcc47..000000000 --- a/src/http/modules/ngx_http_quic_module.h +++ /dev/null @@ -1,28 +0,0 @@ - -/* - * 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_PROTO "\x0Ahq-interop" -#define NGX_HTTP_QUIC_ALPN_DRAFT_FMT "\x05hq-%02uD" - - -#define ngx_http_quic_get_connection(c) \ - ((ngx_http_connection_t *) (c)->quic->parent->data) - - -ngx_int_t ngx_http_quic_init(ngx_connection_t *c); - - -#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 index afeb68462..3af21178b 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -416,7 +416,7 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg) { -#if (NGX_HTTP_QUIC) +#if (NGX_HTTP_V3) const char *fmt; #endif unsigned int srvlen; @@ -424,10 +424,10 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, #if (NGX_DEBUG) unsigned int i; #endif -#if (NGX_HTTP_V2 || NGX_HTTP_QUIC) +#if (NGX_HTTP_V2 || NGX_HTTP_V3) ngx_http_connection_t *hc; #endif -#if (NGX_HTTP_V2 || NGX_HTTP_QUIC || NGX_DEBUG) +#if (NGX_HTTP_V2 || NGX_HTTP_V3 || NGX_DEBUG) ngx_connection_t *c; c = ngx_ssl_get_connection(ssl_conn); @@ -441,7 +441,7 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, } #endif -#if (NGX_HTTP_V2 || NGX_HTTP_QUIC) +#if (NGX_HTTP_V2 || NGX_HTTP_V3) hc = c->data; #endif @@ -451,17 +451,14 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, srvlen = sizeof(NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTOS) - 1; } else #endif -#if (NGX_HTTP_QUIC) - if (hc->addr_conf->quic) { #if (NGX_HTTP_V3) + if (hc->addr_conf->quic) { if (hc->addr_conf->http3) { srv = (unsigned char *) NGX_HTTP_V3_ALPN_PROTO; srvlen = sizeof(NGX_HTTP_V3_ALPN_PROTO) - 1; fmt = NGX_HTTP_V3_ALPN_DRAFT_FMT; - } else -#endif - { + } else { srv = (unsigned char *) NGX_HTTP_QUIC_ALPN_PROTO; srvlen = sizeof(NGX_HTTP_QUIC_ALPN_PROTO) - 1; fmt = NGX_HTTP_QUIC_ALPN_DRAFT_FMT; diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index 908e88103..187d867bb 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1237,13 +1237,11 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, #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_V3) + ngx_uint_t quic; ngx_uint_t http3; #endif @@ -1278,13 +1276,11 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, #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_V3) + quic = lsopt->quic || addr[i].opt.quic; http3 = lsopt->http3 || addr[i].opt.http3; #endif @@ -1320,13 +1316,11 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, #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_V3) + addr[i].opt.quic = quic; addr[i].opt.http3 = http3; #endif @@ -1371,7 +1365,7 @@ ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, #endif -#if (NGX_HTTP_QUIC && !defined NGX_QUIC) +#if (NGX_HTTP_V3 && !defined NGX_QUIC) if (lsopt->quic) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, @@ -1841,7 +1835,7 @@ ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr) ls->wildcard = addr->opt.wildcard; -#if (NGX_HTTP_QUIC) +#if (NGX_HTTP_V3) ls->quic = addr->opt.quic; #endif @@ -1874,13 +1868,11 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport, #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_V3) + addrs[i].conf.quic = addr[i].opt.quic; addrs[i].conf.http3 = addr[i].opt.http3; #endif addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; @@ -1945,13 +1937,11 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport, #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_V3) + addrs6[i].conf.quic = addr[i].opt.quic; 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 index 708defebc..5ac65c859 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -52,9 +52,6 @@ typedef u_char *(*ngx_http_log_handler_pt)(ngx_http_request_t *r, #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 index 19bc75136..1e8e27802 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -4097,14 +4097,14 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } if (ngx_strcmp(value[n].data, "quic") == 0) { -#if (NGX_HTTP_QUIC) +#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_quic_module"); + "ngx_http_v3_module"); return NGX_CONF_ERROR; #endif } @@ -4232,7 +4232,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } #endif -#if (NGX_HTTP_QUIC) +#if (NGX_HTTP_V3) if (lsopt.ssl && lsopt.quic) { return "\"ssl\" parameter is incompatible with \"quic\""; } diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 7125e7dd1..0acedb6e9 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -316,14 +316,6 @@ ngx_http_init_connection(ngx_connection_t *c) c->log_error = NGX_ERROR_INFO; -#if (NGX_HTTP_QUIC) - if (hc->addr_conf->quic) { - if (ngx_http_quic_init(c) == NGX_DONE) { - return; - } - } -#endif - rev = c->read; rev->handler = ngx_http_wait_request_handler; c->write->handler = ngx_http_empty_handler; @@ -335,7 +327,7 @@ ngx_http_init_connection(ngx_connection_t *c) #endif #if (NGX_HTTP_V3) - if (hc->addr_conf->http3) { + if (hc->addr_conf->quic) { ngx_http_v3_init(c); return; } @@ -2746,7 +2738,7 @@ ngx_http_finalize_connection(ngx_http_request_t *r) } #endif -#if (NGX_HTTP_QUIC) +#if (NGX_HTTP_V3) if (r->connection->quic) { ngx_http_close_request(r, 0); return; @@ -2967,7 +2959,7 @@ ngx_http_test_reading(ngx_http_request_t *r) #endif -#if (NGX_HTTP_QUIC) +#if (NGX_HTTP_V3) if (c->quic) { if (c->read->error) { @@ -3732,7 +3724,7 @@ ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc) log->action = "closing request"; if (r->connection->timedout -#if (NGX_HTTP_QUIC) +#if (NGX_HTTP_V3) && r->connection->quic == NULL #endif ) @@ -3810,7 +3802,7 @@ ngx_http_close_connection(ngx_connection_t *c) #endif #if (NGX_HTTP_V3) - if (ngx_http_v3_connection(c)) { + if (c->quic) { ngx_http_v3_reset_connection(c); } #endif diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index d27a53ea4..670fc022f 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -525,7 +525,7 @@ ngx_http_upstream_init(ngx_http_request_t *r) } #endif -#if (NGX_HTTP_QUIC) +#if (NGX_HTTP_V3) if (c->quic) { ngx_http_upstream_init_request(r); return; @@ -1365,7 +1365,7 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r, } #endif -#if (NGX_HTTP_QUIC) +#if (NGX_HTTP_V3) if (c->quic) { if (c->write->error) { diff --git a/src/http/v3/ngx_http_v3.h b/src/http/v3/ngx_http_v3.h index 758cbd1af..bee073e1d 100644 --- a/src/http/v3/ngx_http_v3.h +++ b/src/http/v3/ngx_http_v3.h @@ -22,6 +22,9 @@ #define NGX_HTTP_V3_ALPN_PROTO "\x02h3" #define NGX_HTTP_V3_ALPN_DRAFT_FMT "\x05h3-%02uD" +#define NGX_HTTP_QUIC_ALPN_PROTO "\x0Ahq-interop" +#define NGX_HTTP_QUIC_ALPN_DRAFT_FMT "\x05hq-%02uD" + #define NGX_HTTP_V3_VARLEN_INT_LEN 4 #define NGX_HTTP_V3_PREFIX_INT_LEN 11 @@ -74,6 +77,9 @@ #define NGX_HTTP_V3_ERR_DECODER_STREAM_ERROR 0x202 +#define ngx_http_quic_get_connection(c) \ + ((ngx_http_connection_t *) (c)->quic->parent->data) + #define ngx_http_v3_get_session(c) ngx_http_quic_get_connection(c)->v3_session #define ngx_http_v3_get_module_loc_conf(c, module) \ @@ -90,15 +96,13 @@ #define ngx_http_v3_shutdown_connection(c, code, reason) \ ngx_quic_shutdown_connection(c->quic->parent, code, reason) -#define ngx_http_v3_connection(c) \ - ((c)->quic ? ngx_http_quic_get_connection(c)->addr_conf->http3 : 0) - typedef struct { size_t max_table_capacity; ngx_uint_t max_blocked_streams; ngx_uint_t max_concurrent_pushes; ngx_uint_t max_uni_streams; + ngx_quic_conf_t quic; } ngx_http_v3_srv_conf_t; diff --git a/src/http/v3/ngx_http_v3_module.c b/src/http/v3/ngx_http_v3_module.c index 4b59b097c..14e24d29a 100644 --- a/src/http/v3/ngx_http_v3_module.c +++ b/src/http/v3/ngx_http_v3_module.c @@ -10,15 +10,34 @@ #include +static ngx_int_t ngx_http_v3_variable_quic(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); static void *ngx_http_v3_create_srv_conf(ngx_conf_t *cf); static char *ngx_http_v3_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 char *ngx_http_quic_host_key(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static void *ngx_http_v3_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_v3_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); static char *ngx_http_v3_push(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +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_v3_commands[] = { { ngx_string("http3_max_table_capacity"), @@ -63,12 +82,119 @@ static ngx_command_t ngx_http_v3_commands[] = { offsetof(ngx_http_v3_loc_conf_t, push_preload), NULL }, + { 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.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_http_v3_srv_conf_t, quic.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_http_v3_srv_conf_t, quic.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_http_v3_srv_conf_t, quic.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_http_v3_srv_conf_t, + quic.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_http_v3_srv_conf_t, + quic.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_http_v3_srv_conf_t, quic.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_http_v3_srv_conf_t, quic.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_http_v3_srv_conf_t, quic.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_http_v3_srv_conf_t, quic.tp.ack_delay_exponent), + &ngx_http_quic_ack_delay_exponent_bounds }, + + { ngx_string("quic_disable_active_migration"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, quic.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_http_v3_srv_conf_t, quic.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_http_v3_srv_conf_t, quic.retry), + NULL }, + + { ngx_string("quic_gso"), + 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.gso_enabled), + NULL }, + + { ngx_string("quic_host_key"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_http_quic_host_key, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + NULL }, + ngx_null_command }; static ngx_http_module_t ngx_http_v3_module_ctx = { - NULL, /* preconfiguration */ + ngx_http_v3_add_variables, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ @@ -98,6 +224,55 @@ ngx_module_t ngx_http_v3_module = { }; +static ngx_http_variable_t ngx_http_v3_vars[] = { + + { ngx_string("quic"), NULL, ngx_http_v3_variable_quic, 0, 0, 0 }, + + ngx_http_null_variable +}; + +static ngx_str_t ngx_http_quic_salt = ngx_string("ngx_quic"); + + +static ngx_int_t +ngx_http_v3_variable_quic(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + if (r->connection->quic) { + + 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_v3_add_variables(ngx_conf_t *cf) +{ + ngx_http_variable_t *var, *v; + + for (v = ngx_http_v3_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_v3_create_srv_conf(ngx_conf_t *cf) { @@ -108,11 +283,42 @@ ngx_http_v3_create_srv_conf(ngx_conf_t *cf) return NULL; } + /* + * set by ngx_pcalloc(): + * + * h3scf->quic.tp.original_dcid = { 0, NULL }; + * h3scf->quic.tp.initial_scid = { 0, NULL }; + * h3scf->quic.tp.retry_scid = { 0, NULL }; + * h3scf->quic.tp.sr_token = { 0 } + * h3scf->quic.tp.sr_enabled = 0 + * h3scf->quic.tp.preferred_address = NULL + * h3scf->quic.host_key = { 0, NULL } + * h3scf->quic.stream_reject_code_uni = 0; + */ + h3scf->max_table_capacity = NGX_CONF_UNSET_SIZE; h3scf->max_blocked_streams = NGX_CONF_UNSET_UINT; h3scf->max_concurrent_pushes = NGX_CONF_UNSET_UINT; h3scf->max_uni_streams = NGX_CONF_UNSET_UINT; + h3scf->quic.tp.max_idle_timeout = NGX_CONF_UNSET_MSEC; + h3scf->quic.tp.max_ack_delay = NGX_CONF_UNSET_MSEC; + h3scf->quic.tp.max_udp_payload_size = NGX_CONF_UNSET_SIZE; + h3scf->quic.tp.initial_max_data = NGX_CONF_UNSET_SIZE; + h3scf->quic.tp.initial_max_stream_data_bidi_local = NGX_CONF_UNSET_SIZE; + h3scf->quic.tp.initial_max_stream_data_bidi_remote = NGX_CONF_UNSET_SIZE; + h3scf->quic.tp.initial_max_stream_data_uni = NGX_CONF_UNSET_SIZE; + h3scf->quic.tp.initial_max_streams_bidi = NGX_CONF_UNSET_UINT; + h3scf->quic.tp.initial_max_streams_uni = NGX_CONF_UNSET_UINT; + h3scf->quic.tp.ack_delay_exponent = NGX_CONF_UNSET_UINT; + h3scf->quic.tp.disable_active_migration = NGX_CONF_UNSET; + h3scf->quic.tp.active_connection_id_limit = NGX_CONF_UNSET_UINT; + + h3scf->quic.retry = NGX_CONF_UNSET; + h3scf->quic.gso_enabled = NGX_CONF_UNSET; + h3scf->quic.stream_close_code = NGX_HTTP_V3_ERR_NO_ERROR; + h3scf->quic.stream_reject_code_bidi = NGX_HTTP_V3_ERR_REQUEST_REJECTED; + return h3scf; } @@ -123,6 +329,8 @@ ngx_http_v3_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_v3_srv_conf_t *prev = parent; ngx_http_v3_srv_conf_t *conf = child; + ngx_http_ssl_srv_conf_t *sscf; + ngx_conf_merge_size_value(conf->max_table_capacity, prev->max_table_capacity, 16384); @@ -135,10 +343,231 @@ ngx_http_v3_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_uint_value(conf->max_uni_streams, prev->max_uni_streams, 3); + ngx_conf_merge_msec_value(conf->quic.tp.max_idle_timeout, + prev->quic.tp.max_idle_timeout, 60000); + + ngx_conf_merge_msec_value(conf->quic.tp.max_ack_delay, + prev->quic.tp.max_ack_delay, + NGX_QUIC_DEFAULT_MAX_ACK_DELAY); + + ngx_conf_merge_size_value(conf->quic.tp.max_udp_payload_size, + prev->quic.tp.max_udp_payload_size, + NGX_QUIC_MAX_UDP_PAYLOAD_SIZE); + + ngx_conf_merge_size_value(conf->quic.tp.initial_max_data, + prev->quic.tp.initial_max_data, + 16 * NGX_QUIC_STREAM_BUFSIZE); + + ngx_conf_merge_size_value(conf->quic.tp.initial_max_stream_data_bidi_local, + prev->quic.tp.initial_max_stream_data_bidi_local, + NGX_QUIC_STREAM_BUFSIZE); + + ngx_conf_merge_size_value(conf->quic.tp.initial_max_stream_data_bidi_remote, + prev->quic.tp.initial_max_stream_data_bidi_remote, + NGX_QUIC_STREAM_BUFSIZE); + + ngx_conf_merge_size_value(conf->quic.tp.initial_max_stream_data_uni, + prev->quic.tp.initial_max_stream_data_uni, + NGX_QUIC_STREAM_BUFSIZE); + + ngx_conf_merge_uint_value(conf->quic.tp.initial_max_streams_bidi, + prev->quic.tp.initial_max_streams_bidi, 16); + + ngx_conf_merge_uint_value(conf->quic.tp.initial_max_streams_uni, + prev->quic.tp.initial_max_streams_uni, 3); + + ngx_conf_merge_uint_value(conf->quic.tp.ack_delay_exponent, + prev->quic.tp.ack_delay_exponent, + NGX_QUIC_DEFAULT_ACK_DELAY_EXPONENT); + + ngx_conf_merge_value(conf->quic.tp.disable_active_migration, + prev->quic.tp.disable_active_migration, 0); + + ngx_conf_merge_uint_value(conf->quic.tp.active_connection_id_limit, + prev->quic.tp.active_connection_id_limit, 2); + + ngx_conf_merge_value(conf->quic.retry, prev->quic.retry, 0); + ngx_conf_merge_value(conf->quic.gso_enabled, prev->quic.gso_enabled, 0); + + ngx_conf_merge_str_value(conf->quic.host_key, prev->quic.host_key, ""); + + if (conf->quic.host_key.len == 0) { + + conf->quic.host_key.len = NGX_QUIC_DEFAULT_HOST_KEY_LEN; + conf->quic.host_key.data = ngx_palloc(cf->pool, + conf->quic.host_key.len); + if (conf->quic.host_key.data == NULL) { + return NGX_CONF_ERROR; + } + + if (RAND_bytes(conf->quic.host_key.data, NGX_QUIC_DEFAULT_HOST_KEY_LEN) + <= 0) + { + return NGX_CONF_ERROR; + } + } + + if (ngx_quic_derive_key(cf->log, "av_token_key", + &conf->quic.host_key, &ngx_http_quic_salt, + conf->quic.av_token_key, NGX_QUIC_AV_KEY_LEN) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + if (ngx_quic_derive_key(cf->log, "sr_token_key", + &conf->quic.host_key, &ngx_http_quic_salt, + conf->quic.sr_token_key, NGX_QUIC_SR_KEY_LEN) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + sscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_ssl_module); + conf->quic.ssl = &sscf->ssl; + 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; +} + + +static char * +ngx_http_quic_host_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_v3_srv_conf_t *h3scf = conf; + + u_char *buf; + size_t size; + ssize_t n; + ngx_str_t *value; + ngx_file_t file; + ngx_file_info_t fi; + ngx_quic_conf_t *qcf; + + qcf = &h3scf->quic; + + if (qcf->host_key.len) { + return "is duplicate"; + } + + buf = NULL; +#if (NGX_SUPPRESS_WARN) + size = 0; +#endif + + value = cf->args->elts; + + if (ngx_conf_full_name(cf->cycle, &value[1], 1) != NGX_OK) { + return NGX_CONF_ERROR; + } + + ngx_memzero(&file, sizeof(ngx_file_t)); + file.name = value[1]; + file.log = cf->log; + + file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + + if (file.fd == NGX_INVALID_FILE) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, + ngx_open_file_n " \"%V\" failed", &file.name); + return NGX_CONF_ERROR; + } + + if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, + ngx_fd_info_n " \"%V\" failed", &file.name); + goto failed; + } + + size = ngx_file_size(&fi); + + if (size == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"%V\" zero key size", &file.name); + goto failed; + } + + buf = ngx_pnalloc(cf->pool, size); + if (buf == NULL) { + goto failed; + } + + n = ngx_read_file(&file, buf, size, 0); + + if (n == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, + ngx_read_file_n " \"%V\" failed", &file.name); + goto failed; + } + + if ((size_t) n != size) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, 0, + ngx_read_file_n " \"%V\" returned only " + "%z bytes instead of %uz", &file.name, n, size); + goto failed; + } + + qcf->host_key.data = buf; + qcf->host_key.len = n; + + if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_close_file_n " \"%V\" failed", &file.name); + } + + return NGX_CONF_OK; + +failed: + + if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_close_file_n " \"%V\" failed", &file.name); + } + + if (buf) { + ngx_explicit_memzero(buf, size); + } + + return NGX_CONF_ERROR; +} + + static void * ngx_http_v3_create_loc_conf(ngx_conf_t *cf) { diff --git a/src/http/v3/ngx_http_v3_request.c b/src/http/v3/ngx_http_v3_request.c index e0c3a71ba..a4b570370 100644 --- a/src/http/v3/ngx_http_v3_request.c +++ b/src/http/v3/ngx_http_v3_request.c @@ -10,6 +10,8 @@ #include +static void ngx_http_v3_init_hq_stream(ngx_connection_t *c); +static void ngx_http_v3_init_request_stream(ngx_connection_t *c); static void ngx_http_v3_wait_request_handler(ngx_event_t *rev); static void ngx_http_v3_cleanup_request(void *data); static void ngx_http_v3_process_request(ngx_event_t *rev); @@ -54,12 +56,36 @@ static const struct { void ngx_http_v3_init(ngx_connection_t *c) { - uint64_t n; - ngx_event_t *rev; - ngx_http_connection_t *hc; - ngx_http_v3_session_t *h3c; + ngx_http_connection_t *hc, *phc; + ngx_http_v3_srv_conf_t *h3scf; ngx_http_core_loc_conf_t *clcf; - ngx_http_core_srv_conf_t *cscf; + + hc = c->data; + + hc->ssl = 1; + + if (c->quic == NULL) { + h3scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v3_module); + + ngx_quic_run(c, &h3scf->quic); + + return; + } + + phc = ngx_http_quic_get_connection(c); + + if (phc->ssl_servername) { + hc->ssl_servername = phc->ssl_servername; + hc->conf_ctx = phc->conf_ctx; + + clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, ngx_http_core_module); + ngx_set_connection_log(c, clcf->error_log); + } + + if (!hc->addr_conf->http3) { + ngx_http_v3_init_hq_stream(c); + return; + } if (ngx_http_v3_init_session(c) != NGX_OK) { ngx_http_close_connection(c); @@ -68,9 +94,91 @@ ngx_http_v3_init(ngx_connection_t *c) if (c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { ngx_http_v3_init_uni_stream(c); + + } else { + ngx_http_v3_init_request_stream(c); + } +} + + +static void +ngx_http_v3_init_hq_stream(ngx_connection_t *c) +{ + uint64_t n; + ngx_event_t *rev; + ngx_http_connection_t *hc; + ngx_http_core_loc_conf_t *clcf; + ngx_http_core_srv_conf_t *cscf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init hq stream"); + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_active, 1); +#endif + + hc = c->data; + + /* Use HTTP/3 General Protocol Error Code 0x101 for finalization */ + + if (c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) { + ngx_quic_finalize_connection(c->quic->parent, + NGX_HTTP_V3_ERR_GENERAL_PROTOCOL_ERROR, + "unexpected uni stream"); + ngx_http_close_connection(c); return; } + clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, ngx_http_core_module); + + n = c->quic->id >> 2; + + if (n >= clcf->keepalive_requests) { + ngx_quic_finalize_connection(c->quic->parent, + NGX_HTTP_V3_ERR_GENERAL_PROTOCOL_ERROR, + "reached maximum number of requests"); + ngx_http_close_connection(c); + return; + } + + if (ngx_current_msec - c->quic->parent->start_time + > clcf->keepalive_time) + { + ngx_quic_finalize_connection(c->quic->parent, + NGX_HTTP_V3_ERR_GENERAL_PROTOCOL_ERROR, + "reached maximum time for requests"); + ngx_http_close_connection(c); + return; + } + + rev = c->read; + + if (rev->ready) { + rev->handler(rev); + return; + } + + cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module); + + ngx_add_timer(rev, cscf->client_header_timeout); + ngx_reusable_connection(c, 1); + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_http_close_connection(c); + return; + } +} + + +static void +ngx_http_v3_init_request_stream(ngx_connection_t *c) +{ + uint64_t n; + ngx_event_t *rev; + ngx_http_connection_t *hc; + ngx_http_v3_session_t *h3c; + ngx_http_core_loc_conf_t *clcf; + ngx_http_core_srv_conf_t *cscf; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init request stream"); #if (NGX_STAT_STUB) @@ -279,8 +387,15 @@ ngx_http_v3_wait_request_handler(ngx_event_t *rev) void ngx_http_v3_reset_connection(ngx_connection_t *c) { + ngx_http_connection_t *hc; ngx_http_v3_srv_conf_t *h3scf; + hc = ngx_http_quic_get_connection(c); + + if (!hc->addr_conf->http3) { + return; + } + h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module); if (h3scf->max_table_capacity > 0 && !c->read->eof) {