diff --git a/genheaderfunc.py b/genheaderfunc.py index 4f342364..dfca88a3 100755 --- a/genheaderfunc.py +++ b/genheaderfunc.py @@ -31,6 +31,7 @@ HEADERS = [ "user-agent", "date", "content-type", + "early-data", # disallowed h1 headers 'connection', 'keep-alive', diff --git a/gennghttpxfun.py b/gennghttpxfun.py index 692e675b..d4e996cc 100755 --- a/gennghttpxfun.py +++ b/gennghttpxfun.py @@ -174,6 +174,7 @@ OPTIONS = [ "tls-max-early-data", "tls13-ciphers", "tls13-client-ciphers", + "no-strip-incoming-early-data", ] LOGVARS = [ diff --git a/src/http2.cc b/src/http2.cc index 0402d9c0..01709a84 100644 --- a/src/http2.cc +++ b/src/http2.cc @@ -389,6 +389,11 @@ void copy_headers_to_nva_internal(std::vector &nva, case HD_TRANSFER_ENCODING: case HD_UPGRADE: continue; + case HD_EARLY_DATA: + if (flags & HDOP_STRIP_EARLY_DATA) { + continue; + } + break; case HD_FORWARDED: if (flags & HDOP_STRIP_FORWARDED) { continue; @@ -483,6 +488,11 @@ void build_http1_headers_from_headers(DefaultMemchunks *buf, case HD_SERVER: case HD_UPGRADE: continue; + case HD_EARLY_DATA: + if (flags & HDOP_STRIP_EARLY_DATA) { + continue; + } + break; case HD_FORWARDED: if (flags & HDOP_STRIP_FORWARDED) { continue; @@ -828,6 +838,11 @@ int lookup_token(const uint8_t *name, size_t namelen) { break; case 10: switch (name[9]) { + case 'a': + if (util::streq_l("early-dat", name, 9)) { + return HD_EARLY_DATA; + } + break; case 'e': if (util::streq_l("keep-aliv", name, 9)) { return HD_KEEP_ALIVE; diff --git a/src/http2.h b/src/http2.h index eb6a41d3..be4396e7 100644 --- a/src/http2.h +++ b/src/http2.h @@ -203,9 +203,13 @@ enum HeaderBuildOp { // Via header fields must be stripped. If this flag is not set, all // Via header fields other than last one are added. HDOP_STRIP_VIA = 1 << 3, + // Early-Data header fields must be stripped. If this flag is not + // set, all Early-Data header fields are added. + HDOP_STRIP_EARLY_DATA = 1 << 4, // Strip above all header fields. HDOP_STRIP_ALL = HDOP_STRIP_FORWARDED | HDOP_STRIP_X_FORWARDED_FOR | - HDOP_STRIP_X_FORWARDED_PROTO | HDOP_STRIP_VIA, + HDOP_STRIP_X_FORWARDED_PROTO | HDOP_STRIP_VIA | + HDOP_STRIP_EARLY_DATA, }; // Appends headers in |headers| to |nv|. |headers| must be indexed @@ -304,6 +308,7 @@ enum { HD_CONTENT_TYPE, HD_COOKIE, HD_DATE, + HD_EARLY_DATA, HD_EXPECT, HD_FORWARDED, HD_HOST, diff --git a/src/shrpx.cc b/src/shrpx.cc index c9eb2eda..89d7f893 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -1487,6 +1487,7 @@ void fill_default_config(Config *config) { httpconf.max_requests = std::numeric_limits::max(); httpconf.xfp.add = true; httpconf.xfp.strip_incoming = true; + httpconf.early_data.strip_incoming = true; auto &http2conf = config->http2; { @@ -2644,6 +2645,9 @@ HTTP: Default: obfuscated --no-via Don't append to Via header field. If Via header field is received, it is left unaltered. + --no-strip-incoming-early-data + Don't strip Early-Data header field from inbound client + requests. --no-location-rewrite Don't rewrite location header field in default mode. When --http2-proxy is used, location header field will @@ -3475,6 +3479,8 @@ int main(int argc, char **argv) { {SHRPX_OPT_TLS_MAX_EARLY_DATA.c_str(), required_argument, &flag, 163}, {SHRPX_OPT_TLS13_CIPHERS.c_str(), required_argument, &flag, 164}, {SHRPX_OPT_TLS13_CLIENT_CIPHERS.c_str(), required_argument, &flag, 165}, + {SHRPX_OPT_NO_STRIP_INCOMING_EARLY_DATA.c_str(), no_argument, &flag, + 166}, {nullptr, 0, nullptr, 0}}; int option_index = 0; @@ -4263,6 +4269,11 @@ int main(int argc, char **argv) { // --tls13-client-ciphers cmdcfgs.emplace_back(SHRPX_OPT_TLS13_CLIENT_CIPHERS, StringRef{optarg}); break; + case 166: + // --no-strip-incoming-early-data + cmdcfgs.emplace_back(SHRPX_OPT_NO_STRIP_INCOMING_EARLY_DATA, + StringRef::from_lit("yes")); + break; default: break; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 74194ca9..396880b8 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -2186,6 +2186,11 @@ int option_lookup_token(const char *name, size_t namelen) { break; case 28: switch (name[27]) { + case 'a': + if (util::strieq_l("no-strip-incoming-early-dat", name, 27)) { + return SHRPX_OPTID_NO_STRIP_INCOMING_EARLY_DATA; + } + break; case 'd': if (util::strieq_l("tls-dyn-rec-warmup-threshol", name, 27)) { return SHRPX_OPTID_TLS_DYN_REC_WARMUP_THRESHOLD; @@ -3626,6 +3631,10 @@ int parse_config(Config *config, int optid, const StringRef &opt, case SHRPX_OPTID_TLS_MAX_EARLY_DATA: { return parse_uint_with_unit(&config->tls.max_early_data, opt, optarg); } + case SHRPX_OPTID_NO_STRIP_INCOMING_EARLY_DATA: + config->http.early_data.strip_incoming = !util::strieq_l("yes", optarg); + + return 0; case SHRPX_OPTID_CONF: LOG(WARN) << "conf: ignored"; diff --git a/src/shrpx_config.h b/src/shrpx_config.h index e47fa991..7e023451 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -354,6 +354,8 @@ constexpr auto SHRPX_OPT_TLS_MAX_EARLY_DATA = constexpr auto SHRPX_OPT_TLS13_CIPHERS = StringRef::from_lit("tls13-ciphers"); constexpr auto SHRPX_OPT_TLS13_CLIENT_CIPHERS = StringRef::from_lit("tls13-client-ciphers"); +constexpr auto SHRPX_OPT_NO_STRIP_INCOMING_EARLY_DATA = + StringRef::from_lit("no-strip-incoming-early-data"); constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; @@ -704,6 +706,9 @@ struct HttpConfig { bool add; bool strip_incoming; } xfp; + struct { + bool strip_incoming; + } early_data; std::vector altsvcs; std::vector error_pages; HeaderRefs add_request_headers; @@ -1100,6 +1105,7 @@ enum { SHRPX_OPTID_NO_OCSP, SHRPX_OPTID_NO_SERVER_PUSH, SHRPX_OPTID_NO_SERVER_REWRITE, + SHRPX_OPTID_NO_STRIP_INCOMING_EARLY_DATA, SHRPX_OPTID_NO_STRIP_INCOMING_X_FORWARDED_PROTO, SHRPX_OPTID_NO_VERIFY_OCSP, SHRPX_OPTID_NO_VIA, diff --git a/src/shrpx_http2_downstream_connection.cc b/src/shrpx_http2_downstream_connection.cc index 5e4e8952..313c2481 100644 --- a/src/shrpx_http2_downstream_connection.cc +++ b/src/shrpx_http2_downstream_connection.cc @@ -320,11 +320,13 @@ int Http2DownstreamConnection::push_request_headers() { auto &fwdconf = httpconf.forwarded; auto &xffconf = httpconf.xff; auto &xfpconf = httpconf.xfp; + auto &earlydataconf = httpconf.early_data; uint32_t build_flags = (fwdconf.strip_incoming ? http2::HDOP_STRIP_FORWARDED : 0) | (xffconf.strip_incoming ? http2::HDOP_STRIP_X_FORWARDED_FOR : 0) | - (xfpconf.strip_incoming ? http2::HDOP_STRIP_X_FORWARDED_PROTO : 0); + (xfpconf.strip_incoming ? http2::HDOP_STRIP_X_FORWARDED_PROTO : 0) | + (earlydataconf.strip_incoming ? http2::HDOP_STRIP_EARLY_DATA : 0); http2::copy_headers_to_nva_nocopy(nva, req.fs.headers(), build_flags); diff --git a/src/shrpx_http_downstream_connection.cc b/src/shrpx_http_downstream_connection.cc index e78b868f..1bfadaa1 100644 --- a/src/shrpx_http_downstream_connection.cc +++ b/src/shrpx_http_downstream_connection.cc @@ -540,11 +540,13 @@ int HttpDownstreamConnection::push_request_headers() { auto &fwdconf = httpconf.forwarded; auto &xffconf = httpconf.xff; auto &xfpconf = httpconf.xfp; + auto &earlydataconf = httpconf.early_data; uint32_t build_flags = (fwdconf.strip_incoming ? http2::HDOP_STRIP_FORWARDED : 0) | (xffconf.strip_incoming ? http2::HDOP_STRIP_X_FORWARDED_FOR : 0) | - (xfpconf.strip_incoming ? http2::HDOP_STRIP_X_FORWARDED_PROTO : 0); + (xfpconf.strip_incoming ? http2::HDOP_STRIP_X_FORWARDED_PROTO : 0) | + (earlydataconf.strip_incoming ? http2::HDOP_STRIP_EARLY_DATA : 0); http2::build_http1_headers_from_headers(buf, req.fs.headers(), build_flags);