diff --git a/gennghttpxfun.py b/gennghttpxfun.py index e8b7fd96..1f925915 100755 --- a/gennghttpxfun.py +++ b/gennghttpxfun.py @@ -188,6 +188,7 @@ OPTIONS = [ "frontend-http3-max-window-size", "frontend-http3-max-connection-window-size", "frontend-http3-max-concurrent-streams", + "frontend-quic-early-data", ] LOGVARS = [ diff --git a/src/shrpx.cc b/src/shrpx.cc index eada0491..42c5fe89 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -2776,12 +2776,13 @@ SSL/TLS: consider to use --client-no-http2-cipher-block-list option. But be aware its implications. --tls-no-postpone-early-data - By default, nghttpx postpones forwarding HTTP requests - sent in early data, including those sent in partially in - it, until TLS handshake finishes. If all backend server - recognizes "Early-Data" header field, using this option - makes nghttpx not postpone forwarding request and get - full potential of 0-RTT data. + By default, except for QUIC connections, nghttpx + postpones forwarding HTTP requests sent in early data, + including those sent in partially in it, until TLS + handshake finishes. If all backend server recognizes + "Early-Data" header field, using this option makes + nghttpx not postpone forwarding request and get full + potential of 0-RTT data. --tls-max-early-data= Sets the maximum amount of 0-RTT data that server accepts. @@ -3209,6 +3210,12 @@ HTTP/3 and QUIC: socket. Default: )" << config->quic.bpf.prog_file << R"( + --frontend-quic-early-data + Enable early data on frontend QUIC connections. nghttpx + sends "Early-Data" header field to a backend server if a + request is received in early data and handshake has not + finished. All backend servers should deal with possibly + replayed requests. --no-quic-bpf Disable eBPF. --frontend-http3-window-size= @@ -3995,6 +4002,7 @@ int main(int argc, char **argv) { required_argument, &flag, 178}, {SHRPX_OPT_FRONTEND_HTTP3_MAX_CONCURRENT_STREAMS.c_str(), required_argument, &flag, 179}, + {SHRPX_OPT_FRONTEND_QUIC_EARLY_DATA.c_str(), no_argument, &flag, 180}, {nullptr, 0, nullptr, 0}}; int option_index = 0; @@ -4852,6 +4860,11 @@ int main(int argc, char **argv) { cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP3_MAX_CONCURRENT_STREAMS, StringRef{optarg}); break; + case 180: + // --frontend-quic-early-data + cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_QUIC_EARLY_DATA, + StringRef::from_lit("yes")); + break; default: break; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index a5e0ae6a..f9bdf279 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -2297,6 +2297,11 @@ int option_lookup_token(const char *name, size_t namelen) { break; case 24: switch (name[23]) { + case 'a': + if (util::strieq_l("frontend-quic-early-dat", name, 23)) { + return SHRPX_OPTID_FRONTEND_QUIC_EARLY_DATA; + } + break; case 'd': if (util::strieq_l("strip-incoming-forwarde", name, 23)) { return SHRPX_OPTID_STRIP_INCOMING_FORWARDED; @@ -3967,6 +3972,12 @@ int parse_config(Config *config, int optid, const StringRef &opt, #else // !ENABLE_HTTP3 return 0; #endif // !ENABLE_HTTP3 + case SHRPX_OPTID_FRONTEND_QUIC_EARLY_DATA: +#ifdef ENABLE_HTTP3 + config->quic.upstream.early_data = util::strieq_l("yes", optarg); +#endif // ENABLE_HTTP3 + + return 0; case SHRPX_OPTID_CONF: LOG(WARN) << "conf: ignored"; diff --git a/src/shrpx_config.h b/src/shrpx_config.h index c2ffcca6..33c0cfa9 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -383,6 +383,8 @@ constexpr auto SHRPX_OPT_FRONTEND_HTTP3_MAX_CONNECTION_WINDOW_SIZE = StringRef::from_lit("frontend-http3-max-connection-window-size"); constexpr auto SHRPX_OPT_FRONTEND_HTTP3_MAX_CONCURRENT_STREAMS = StringRef::from_lit("frontend-http3-max-concurrent-streams"); +constexpr auto SHRPX_OPT_FRONTEND_QUIC_EARLY_DATA = + StringRef::from_lit("frontend-quic-early-data"); constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; @@ -746,6 +748,7 @@ struct QUICConfig { struct { bool log; } debug; + bool early_data; } upstream; struct { StringRef prog_file; @@ -1199,6 +1202,7 @@ enum { SHRPX_OPTID_FRONTEND_MAX_REQUESTS, SHRPX_OPTID_FRONTEND_NO_TLS, SHRPX_OPTID_FRONTEND_QUIC_DEBUG_LOG, + SHRPX_OPTID_FRONTEND_QUIC_EARLY_DATA, SHRPX_OPTID_FRONTEND_QUIC_IDLE_TIMEOUT, SHRPX_OPTID_FRONTEND_READ_TIMEOUT, SHRPX_OPTID_FRONTEND_WRITE_TIMEOUT, diff --git a/src/shrpx_quic_connection_handler.cc b/src/shrpx_quic_connection_handler.cc index 05d85f28..19f9dab1 100644 --- a/src/shrpx_quic_connection_handler.cc +++ b/src/shrpx_quic_connection_handler.cc @@ -259,7 +259,13 @@ ClientHandler *QUICConnectionHandler::handle_new_connection( assert(SSL_is_quic(ssl)); SSL_set_accept_state(ssl); - SSL_set_quic_early_data_enabled(ssl, 1); + + auto config = get_config(); + auto &quicconf = config->quic; + + if (quicconf.upstream.early_data) { + SSL_set_quic_early_data_enabled(ssl, 1); + } // Disable TLS session ticket if we don't have working ticket // keys. diff --git a/src/shrpx_tls.cc b/src/shrpx_tls.cc index a86dc1a5..5fef6cae 100644 --- a/src/shrpx_tls.cc +++ b/src/shrpx_tls.cc @@ -1389,7 +1389,10 @@ SSL_CTX *create_quic_ssl_context(const char *private_key_file, // !defined(OPENSSL_IS_BORINGSSL) # if OPENSSL_1_1_1_API - if (SSL_CTX_set_max_early_data(ssl_ctx, + auto &quicconf = config->quic; + + if (quicconf.upstream.early_data && + SSL_CTX_set_max_early_data(ssl_ctx, std::numeric_limits::max()) != 1) { LOG(FATAL) << "SSL_CTX_set_max_early_data failed: " << ERR_error_string(ERR_get_error(), nullptr);