Version in base suite: 9.2.4+ds-0+deb12u1 Base version: trafficserver_9.2.4+ds-0+deb12u1 Target version: trafficserver_9.2.5+ds-0+deb12u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/t/trafficserver/trafficserver_9.2.4+ds-0+deb12u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/t/trafficserver/trafficserver_9.2.5+ds-0+deb12u1.dsc CHANGELOG-9.2.5 | 11 configure | 30 configure.ac | 4 debian/changelog | 11 doc/admin-guide/files/records.config.en.rst | 12 doc/admin-guide/plugins/ja3_fingerprint.en.rst | 14 doc/admin-guide/plugins/lua.en.rst | 1 doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst | 1 doc/developer-guide/api/types/TSOverridableConfigKey.en.rst | 1 include/ts/apidefs.h.in | 1 include/tscore/History.h | 2 include/tscore/ParseRules.h | 21 include/tscpp/util/TextView.h | 2 iocore/net/SSLConfig.cc | 4 iocore/net/SSLUtils.cc | 58 mgmt/RecordsConfig.cc | 2 plugins/header_rewrite/matcher.h | 4 plugins/lua/ts_lua_http_config.c | 2 proxy/hdrs/MIME.cc | 16 proxy/hdrs/unit_tests/test_Hdrs.cc | 69 proxy/http/HttpConfig.cc | 2 proxy/http/HttpConfig.h | 7 proxy/http/HttpSM.cc | 39 proxy/http/HttpTransact.h | 2 proxy/http/HttpTunnel.cc | 113 - proxy/http/HttpTunnel.h | 40 proxy/http2/Http2ConnectionState.cc | 14 src/shared/overridable_txn_vars.cc | 1 src/traffic_server/FetchSM.cc | 2 src/traffic_server/InkAPI.cc | 3 src/traffic_server/InkAPITest.cc | 3 src/tscore/HostLookup.cc | 1 tests/gold_tests/cache/replay/cache-range-response.replay.yaml | 20 tests/gold_tests/chunked_encoding/chunked_encoding.test.py | 96 + tests/gold_tests/chunked_encoding/replays/chunked_trailer_dropped.replay.yaml | 68 tests/gold_tests/chunked_encoding/replays/chunked_trailer_proxied.replay.yaml | 68 tests/gold_tests/headers/gold/invalid_character_in_te_value.gold | 23 tests/gold_tests/headers/good_request_after_bad.test.py | 2 tests/gold_tests/headers/normalized_ae_match_vary_cache.test.py | 67 tests/gold_tests/headers/replays/normalized_ae_varied_transactions.replay.yaml | 813 ++++++++++ tests/gold_tests/logging/gold/field-json-test.gold | 5 tests/gold_tests/logging/log-field-json.test.py | 5 tests/gold_tests/tls/ssl/passphrase.key | 30 tests/gold_tests/tls/ssl/passphrase.pem | 27 tests/gold_tests/tls/ssl/passphrase2.key | 30 tests/gold_tests/tls/ssl/passphrase2.pem | 27 tests/gold_tests/tls/ssl_key_dialog.test.py | 91 + tools/clang-format.sh | 2 tools/package/trafficserver.spec | 2 49 files changed, 1739 insertions(+), 130 deletions(-) diff -Nru trafficserver-9.2.4+ds/CHANGELOG-9.2.5 trafficserver-9.2.5+ds/CHANGELOG-9.2.5 --- trafficserver-9.2.4+ds/CHANGELOG-9.2.5 1970-01-01 00:00:00.000000000 +0000 +++ trafficserver-9.2.5+ds/CHANGELOG-9.2.5 2024-07-23 21:42:39.000000000 +0000 @@ -0,0 +1,11 @@ +Changes with Apache Traffic Server 9.2.5 + #11226 - ja3_fingerprint.so docs: --modify-incoming + #11263 - [9.2.x] Terminate H2 connection by COMPRESSION_ERROR (#11222) + #11264 - Initialize HistoryEntry array + #11268 - [9.2.x] Fix GCC 14.0.1 -std=c++20 build failures (#11189) + #11348 - Restore private key passphrase behavior + #11351 - Fix case where 206 could be returned for range revalidates (#11308) + #11444 - docs: fix header rewrite nexthop sample usage + #11595 - Stricten field name check + #11596 - Normalize Accept-Encoding header value before cache lookup + #11604 - proxy.config.http.drop_chunked_trailers (9.2.x) diff -Nru trafficserver-9.2.4+ds/configure trafficserver-9.2.5+ds/configure --- trafficserver-9.2.4+ds/configure 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/configure 2024-07-23 21:42:39.000000000 +0000 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for Apache Traffic Server 9.2.4. +# Generated by GNU Autoconf 2.71 for Apache Traffic Server 9.2.5. # # Report bugs to . # @@ -621,8 +621,8 @@ # Identity of this package. PACKAGE_NAME='Apache Traffic Server' PACKAGE_TARNAME='trafficserver' -PACKAGE_VERSION='9.2.4' -PACKAGE_STRING='Apache Traffic Server 9.2.4' +PACKAGE_VERSION='9.2.5' +PACKAGE_STRING='Apache Traffic Server 9.2.5' PACKAGE_BUGREPORT='dev@trafficserver.apache.org' PACKAGE_URL='https://trafficserver.apache.org' @@ -1744,7 +1744,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures Apache Traffic Server 9.2.4 to adapt to many kinds of systems. +\`configure' configures Apache Traffic Server 9.2.5 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1815,7 +1815,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of Apache Traffic Server 9.2.4:";; + short | recursive ) echo "Configuration of Apache Traffic Server 9.2.5:";; esac cat <<\_ACEOF @@ -2065,7 +2065,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -Apache Traffic Server configure 9.2.4 +Apache Traffic Server configure 9.2.5 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. @@ -2879,7 +2879,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by Apache Traffic Server $as_me 9.2.4, which was +It was created by Apache Traffic Server $as_me 9.2.5, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw @@ -4371,7 +4371,7 @@ # Define the identity of the package. PACKAGE='trafficserver' - VERSION='9.2.4' + VERSION='9.2.5' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -4673,13 +4673,13 @@ # convention that attempts to solve problems that most people just # don't have and which just causes confusion for most end users. # -TS_VERSION_MAJOR=$((9002004 / 1000000 )) -TS_VERSION_MINOR=$(((9002004 / 1000) % 1000 )) -TS_VERSION_MICRO=$((9002004 % 1000 )) +TS_VERSION_MAJOR=$((9002005 / 1000000 )) +TS_VERSION_MINOR=$(((9002005 / 1000) % 1000 )) +TS_VERSION_MICRO=$((9002005 % 1000 )) TS_LIBTOOL_MAJOR=`echo $((${TS_VERSION_MAJOR} + ${TS_VERSION_MINOR}))` TS_LIBTOOL_VERSION=$TS_LIBTOOL_MAJOR:$TS_VERSION_MICRO:$TS_VERSION_MINOR -TS_VERSION_STRING=9.2.4 -TS_VERSION_NUMBER=9002004 +TS_VERSION_STRING=9.2.5 +TS_VERSION_NUMBER=9002005 # # Substitute the above version numbers into the various files below. @@ -34772,7 +34772,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by Apache Traffic Server $as_me 9.2.4, which was +This file was extended by Apache Traffic Server $as_me 9.2.5, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -34841,7 +34841,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -Apache Traffic Server config.status 9.2.4 +Apache Traffic Server config.status 9.2.5 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" diff -Nru trafficserver-9.2.4+ds/configure.ac trafficserver-9.2.5+ds/configure.ac --- trafficserver-9.2.4+ds/configure.ac 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/configure.ac 2024-07-23 21:42:39.000000000 +0000 @@ -32,8 +32,8 @@ # Version number is calculated as MAJOR * 1000000 + MINOR * 1000 + MICRO # Version string is in the form of MAJOR.MINOR.MICRO[sufix] # -m4_define([TS_VERSION_S],[9.2.4]) -m4_define([TS_VERSION_N],[9002004]) +m4_define([TS_VERSION_S],[9.2.5]) +m4_define([TS_VERSION_N],[9002005]) AC_INIT([Apache Traffic Server],[TS_VERSION_S()],[dev@trafficserver.apache.org],[trafficserver],[https://trafficserver.apache.org]) AC_PREREQ([2.69]) diff -Nru trafficserver-9.2.4+ds/debian/changelog trafficserver-9.2.5+ds/debian/changelog --- trafficserver-9.2.4+ds/debian/changelog 2024-04-13 09:21:19.000000000 +0000 +++ trafficserver-9.2.5+ds/debian/changelog 2024-08-23 18:20:06.000000000 +0000 @@ -1,3 +1,14 @@ +trafficserver (9.2.5+ds-0+deb12u1) bookworm-security; urgency=medium + + * New upstream version 9.2.5+ds + * CVEs fix (Closes: #1077141) + - CVE-2023-38522: Incomplete field name check allows request smuggling + - CVE-2024-35161: Incomplete check for chunked trailer section allows + request smuggling + - CVE-2024-35296: Invalid Accept-Encoding can force forwarding requests + + -- Jean Baptiste Favre Fri, 23 Aug 2024 20:20:06 +0200 + trafficserver (9.2.4+ds-0+deb12u1) bookworm-security; urgency=medium * New upstream version 9.2.4+ds diff -Nru trafficserver-9.2.4+ds/doc/admin-guide/files/records.config.en.rst trafficserver-9.2.5+ds/doc/admin-guide/files/records.config.en.rst --- trafficserver-9.2.4+ds/doc/admin-guide/files/records.config.en.rst 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/doc/admin-guide/files/records.config.en.rst 2024-07-23 21:42:39.000000000 +0000 @@ -974,6 +974,18 @@ request, this option determines the size of the chunks, in bytes, to use when sending content to an HTTP/1.1 client. +.. ts:cv:: CONFIG proxy.config.http.drop_chunked_trailers INT 0 + :reloadable: + :overridable: + + Specifies whether |TS| should drop chunked trailers. If enabled (``1``), |TS| + will drop any chunked trailers in a ``Transfer-Encoded: chunked`` request or + response body. If disabled (``0``), |TS| will pass the chunked trailers + unmodified to the receiving peer. See `RFC 9112, section 7.1.2 + `_ + for details about chunked trailers. By default, this option is disabled + and therefore |TS| will not drop chunked trailers. + .. ts:cv:: CONFIG proxy.config.http.send_http11_requests INT 1 :reloadable: :overridable: diff -Nru trafficserver-9.2.4+ds/doc/admin-guide/plugins/ja3_fingerprint.en.rst trafficserver-9.2.5+ds/doc/admin-guide/plugins/ja3_fingerprint.en.rst --- trafficserver-9.2.4+ds/doc/admin-guide/plugins/ja3_fingerprint.en.rst 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/doc/admin-guide/plugins/ja3_fingerprint.en.rst 2024-07-23 21:42:39.000000000 +0000 @@ -55,7 +55,6 @@ .. option:: --ja3log - This option enables logging to the file ``ja3_fingerprint.log`` in the standard logging directory. The format is :: @@ -63,6 +62,19 @@ By default this is not enabled. +.. option:: --modify-incoming + + As described above, typically, the ``X-JA3-Sig`` header is added to the request as it is sent + upstream so that any upstream hosts can make use of it. The ``--modify-incoming`` option + instructs the plugin to add the ``X-JA3-Sig`` header field earlier on the incoming request so + that other plugins can make use of it while processing the request. To be precise, + ``--modify-incoming`` adds the ``X-JA3-Sig`` header field in the + ``TS_HTTP_READ_REQUEST_HDR_HOOK`` hook rather than the default ``TS_HTTP_SEND_REQUEST_HDR_HOOK`` + hook. + + This option is only useful when the plugin is configured as a global plugin. By default this + is not enabled. + Requirement ============= diff -Nru trafficserver-9.2.4+ds/doc/admin-guide/plugins/lua.en.rst trafficserver-9.2.5+ds/doc/admin-guide/plugins/lua.en.rst --- trafficserver-9.2.4+ds/doc/admin-guide/plugins/lua.en.rst 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/doc/admin-guide/plugins/lua.en.rst 2024-07-23 21:42:39.000000000 +0000 @@ -4167,6 +4167,7 @@ TS_LUA_CONFIG_NET_SOCK_PACKET_TOS_OUT TS_LUA_CONFIG_HTTP_INSERT_AGE_IN_RESPONSE TS_LUA_CONFIG_HTTP_CHUNKING_SIZE + TS_LUA_CONFIG_HTTP_DROP_CHUNKED_TRAILERS TS_LUA_CONFIG_HTTP_FLOW_CONTROL_ENABLED TS_LUA_CONFIG_HTTP_FLOW_CONTROL_LOW_WATER_MARK TS_LUA_CONFIG_HTTP_FLOW_CONTROL_HIGH_WATER_MARK diff -Nru trafficserver-9.2.4+ds/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst trafficserver-9.2.5+ds/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst --- trafficserver-9.2.4+ds/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst 2024-07-23 21:42:39.000000000 +0000 @@ -112,6 +112,7 @@ :c:enumerator:`TS_CONFIG_HTTP_CHUNKING_ENABLED` :ts:cv:`proxy.config.http.chunking_enabled` :c:enumerator:`TS_CONFIG_HTTP_CHUNKING_SIZE` :ts:cv:`proxy.config.http.chunking.size` :c:enumerator:`TS_CONFIG_HTTP_CONNECT_ATTEMPTS_MAX_RETRIES_DEAD_SERVER` :ts:cv:`proxy.config.http.connect_attempts_max_retries_dead_server` +:c:enumerator:`TS_CONFIG_HTTP_DROP_CHUNKED_TRAILERS` :ts:cv:`proxy.config.http.drop_chunked_trailers` :c:enumerator:`TS_CONFIG_HTTP_CONNECT_ATTEMPTS_MAX_RETRIES` :ts:cv:`proxy.config.http.connect_attempts_max_retries` :c:enumerator:`TS_CONFIG_HTTP_CONNECT_ATTEMPTS_RR_RETRIES` :ts:cv:`proxy.config.http.connect_attempts_rr_retries` :c:enumerator:`TS_CONFIG_HTTP_CONNECT_ATTEMPTS_TIMEOUT` :ts:cv:`proxy.config.http.connect_attempts_timeout` diff -Nru trafficserver-9.2.4+ds/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst trafficserver-9.2.5+ds/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst --- trafficserver-9.2.4+ds/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst 2024-07-23 21:42:39.000000000 +0000 @@ -91,6 +91,7 @@ .. c:enumerator:: TS_CONFIG_NET_SOCK_PACKET_TOS_OUT .. c:enumerator:: TS_CONFIG_HTTP_INSERT_AGE_IN_RESPONSE .. c:enumerator:: TS_CONFIG_HTTP_CHUNKING_SIZE +.. c:enumerator:: TS_CONFIG_HTTP_DROP_CHUNKED_TRAILERS .. c:enumerator:: TS_CONFIG_HTTP_FLOW_CONTROL_ENABLED .. c:enumerator:: TS_CONFIG_HTTP_FLOW_CONTROL_LOW_WATER_MARK .. c:enumerator:: TS_CONFIG_HTTP_FLOW_CONTROL_HIGH_WATER_MARK diff -Nru trafficserver-9.2.4+ds/include/ts/apidefs.h.in trafficserver-9.2.5+ds/include/ts/apidefs.h.in --- trafficserver-9.2.4+ds/include/ts/apidefs.h.in 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/include/ts/apidefs.h.in 2024-07-23 21:42:39.000000000 +0000 @@ -874,6 +874,7 @@ TS_CONFIG_BODY_FACTORY_RESPONSE_SUPPRESSION_MODE, TS_CONFIG_HTTP_ENABLE_PARENT_TIMEOUT_MARKDOWNS, TS_CONFIG_HTTP_DISABLE_PARENT_MARKDOWNS, + TS_CONFIG_HTTP_DROP_CHUNKED_TRAILERS, TS_CONFIG_LAST_ENTRY } TSOverridableConfigKey; diff -Nru trafficserver-9.2.4+ds/include/tscore/History.h trafficserver-9.2.5+ds/include/tscore/History.h --- trafficserver-9.2.4+ds/include/tscore/History.h 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/include/tscore/History.h 2024-07-23 21:42:39.000000000 +0000 @@ -74,7 +74,7 @@ } private: - HistoryEntry history[Count]; + HistoryEntry history[Count] = {}; unsigned int history_pos = 0; }; diff -Nru trafficserver-9.2.4+ds/include/tscore/ParseRules.h trafficserver-9.2.5+ds/include/tscore/ParseRules.h --- trafficserver-9.2.4+ds/include/tscore/ParseRules.h 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/include/tscore/ParseRules.h 2024-07-23 21:42:39.000000000 +0000 @@ -128,9 +128,9 @@ static CTypeResult is_empty(char c); // wslfcr,# static CTypeResult is_alnum(char c); // 0-9,A-Z,a-z static CTypeResult is_space(char c); // ' ' HT,VT,NP,CR,LF - static CTypeResult is_control(char c); // 0-31 127 - static CTypeResult is_mime_sep(char c); // ()<>,;\"/[]?{} \t - static CTypeResult is_http_field_name(char c); // not : or mime_sep except for @ + static CTypeResult is_control(char c); // 0x00-0x08, 0x0a-0x1f, 0x7f + static CTypeResult is_mime_sep(char c); // @()<>,;\"/[]?{} \t + static CTypeResult is_http_field_name(char c); // not :, =, 0x80+, control, or mime_sep except for @ static CTypeResult is_http_field_value(char c); // not CR, LF, comma, or " ////////////////// @@ -667,14 +667,24 @@ #endif } +/** + Return true if @c is a control char except HTAB(0x09) and SP(0x20). + If you need to check @c is HTAB or SP, use `ParseRules::is_ws`. + */ inline CTypeResult ParseRules::is_control(char c) { #ifndef COMPILE_PARSE_RULES return (parseRulesCType[(unsigned char)c] & is_control_BIT); #else - if (((unsigned char)c) < 32 || ((unsigned char)c) == 127) + if (c == CHAR_HT || c == CHAR_SP) { + return false; + } + + if (((unsigned char)c) < 0x20 || c == 0x7f) { return true; + } + return false; #endif } @@ -698,8 +708,9 @@ #ifndef COMPILE_PARSE_RULES return (parseRulesCType[(unsigned char)c] & is_http_field_name_BIT); #else - if ((c == ':') || (is_mime_sep(c) && (c != '@'))) + if (!is_char(c) || is_control(c) || (is_mime_sep(c) && c != '@') || c == '=' || c == ':') { return false; + } return true; #endif } diff -Nru trafficserver-9.2.4+ds/include/tscpp/util/TextView.h trafficserver-9.2.5+ds/include/tscpp/util/TextView.h --- trafficserver-9.2.4+ds/include/tscpp/util/TextView.h 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/include/tscpp/util/TextView.h 2024-07-23 21:42:39.000000000 +0000 @@ -621,7 +621,7 @@ static_assert(0 < N && N <= 36, "Radix must be in the range 1..36"); uintmax_t zret{0}; uintmax_t v; - while (src.size() && (0 <= (v = ts::svtoi_convert[static_cast(*src)])) && v < N) { + while (src.size() && ((v = ts::svtoi_convert[static_cast(*src)]) < N)) { auto n = zret * N + v; if (n < zret) { // overflow / wrap return std::numeric_limits::max(); diff -Nru trafficserver-9.2.4+ds/iocore/net/SSLConfig.cc trafficserver-9.2.5+ds/iocore/net/SSLConfig.cc --- trafficserver-9.2.4+ds/iocore/net/SSLConfig.cc 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/iocore/net/SSLConfig.cc 2024-07-23 21:42:39.000000000 +0000 @@ -910,7 +910,9 @@ biop = BIO_new_mem_buf(secret_data.data(), secret_data.size()); } - key = PEM_read_bio_PrivateKey(biop, nullptr, nullptr, nullptr); + pem_password_cb *password_cb = SSL_CTX_get_default_passwd_cb(client_ctx.get()); + void *u = SSL_CTX_get_default_passwd_cb_userdata(client_ctx.get()); + key = PEM_read_bio_PrivateKey(biop, nullptr, password_cb, u); if (!key) { SSLError("failed to load client private key file from %s", key_file_name.c_str()); goto fail; diff -Nru trafficserver-9.2.4+ds/iocore/net/SSLUtils.cc trafficserver-9.2.5+ds/iocore/net/SSLUtils.cc --- trafficserver-9.2.4+ds/iocore/net/SSLUtils.cc 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/iocore/net/SSLUtils.cc 2024-07-23 21:42:39.000000000 +0000 @@ -701,18 +701,6 @@ #endif /* TS_HAS_TLS_SESSION_TICKET */ } -struct passphrase_cb_userdata { - const SSLConfigParams *_configParams; - const char *_serverDialog; - const char *_serverCert; - const char *_serverKey; - - passphrase_cb_userdata(const SSLConfigParams *params, const char *dialog, const char *cert, const char *key) - : _configParams(params), _serverDialog(dialog), _serverCert(cert), _serverKey(key) - { - } -}; - // RAII implementation for struct termios struct ssl_termios : public termios { ssl_termios(int fd) @@ -788,15 +776,18 @@ return 0; } - *buf = 0; - passphrase_cb_userdata *ud = static_cast(userdata); + *buf = 0; + const SSLMultiCertConfigParams *sslMultCertSettings = static_cast(userdata); - Debug("ssl_load", "ssl_private_key_passphrase_callback_exec rwflag=%d serverDialog=%s", rwflag, ud->_serverDialog); + Debug("ssl_load", "ssl_private_key_passphrase_callback_exec rwflag=%d serverDialog=%s", rwflag, + sslMultCertSettings->dialog.get()); // only respond to reading private keys, not writing them (does ats even do that?) if (0 == rwflag) { // execute the dialog program and use the first line output as the passphrase - FILE *f = popen(ud->_serverDialog, "r"); + ink_assert(strncmp(sslMultCertSettings->dialog, "exec:", 5) == 0); + const char *serverDialog = &sslMultCertSettings->dialog[5]; + FILE *f = popen(serverDialog, "r"); if (f) { if (fgets(buf, size, f)) { // remove any ending CR or LF @@ -809,7 +800,7 @@ } pclose(f); } else { // popen failed - Error("could not open dialog '%s' - %s", ud->_serverDialog, strerror(errno)); + Error("could not open dialog '%s' - %s", serverDialog, strerror(errno)); } } return strlen(buf); @@ -822,19 +813,19 @@ return 0; } - *buf = 0; - passphrase_cb_userdata *ud = static_cast(userdata); + *buf = 0; + const SSLMultiCertConfigParams *sslMultCertSettings = static_cast(userdata); - Debug("ssl_load", "ssl_private_key_passphrase_callback rwflag=%d serverDialog=%s", rwflag, ud->_serverDialog); + Debug("ssl_load", "ssl_private_key_passphrase_callback rwflag=%d serverDialog=%s", rwflag, sslMultCertSettings->dialog.get()); // only respond to reading private keys, not writing them (does ats even do that?) if (0 == rwflag) { // output request fprintf(stdout, "Some of your private key files are encrypted for security reasons.\n"); fprintf(stdout, "In order to read them you have to provide the pass phrases.\n"); - fprintf(stdout, "ssl_cert_name=%s", ud->_serverCert); - if (ud->_serverKey) { // output ssl_key_name if provided - fprintf(stdout, " ssl_key_name=%s", ud->_serverKey); + fprintf(stdout, "ssl_cert_name=%s", sslMultCertSettings->cert.get()); + if (sslMultCertSettings->key.get()) { // output ssl_key_name if provided + fprintf(stdout, " ssl_key_name=%s", sslMultCertSettings->key.get()); } fprintf(stdout, "\n"); // get passphrase @@ -1018,7 +1009,10 @@ #endif if (pkey == nullptr) { scoped_BIO bio(BIO_new_mem_buf(secret_data, secret_data_len)); - pkey = PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr); + + pem_password_cb *password_cb = SSL_CTX_get_default_passwd_cb(ctx); + void *u = SSL_CTX_get_default_passwd_cb_userdata(ctx); + pkey = PEM_read_bio_PrivateKey(bio.get(), nullptr, password_cb, u); if (nullptr == pkey) { Debug("ssl_load", "failed to load server private key (%.*s) from %s", secret_data_len < 50 ? secret_data_len : 50, secret_data, (!keyPath || keyPath[0] == '\0') ? "[empty key path]" : keyPath); @@ -1451,16 +1445,14 @@ SSLMultiCertConfigLoader::_setup_dialog(SSL_CTX *ctx, const SSLMultiCertConfigParams *sslMultCertSettings) { if (sslMultCertSettings->dialog) { - passphrase_cb_userdata ud(this->_params, sslMultCertSettings->dialog, sslMultCertSettings->first_cert, - sslMultCertSettings->key); // pass phrase dialog configuration pem_password_cb *passwd_cb = nullptr; if (strncmp(sslMultCertSettings->dialog, "exec:", 5) == 0) { - ud._serverDialog = &sslMultCertSettings->dialog[5]; + const char *serverDialog = &sslMultCertSettings->dialog[5]; + Debug("ssl_load", "exec:%s", serverDialog); // validate the exec program - if (!ssl_private_key_validate_exec(ud._serverDialog)) { - SSLError("failed to access '%s' pass phrase program: %s", (const char *)ud._serverDialog, strerror(errno)); - memset(static_cast(&ud), 0, sizeof(ud)); + if (!ssl_private_key_validate_exec(serverDialog)) { + SSLError("failed to access '%s' pass phrase program: %s", serverDialog, strerror(errno)); return false; } passwd_cb = ssl_private_key_passphrase_callback_exec; @@ -1468,13 +1460,10 @@ passwd_cb = ssl_private_key_passphrase_callback_builtin; } else { // unknown config SSLError("unknown %s configuration value '%s'", SSL_KEY_DIALOG.data(), (const char *)sslMultCertSettings->dialog); - memset(static_cast(&ud), 0, sizeof(ud)); return false; } SSL_CTX_set_default_passwd_cb(ctx, passwd_cb); - SSL_CTX_set_default_passwd_cb_userdata(ctx, &ud); - // Clear any password info lingering in the UD data structure - memset(static_cast(&ud), 0, sizeof(ud)); + SSL_CTX_set_default_passwd_cb_userdata(ctx, const_cast(sslMultCertSettings)); } return true; } @@ -2576,6 +2565,7 @@ void SSLMultiCertConfigLoader::clear_pw_references(SSL_CTX *ssl_ctx) { + Debug("ssl_load", "clearing pw preferences"); SSL_CTX_set_default_passwd_cb(ssl_ctx, nullptr); SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, nullptr); } diff -Nru trafficserver-9.2.4+ds/mgmt/RecordsConfig.cc trafficserver-9.2.5+ds/mgmt/RecordsConfig.cc --- trafficserver-9.2.4+ds/mgmt/RecordsConfig.cc 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/mgmt/RecordsConfig.cc 2024-07-23 21:42:39.000000000 +0000 @@ -361,6 +361,8 @@ , {RECT_CONFIG, "proxy.config.http.chunking.size", RECD_INT, "4096", RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , + {RECT_CONFIG, "proxy.config.http.drop_chunked_trailers", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_NULL, "[0-1]", RECA_NULL} + , {RECT_CONFIG, "proxy.config.http.flow_control.enabled", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , {RECT_CONFIG, "proxy.config.http.flow_control.high_water", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL} diff -Nru trafficserver-9.2.4+ds/plugins/header_rewrite/matcher.h trafficserver-9.2.5+ds/plugins/header_rewrite/matcher.h --- trafficserver-9.2.4+ds/plugins/header_rewrite/matcher.h 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/plugins/header_rewrite/matcher.h 2024-07-23 21:42:39.000000000 +0000 @@ -67,7 +67,7 @@ template class Matchers : public Matcher { public: - explicit Matchers(const MatcherOps op) : Matcher(op), _data() {} + explicit Matchers(const MatcherOps op) : Matcher(op), _data() {} // Getters / setters const T & get() const @@ -218,7 +218,7 @@ template <> class Matchers : public Matcher { public: - explicit Matchers(const MatcherOps op) : Matcher(op) {} + explicit Matchers(const MatcherOps op) : Matcher(op) {} void set(const std::string &data) diff -Nru trafficserver-9.2.4+ds/plugins/lua/ts_lua_http_config.c trafficserver-9.2.5+ds/plugins/lua/ts_lua_http_config.c --- trafficserver-9.2.4+ds/plugins/lua/ts_lua_http_config.c 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/plugins/lua/ts_lua_http_config.c 2024-07-23 21:42:39.000000000 +0000 @@ -84,6 +84,7 @@ TS_LUA_CONFIG_NET_SOCK_PACKET_TOS_OUT = TS_CONFIG_NET_SOCK_PACKET_TOS_OUT, TS_LUA_CONFIG_HTTP_INSERT_AGE_IN_RESPONSE = TS_CONFIG_HTTP_INSERT_AGE_IN_RESPONSE, TS_LUA_CONFIG_HTTP_CHUNKING_SIZE = TS_CONFIG_HTTP_CHUNKING_SIZE, + TS_LUA_CONFIG_HTTP_DROP_CHUNKED_TRAILERS = TS_CONFIG_HTTP_DROP_CHUNKED_TRAILERS, TS_LUA_CONFIG_HTTP_FLOW_CONTROL_ENABLED = TS_CONFIG_HTTP_FLOW_CONTROL_ENABLED, TS_LUA_CONFIG_HTTP_FLOW_CONTROL_LOW_WATER_MARK = TS_CONFIG_HTTP_FLOW_CONTROL_LOW_WATER_MARK, TS_LUA_CONFIG_HTTP_FLOW_CONTROL_HIGH_WATER_MARK = TS_CONFIG_HTTP_FLOW_CONTROL_HIGH_WATER_MARK, @@ -221,6 +222,7 @@ TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_NET_SOCK_PACKET_TOS_OUT), TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_INSERT_AGE_IN_RESPONSE), TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_CHUNKING_SIZE), + TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_DROP_CHUNKED_TRAILERS), TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_FLOW_CONTROL_ENABLED), TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_FLOW_CONTROL_LOW_WATER_MARK), TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_FLOW_CONTROL_HIGH_WATER_MARK), diff -Nru trafficserver-9.2.4+ds/proxy/hdrs/MIME.cc trafficserver-9.2.5+ds/proxy/hdrs/MIME.cc --- trafficserver-9.2.4+ds/proxy/hdrs/MIME.cc 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/proxy/hdrs/MIME.cc 2024-07-23 21:42:39.000000000 +0000 @@ -2613,6 +2613,22 @@ int field_name_wks_idx = hdrtoken_tokenize(field_name.data(), field_name.size()); + if (field_name_wks_idx < 0) { + for (auto i : field_name) { + if (!ParseRules::is_http_field_name(i)) { + return PARSE_RESULT_ERROR; + } + } + } + + // RFC 9110 Section 5.5. Field Values + for (char i : field_value) { + // FIXME: ParseRules::is_http_field_value() should be used but the implementation looks wrong + if (ParseRules::is_control(i)) { + return PARSE_RESULT_ERROR; + } + } + /////////////////////////////////////////// // build and insert the new field object // /////////////////////////////////////////// diff -Nru trafficserver-9.2.4+ds/proxy/hdrs/unit_tests/test_Hdrs.cc trafficserver-9.2.5+ds/proxy/hdrs/unit_tests/test_Hdrs.cc --- trafficserver-9.2.4+ds/proxy/hdrs/unit_tests/test_Hdrs.cc 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/proxy/hdrs/unit_tests/test_Hdrs.cc 2024-07-23 21:42:39.000000000 +0000 @@ -535,6 +535,73 @@ mime_init(); http_init(); + SECTION("Field Char Check") + { + static struct { + std::string_view line; + ParseResult expected; + } test_cases[] = { + //// + // Field Name + {"Content-Length: 10\r\n", PARSE_RESULT_CONT}, + {"Content-Length\x0b: 10\r\n", PARSE_RESULT_ERROR}, + {"Content-Length\xff: 10\r\n", PARSE_RESULT_ERROR}, + // Delimiters in field name + {"delimiter_\": 10\r\n", PARSE_RESULT_ERROR}, + {"delimiter_(: 0\r\n", PARSE_RESULT_ERROR}, + {"delimiter_): 0\r\n", PARSE_RESULT_ERROR}, + {"delimiter_,: 0\r\n", PARSE_RESULT_ERROR}, + {"delimiter_/: 0\r\n", PARSE_RESULT_ERROR}, + {"delimiter_:: 0\r\n", PARSE_RESULT_CONT}, // Parsed as field name "delimiter_" and field value ": 0", which is valid + {"delimiter_;: 0\r\n", PARSE_RESULT_ERROR}, + {"delimiter_<: 0\r\n", PARSE_RESULT_ERROR}, + {"delimiter_=: 0\r\n", PARSE_RESULT_ERROR}, + {"delimiter_>: 0\r\n", PARSE_RESULT_ERROR}, + {"delimiter_?: 0\r\n", PARSE_RESULT_ERROR}, + {"delimiter_@: 0\r\n", PARSE_RESULT_CONT}, // Not allowed by the spec, but we use it as internal header indicator + {"delimiter_[: 0\r\n", PARSE_RESULT_ERROR}, + {"delimiter_\\: 0\r\n", PARSE_RESULT_ERROR}, + {"delimiter_]: 0\r\n", PARSE_RESULT_ERROR}, + {"delimiter_{: 0\r\n", PARSE_RESULT_ERROR}, + {"delimiter_}: 0\r\n", PARSE_RESULT_ERROR}, + //// + // Field Value + // SP + {"Content-Length: 10\r\n", PARSE_RESULT_CONT}, + // HTAB + {"Foo: ab\td/cd\r\n", PARSE_RESULT_CONT}, + // VCHAR + {"Foo: ab\x21/cd\r\n", PARSE_RESULT_CONT}, + {"Foo: ab\x7e/cd\r\n", PARSE_RESULT_CONT}, + // DEL + {"Foo: ab\x7f/cd\r\n", PARSE_RESULT_ERROR}, + // obs-text + {"Foo: ab\x80/cd\r\n", PARSE_RESULT_CONT}, + {"Foo: ab\xff/cd\r\n", PARSE_RESULT_CONT}, + // control char + {"Content-Length: 10\x0b\r\n", PARSE_RESULT_ERROR}, + {"Content-Length:\x0b 10\r\n", PARSE_RESULT_ERROR}, + {"Foo: ab\x1d/cd\r\n", PARSE_RESULT_ERROR}, + }; + + MIMEHdr hdr; + MIMEParser parser; + mime_parser_init(&parser); + + for (const auto &t : test_cases) { + mime_parser_clear(&parser); + + const char *start = t.line.data(); + const char *end = start + t.line.size(); + + int r = hdr.parse(&parser, &start, end, false, false, false); + if (r != t.expected) { + std::printf("Expected %s is %s, but not", t.line.data(), t.expected == PARSE_RESULT_ERROR ? "invalid" : "valid"); + CHECK(false); + } + } + } + SECTION("Test parse date") { static struct { @@ -834,13 +901,11 @@ "Cache-Control: private\r\n" "accept: foo\r\n" "accept: bar\n" - ": (null) field name\r\n" "aCCept: \n" "ACCEPT\r\n" "foo: bar\r\n" "foo: argh\r\n" "foo: three, four\r\n" - "word word: word \r\n" "accept: \"fazzle, dazzle\"\r\n" "accept: 1, 2, 3, 4, 5, 6, 7, 8\r\n" "continuation: part1\r\n" diff -Nru trafficserver-9.2.4+ds/proxy/http/HttpConfig.cc trafficserver-9.2.5+ds/proxy/http/HttpConfig.cc --- trafficserver-9.2.4+ds/proxy/http/HttpConfig.cc 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/proxy/http/HttpConfig.cc 2024-07-23 21:42:39.000000000 +0000 @@ -1189,6 +1189,7 @@ HttpEstablishStaticConfigByte(c.oride.keep_alive_enabled_out, "proxy.config.http.keep_alive_enabled_out"); HttpEstablishStaticConfigByte(c.oride.chunking_enabled, "proxy.config.http.chunking_enabled"); HttpEstablishStaticConfigLongLong(c.oride.http_chunking_size, "proxy.config.http.chunking.size"); + HttpEstablishStaticConfigByte(c.oride.http_drop_chunked_trailers, "proxy.config.http.drop_chunked_trailers"); HttpEstablishStaticConfigByte(c.oride.flow_control_enabled, "proxy.config.http.flow_control.enabled"); HttpEstablishStaticConfigLongLong(c.oride.flow_high_water_mark, "proxy.config.http.flow_control.high_water"); HttpEstablishStaticConfigLongLong(c.oride.flow_low_water_mark, "proxy.config.http.flow_control.low_water"); @@ -1494,6 +1495,7 @@ params->oride.keep_alive_enabled_in = INT_TO_BOOL(m_master.oride.keep_alive_enabled_in); params->oride.keep_alive_enabled_out = INT_TO_BOOL(m_master.oride.keep_alive_enabled_out); params->oride.chunking_enabled = INT_TO_BOOL(m_master.oride.chunking_enabled); + params->oride.http_drop_chunked_trailers = m_master.oride.http_drop_chunked_trailers; params->oride.auth_server_session_private = INT_TO_BOOL(m_master.oride.auth_server_session_private); params->oride.http_chunking_size = m_master.oride.http_chunking_size; diff -Nru trafficserver-9.2.4+ds/proxy/http/HttpConfig.h trafficserver-9.2.5+ds/proxy/http/HttpConfig.h --- trafficserver-9.2.4+ds/proxy/http/HttpConfig.h 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/proxy/http/HttpConfig.h 2024-07-23 21:42:39.000000000 +0000 @@ -701,9 +701,10 @@ MgmtInt background_fill_active_timeout = 60; - MgmtInt http_chunking_size = 4096; // Maximum chunk size for chunked output. - MgmtInt flow_high_water_mark = 0; ///< Flow control high water mark. - MgmtInt flow_low_water_mark = 0; ///< Flow control low water mark. + MgmtInt http_chunking_size = 4096; // Maximum chunk size for chunked output. + MgmtByte http_drop_chunked_trailers = 0; ///< Whether to drop chunked trailers. + MgmtInt flow_high_water_mark = 0; ///< Flow control high water mark. + MgmtInt flow_low_water_mark = 0; ///< Flow control low water mark. MgmtInt default_buffer_size_index = 8; MgmtInt default_buffer_water_mark = 32768; diff -Nru trafficserver-9.2.4+ds/proxy/http/HttpSM.cc trafficserver-9.2.5+ds/proxy/http/HttpSM.cc --- trafficserver-9.2.4+ds/proxy/http/HttpSM.cc 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/proxy/http/HttpSM.cc 2024-07-23 21:42:39.000000000 +0000 @@ -978,7 +978,8 @@ ua_txn->get_remote_reader()->consume(client_request_body_bytes); p = tunnel.add_producer(ua_entry->vc, post_bytes, buf_start, &HttpSM::tunnel_handler_post_ua, HT_BUFFER_READ, "ua post buffer"); if (chunked) { - tunnel.set_producer_chunking_action(p, 0, TCA_PASSTHRU_CHUNKED_CONTENT); + bool const drop_chunked_trailers = t_state.http_config_param->oride.http_drop_chunked_trailers == 1; + tunnel.set_producer_chunking_action(p, 0, TCA_PASSTHRU_CHUNKED_CONTENT, drop_chunked_trailers); } ua_entry->in_tunnel = true; ua_txn->set_inactivity_timeout(HRTIME_SECONDS(t_state.txn_conf->transaction_no_activity_timeout_in)); @@ -4777,10 +4778,13 @@ } } else { // if revalidating and cache is stale we want to transform - if (t_state.cache_info.action == HttpTransact::CACHE_DO_REPLACE && - t_state.hdr_info.server_response.status_get() == HTTP_STATUS_OK) { - Debug("http_range", "Serving transform after stale cache re-serve"); - do_transform = true; + if (t_state.cache_info.action == HttpTransact::CACHE_DO_REPLACE) { + if (t_state.hdr_info.server_response.status_get() == HTTP_STATUS_OK) { + Debug("http_range", "Serving transform after stale cache re-serve"); + do_transform = true; + } else { + Debug("http_range", "Not transforming after revalidate"); + } } else if (cache_sm.cache_read_vc && cache_sm.cache_read_vc->is_pread_capable()) { // If only one range entry and pread is capable, no need transform range t_state.range_setup = HttpTransact::RANGE_NOT_TRANSFORM_REQUESTED; @@ -4861,8 +4865,10 @@ HttpCacheKey key; Cache::generate_key(&key, c_url, t_state.txn_conf->cache_generation_number); + t_state.hdr_info.cache_request.copy(&t_state.hdr_info.client_request); + HttpTransactHeaders::normalize_accept_encoding(t_state.txn_conf, &t_state.hdr_info.cache_request); Action *cache_action_handle = cache_sm.open_read( - &key, c_url, &t_state.hdr_info.client_request, t_state.txn_conf, + &key, c_url, &t_state.hdr_info.cache_request, t_state.txn_conf, static_cast((t_state.cache_control.pin_in_cache_for < 0) ? 0 : t_state.cache_control.pin_in_cache_for)); // // pin_in_cache value is an open_write parameter. @@ -4976,7 +4982,7 @@ Cache::generate_key(&key, s_url, t_state.txn_conf->cache_generation_number); Action *cache_action_handle = - c_sm->open_write(&key, s_url, &t_state.hdr_info.client_request, object_read_info, + c_sm->open_write(&key, s_url, &t_state.hdr_info.cache_request, object_read_info, static_cast((t_state.cache_control.pin_in_cache_for < 0) ? 0 : t_state.cache_control.pin_in_cache_for), retry, allow_multiple); if (cache_action_handle != ACTION_RESULT_DONE) { @@ -6156,10 +6162,11 @@ // The user agent may support chunked (HTTP/1.1) or not (HTTP/2) // In either case, the server will support chunked (HTTP/1.1) if (chunked) { + bool const drop_chunked_trailers = t_state.http_config_param->oride.http_drop_chunked_trailers == 1; if (ua_txn->is_chunked_encoding_supported()) { - tunnel.set_producer_chunking_action(p, 0, TCA_PASSTHRU_CHUNKED_CONTENT); + tunnel.set_producer_chunking_action(p, 0, TCA_PASSTHRU_CHUNKED_CONTENT, drop_chunked_trailers); } else { - tunnel.set_producer_chunking_action(p, 0, TCA_CHUNK_CONTENT); + tunnel.set_producer_chunking_action(p, 0, TCA_CHUNK_CONTENT, drop_chunked_trailers); tunnel.set_producer_chunking_size(p, 0); } } @@ -6567,7 +6574,8 @@ // this only applies to read-while-write cases where origin server sends a dynamically generated chunked content // w/o providing a Content-Length header if (t_state.client_info.receive_chunked_response) { - tunnel.set_producer_chunking_action(p, client_response_hdr_bytes, TCA_CHUNK_CONTENT); + bool const drop_chunked_trailers = t_state.http_config_param->oride.http_drop_chunked_trailers == 1; + tunnel.set_producer_chunking_action(p, client_response_hdr_bytes, TCA_CHUNK_CONTENT, drop_chunked_trailers); tunnel.set_producer_chunking_size(p, t_state.txn_conf->http_chunking_size); } ua_entry->in_tunnel = true; @@ -6884,7 +6892,7 @@ if (t_state.current.server->transfer_encoding == HttpTransact::CHUNKED_ENCODING) { client_response_hdr_bytes = 0; // fixed by YTS Team, yamsat - tunnel.set_producer_chunking_action(p, client_response_hdr_bytes, TCA_DECHUNK_CONTENT); + tunnel.set_producer_chunking_action(p, client_response_hdr_bytes, TCA_DECHUNK_CONTENT, HttpTunnel::DROP_CHUNKED_TRAILERS); } return p; @@ -6923,7 +6931,8 @@ this->setup_plugin_agents(p, client_response_hdr_bytes); if (t_state.client_info.receive_chunked_response) { - tunnel.set_producer_chunking_action(p, client_response_hdr_bytes, TCA_CHUNK_CONTENT); + bool const drop_chunked_trailers = t_state.http_config_param->oride.http_drop_chunked_trailers == 1; + tunnel.set_producer_chunking_action(p, client_response_hdr_bytes, TCA_CHUNK_CONTENT, drop_chunked_trailers); tunnel.set_producer_chunking_size(p, t_state.txn_conf->http_chunking_size); } @@ -6979,7 +6988,8 @@ HttpTunnelProducer *p = tunnel.add_producer(server_entry->vc, nbytes, buf_start, &HttpSM::tunnel_handler_server, HT_HTTP_SERVER, "http server"); - tunnel.set_producer_chunking_action(p, 0, action); + bool const drop_chunked_trailers = t_state.http_config_param->oride.http_drop_chunked_trailers == 1; + tunnel.set_producer_chunking_action(p, 0, action, drop_chunked_trailers); tunnel.set_producer_chunking_size(p, t_state.txn_conf->http_chunking_size); setup_cache_write_transfer(&cache_sm, server_entry->vc, &t_state.cache_info.object_store, 0, "cache write"); @@ -7067,7 +7077,8 @@ else action = TCA_PASSTHRU_CHUNKED_CONTENT; } */ - tunnel.set_producer_chunking_action(p, client_response_hdr_bytes, action); + bool const drop_chunked_trailers = t_state.http_config_param->oride.http_drop_chunked_trailers == 1; + tunnel.set_producer_chunking_action(p, client_response_hdr_bytes, action, drop_chunked_trailers); tunnel.set_producer_chunking_size(p, t_state.txn_conf->http_chunking_size); return p; } diff -Nru trafficserver-9.2.4+ds/proxy/http/HttpTransact.h trafficserver-9.2.5+ds/proxy/http/HttpTransact.h --- trafficserver-9.2.4+ds/proxy/http/HttpTransact.h 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/proxy/http/HttpTransact.h 2024-07-23 21:42:39.000000000 +0000 @@ -634,6 +634,7 @@ HTTPHdr server_request; HTTPHdr server_response; HTTPHdr transform_response; + HTTPHdr cache_request; HTTPHdr cache_response; int64_t request_content_length = HTTP_UNDEFINED_CL; int64_t response_content_length = HTTP_UNDEFINED_CL; @@ -867,6 +868,7 @@ hdr_info.server_request.destroy(); hdr_info.server_response.destroy(); hdr_info.transform_response.destroy(); + hdr_info.cache_request.destroy(); hdr_info.cache_response.destroy(); cache_info.lookup_url_storage.destroy(); cache_info.parent_selection_url_storage.destroy(); diff -Nru trafficserver-9.2.4+ds/proxy/http/HttpTunnel.cc trafficserver-9.2.5+ds/proxy/http/HttpTunnel.cc --- trafficserver-9.2.4+ds/proxy/http/HttpTunnel.cc 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/proxy/http/HttpTunnel.cc 2024-07-23 21:42:39.000000000 +0000 @@ -48,27 +48,27 @@ ChunkedHandler::ChunkedHandler() : max_chunk_size(DEFAULT_MAX_CHUNK_SIZE) {} void -ChunkedHandler::init(IOBufferReader *buffer_in, HttpTunnelProducer *p) +ChunkedHandler::init(IOBufferReader *buffer_in, HttpTunnelProducer *p, bool drop_chunked_trailers) { if (p->do_chunking) { - init_by_action(buffer_in, ACTION_DOCHUNK); + init_by_action(buffer_in, ACTION_DOCHUNK, drop_chunked_trailers); } else if (p->do_dechunking) { - init_by_action(buffer_in, ACTION_DECHUNK); + init_by_action(buffer_in, ACTION_DECHUNK, drop_chunked_trailers); } else { - init_by_action(buffer_in, ACTION_PASSTHRU); + init_by_action(buffer_in, ACTION_PASSTHRU, drop_chunked_trailers); } return; } void -ChunkedHandler::init_by_action(IOBufferReader *buffer_in, Action action) +ChunkedHandler::init_by_action(IOBufferReader *buffer_in, Action action, bool drop_chunked_trailers) { - running_sum = 0; - num_digits = 0; - cur_chunk_size = 0; - bytes_left = 0; - truncation = false; - this->action = action; + running_sum = 0; + num_digits = 0; + cur_chunk_size = 0; + cur_chunk_bytes_left = 0; + truncation = false; + this->action = action; switch (action) { case ACTION_DOCHUNK: @@ -84,6 +84,18 @@ break; case ACTION_PASSTHRU: chunked_reader = buffer_in->mbuf->clone_reader(buffer_in); + if (drop_chunked_trailers) { + // Note that dropping chunked trailers only applies in the passthrough + // case in which we are filtering out chunked trailers as we proxy. + this->drop_chunked_trailers = drop_chunked_trailers; + + // We only need an intermediate buffer when modifying the chunks by + // filtering out the trailers. Otherwise, a simple passthrough needs no + // intermediary buffer as consumers will simply read directly from + // chunked_reader. + chunked_buffer = new_MIOBuffer(CHUNK_IOBUFFER_SIZE_INDEX); + chunked_size = 0; + } break; default: ink_release_assert(!"Unknown action"); @@ -97,12 +109,14 @@ { switch (action) { case ACTION_DOCHUNK: - free_MIOBuffer(chunked_buffer); + case ACTION_PASSTHRU: + if (chunked_buffer) { + free_MIOBuffer(chunked_buffer); + } break; case ACTION_DECHUNK: free_MIOBuffer(dechunked_buffer); break; - case ACTION_PASSTHRU: default: break; } @@ -166,9 +180,9 @@ } else if (state == CHUNK_READ_SIZE_CRLF) { // Scan for a linefeed if (ParseRules::is_lf(*tmp)) { Debug("http_chunk", "read chunk size of %d bytes", running_sum); - bytes_left = (cur_chunk_size = running_sum); - state = (running_sum == 0) ? CHUNK_READ_TRAILER_BLANK : CHUNK_READ_CHUNK; - done = true; + cur_chunk_bytes_left = (cur_chunk_size = running_sum); + state = (running_sum == 0) ? CHUNK_READ_TRAILER_BLANK : CHUNK_READ_CHUNK; + done = true; break; } } else if (state == CHUNK_READ_SIZE_START) { @@ -187,15 +201,19 @@ tmp++; data_size--; } + if (drop_chunked_trailers) { + chunked_buffer->write(chunked_reader, bytes_used); + chunked_size += bytes_used; + } chunked_reader->consume(bytes_used); } } // int ChunkedHandler::transfer_bytes() // -// Transfer bytes from chunked_reader to dechunked buffer +// Transfer bytes from chunked_reader to dechunked buffer. // Use block reference method when there is a sufficient -// size to move. Otherwise, uses memcpy method +// size to move. Otherwise, uses memcpy method. // int64_t ChunkedHandler::transfer_bytes() @@ -204,22 +222,26 @@ // Handle the case where we are doing chunked passthrough. if (!dechunked_buffer) { - moved = std::min(bytes_left, chunked_reader->read_avail()); + moved = std::min(cur_chunk_bytes_left, chunked_reader->read_avail()); + if (drop_chunked_trailers) { + chunked_buffer->write(chunked_reader, moved); + chunked_size += moved; + } chunked_reader->consume(moved); - bytes_left = bytes_left - moved; + cur_chunk_bytes_left = cur_chunk_bytes_left - moved; return moved; } - while (bytes_left > 0) { + while (cur_chunk_bytes_left > 0) { block_read_avail = chunked_reader->block_read_avail(); - to_move = std::min(bytes_left, block_read_avail); + to_move = std::min(cur_chunk_bytes_left, block_read_avail); if (to_move <= 0) { break; } if (to_move >= min_block_transfer_bytes) { - moved = dechunked_buffer->write(chunked_reader, bytes_left); + moved = dechunked_buffer->write(chunked_reader, cur_chunk_bytes_left); } else { // Small amount of data available. We want to copy the // data rather than block reference to prevent the buildup @@ -230,7 +252,7 @@ if (moved > 0) { chunked_reader->consume(moved); - bytes_left = bytes_left - moved; + cur_chunk_bytes_left = cur_chunk_bytes_left - moved; dechunked_size += moved; total_moved += moved; } else { @@ -245,12 +267,12 @@ { int64_t b = transfer_bytes(); - ink_assert(bytes_left >= 0); - if (bytes_left == 0) { + ink_assert(cur_chunk_bytes_left >= 0); + if (cur_chunk_bytes_left == 0) { Debug("http_chunk", "completed read of chunk of %" PRId64 " bytes", cur_chunk_size); state = CHUNK_READ_SIZE_START; - } else if (bytes_left > 0) { + } else if (cur_chunk_bytes_left > 0) { Debug("http_chunk", "read %" PRId64 " bytes of an %" PRId64 " chunk", b, cur_chunk_size); } } @@ -281,6 +303,13 @@ if (state == CHUNK_READ_TRAILER_CR || state == CHUNK_READ_TRAILER_BLANK) { state = CHUNK_READ_DONE; Debug("http_chunk", "completed read of trailers"); + + if (this->drop_chunked_trailers) { + // We skip passing through chunked trailers to the peer and only write + // the final CRLF that ends all chunked content. + chunked_buffer->write(FINAL_CRLF.data(), FINAL_CRLF.size()); + chunked_size += FINAL_CRLF.size(); + } done = true; break; } else { @@ -596,10 +625,12 @@ } void -HttpTunnel::set_producer_chunking_action(HttpTunnelProducer *p, int64_t skip_bytes, TunnelChunkingAction_t action) +HttpTunnel::set_producer_chunking_action(HttpTunnelProducer *p, int64_t skip_bytes, TunnelChunkingAction_t action, + bool drop_chunked_trailers) { - p->chunked_handler.skip_bytes = skip_bytes; - p->chunking_action = action; + this->http_drop_chunked_trailers = drop_chunked_trailers; + p->chunked_handler.skip_bytes = skip_bytes; + p->chunking_action = action; switch (action) { case TCA_CHUNK_CONTENT: @@ -808,9 +839,11 @@ ink_assert(p->vc != nullptr); active = true; - IOBufferReader *chunked_buffer_start = nullptr, *dechunked_buffer_start = nullptr; + IOBufferReader *chunked_buffer_start = nullptr; + IOBufferReader *dechunked_buffer_start = nullptr; + IOBufferReader *passthrough_buffer_start = nullptr; if (p->do_chunking || p->do_dechunking || p->do_chunked_passthru) { - p->chunked_handler.init(p->buffer_start, p); + p->chunked_handler.init(p->buffer_start, p, this->http_drop_chunked_trailers); // Copy the header into the chunked/dechunked buffers. if (p->do_chunking) { @@ -834,6 +867,11 @@ Debug("http_tunnel", "[producer_run] do_dechunking::Copied header of size %" PRId64 "", p->chunked_handler.skip_bytes); } } + if (p->chunked_handler.drop_chunked_trailers) { + // initialize a reader to passthrough buffer start before writing to keep ref count + passthrough_buffer_start = p->chunked_handler.chunked_buffer->alloc_reader(); + p->chunked_handler.chunked_buffer->write(p->buffer_start, p->chunked_handler.skip_bytes); + } } int64_t read_start_pos = 0; @@ -873,7 +911,13 @@ c->buffer_reader = p->chunked_handler.chunked_buffer->clone_reader(chunked_buffer_start); } else if (action == TCA_DECHUNK_CONTENT) { c->buffer_reader = p->chunked_handler.dechunked_buffer->clone_reader(dechunked_buffer_start); - } else { + } else if (action == TCA_PASSTHRU_CHUNKED_CONTENT) { + if (p->chunked_handler.drop_chunked_trailers) { + c->buffer_reader = p->chunked_handler.chunked_buffer->clone_reader(passthrough_buffer_start); + } else { + c->buffer_reader = p->read_buffer->clone_reader(p->buffer_start); + } + } else { // TCA_PASSTHRU_DECHUNKED_CONTENT c->buffer_reader = p->read_buffer->clone_reader(p->buffer_start); } @@ -918,6 +962,9 @@ if (p->do_dechunking && dechunked_buffer_start) { p->chunked_handler.dechunked_buffer->dealloc_reader(dechunked_buffer_start); } + if (p->do_chunked_passthru && passthrough_buffer_start) { + p->chunked_handler.chunked_buffer->dealloc_reader(passthrough_buffer_start); + } // bz57413 // If there is no transformation plugin, then we didn't add the header, hence no need to consume it diff -Nru trafficserver-9.2.4+ds/proxy/http/HttpTunnel.h trafficserver-9.2.5+ds/proxy/http/HttpTunnel.h --- trafficserver-9.2.4+ds/proxy/http/HttpTunnel.h 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/proxy/http/HttpTunnel.h 2024-07-23 21:42:39.000000000 +0000 @@ -105,15 +105,22 @@ MIOBuffer *chunked_buffer = nullptr; int64_t chunked_size = 0; + /** When passing through chunked content, filter out chunked trailers. + * + * @note this is only true when: (1) we are passing through chunked content + * and (2) we are configured to filter out chunked trailers. + */ + bool drop_chunked_trailers = false; + bool truncation = false; int64_t skip_bytes = 0; - ChunkedState state = CHUNK_READ_CHUNK; - int64_t cur_chunk_size = 0; - int64_t bytes_left = 0; - int last_server_event = VC_EVENT_NONE; + ChunkedState state = CHUNK_READ_CHUNK; + int64_t cur_chunk_size = 0; + int64_t cur_chunk_bytes_left = 0; + int last_server_event = VC_EVENT_NONE; - // Parsing Info + // Chunked header size parsing info. int running_sum = 0; int num_digits = 0; @@ -130,8 +137,8 @@ //@} ChunkedHandler(); - void init(IOBufferReader *buffer_in, HttpTunnelProducer *p); - void init_by_action(IOBufferReader *buffer_in, Action action); + void init(IOBufferReader *buffer_in, HttpTunnelProducer *p, bool drop_chunked_trailers); + void init_by_action(IOBufferReader *buffer_in, Action action, bool drop_chunked_trailers); void clear(); /// Set the max chunk @a size. @@ -147,6 +154,8 @@ void read_chunk(); void read_trailer(); int64_t transfer_bytes(); + + constexpr static std::string_view FINAL_CRLF = "\r\n"; }; struct HttpTunnelConsumer { @@ -289,7 +298,19 @@ HttpTunnelProducer *add_producer(VConnection *vc, int64_t nbytes, IOBufferReader *reader_start, HttpProducerHandler sm_handler, HttpTunnelType_t vc_type, const char *name); - void set_producer_chunking_action(HttpTunnelProducer *p, int64_t skip_bytes, TunnelChunkingAction_t action); + /// A named variable for the @a drop_chunked_trailers parameter to @a set_producer_chunking_action. + static constexpr bool DROP_CHUNKED_TRAILERS = true; + + /** Configure how the producer should behave with chunked content. + * @param[in] p Producer to configure. + * @param[in] skip_bytes Number of bytes to skip at the beginning of the stream (typically the headers). + * @param[in] action Action to take with the chunked content. + * @param[in] drop_chunked_trailers If @c true, chunked trailers are filtered + * out. Logically speaking, this is only applicable when proxying chunked + * content, thus only when @a action is @c TCA_PASSTHRU_CHUNKED_CONTENT. + */ + void set_producer_chunking_action(HttpTunnelProducer *p, int64_t skip_bytes, TunnelChunkingAction_t action, + bool drop_chunked_trailers); /// Set the maximum (preferred) chunk @a size of chunked output for @a producer. void set_producer_chunking_size(HttpTunnelProducer *producer, int64_t size); @@ -364,6 +385,9 @@ private: int reentrancy_count = 0; bool call_sm = false; + + /// Corresponds to proxy.config.http.drop_chunked_trailers having a value of 1. + bool http_drop_chunked_trailers = false; }; //// diff -Nru trafficserver-9.2.4+ds/proxy/http2/Http2ConnectionState.cc trafficserver-9.2.5+ds/proxy/http2/Http2ConnectionState.cc --- trafficserver-9.2.4+ds/proxy/http2/Http2ConnectionState.cc 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/proxy/http2/Http2ConnectionState.cc 2024-07-23 21:42:39.000000000 +0000 @@ -260,6 +260,12 @@ stream = cstate.create_stream(stream_id, error); new_stream = true; if (!stream) { + // Terminate the connection with COMPRESSION_ERROR because we don't decompress the field block in this HEADERS frame. + // TODO: try to decompress to keep HPACK Dynamic Table in sync. + if (error.cls == Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM) { + return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_COMPRESSION_ERROR, error.msg); + } + return error; } } @@ -308,7 +314,7 @@ } // Protocol error if the stream depends on itself if (stream_id == params.priority.stream_dependency) { - return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR, + return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_COMPRESSION_ERROR, "recv headers self dependency"); } @@ -1248,6 +1254,12 @@ client_ip, session->get_connection_id(), stream_id, error.msg); } this->send_rst_stream_frame(stream_id, error.code); + + // start closing stream on stream error + if (Http2Stream *stream = find_stream(stream_id); stream != nullptr) { + ink_assert(stream->get_state() == Http2StreamState::HTTP2_STREAM_STATE_CLOSED); + stream->initiating_close(); + } } } } diff -Nru trafficserver-9.2.4+ds/src/shared/overridable_txn_vars.cc trafficserver-9.2.5+ds/src/shared/overridable_txn_vars.cc --- trafficserver-9.2.4+ds/src/shared/overridable_txn_vars.cc 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/src/shared/overridable_txn_vars.cc 2024-07-23 21:42:39.000000000 +0000 @@ -30,6 +30,7 @@ {"proxy.config.ssl.hsts_max_age", {TS_CONFIG_SSL_HSTS_MAX_AGE, TS_RECORDDATATYPE_INT}}, {"proxy.config.http.normalize_ae", {TS_CONFIG_HTTP_NORMALIZE_AE, TS_RECORDDATATYPE_INT}}, {"proxy.config.http.chunking.size", {TS_CONFIG_HTTP_CHUNKING_SIZE, TS_RECORDDATATYPE_INT}}, + {"proxy.config.http.drop_chunked_trailers", {TS_CONFIG_HTTP_DROP_CHUNKED_TRAILERS, TS_RECORDDATATYPE_INT}}, {"proxy.config.ssl.client.cert.path", {TS_CONFIG_SSL_CERT_FILEPATH, TS_RECORDDATATYPE_STRING}}, {"proxy.config.http.allow_half_open", {TS_CONFIG_HTTP_ALLOW_HALF_OPEN, TS_RECORDDATATYPE_INT}}, {"proxy.config.http.chunking_enabled", {TS_CONFIG_HTTP_CHUNKING_ENABLED, TS_RECORDDATATYPE_INT}}, diff -Nru trafficserver-9.2.4+ds/src/traffic_server/FetchSM.cc trafficserver-9.2.5+ds/src/traffic_server/FetchSM.cc --- trafficserver-9.2.4+ds/src/traffic_server/FetchSM.cc 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/src/traffic_server/FetchSM.cc 2024-07-23 21:42:39.000000000 +0000 @@ -197,7 +197,7 @@ if (resp_is_chunked && (fetch_flags & TS_FETCH_FLAGS_DECHUNK)) { ChunkedHandler *ch = &chunked_handler; - ch->init_by_action(resp_reader, ChunkedHandler::ACTION_DECHUNK); + ch->init_by_action(resp_reader, ChunkedHandler::ACTION_DECHUNK, HttpTunnel::DROP_CHUNKED_TRAILERS); ch->dechunked_reader = ch->dechunked_buffer->alloc_reader(); ch->state = ChunkedHandler::CHUNK_READ_SIZE; resp_reader->dealloc(); diff -Nru trafficserver-9.2.4+ds/src/traffic_server/InkAPI.cc trafficserver-9.2.5+ds/src/traffic_server/InkAPI.cc --- trafficserver-9.2.4+ds/src/traffic_server/InkAPI.cc 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/src/traffic_server/InkAPI.cc 2024-07-23 21:42:39.000000000 +0000 @@ -8925,6 +8925,9 @@ case TS_CONFIG_HTTP_CHUNKING_SIZE: ret = _memberp_to_generic(&overridableHttpConfig->http_chunking_size, conv); break; + case TS_CONFIG_HTTP_DROP_CHUNKED_TRAILERS: + ret = _memberp_to_generic(&overridableHttpConfig->http_drop_chunked_trailers, conv); + break; case TS_CONFIG_HTTP_FLOW_CONTROL_ENABLED: ret = _memberp_to_generic(&overridableHttpConfig->flow_control_enabled, conv); break; diff -Nru trafficserver-9.2.4+ds/src/traffic_server/InkAPITest.cc trafficserver-9.2.5+ds/src/traffic_server/InkAPITest.cc --- trafficserver-9.2.4+ds/src/traffic_server/InkAPITest.cc 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/src/traffic_server/InkAPITest.cc 2024-07-23 21:42:39.000000000 +0000 @@ -8773,7 +8773,8 @@ "proxy.config.net.sock_notsent_lowat", "proxy.config.body_factory.response_suppression_mode", "proxy.config.http.parent_proxy.enable_parent_timeout_markdowns", - "proxy.config.http.parent_proxy.disable_parent_markdowns"}}; + "proxy.config.http.parent_proxy.disable_parent_markdowns", + "proxy.config.http.drop_chunked_trailers"}}; extern ClassAllocator httpSMAllocator; diff -Nru trafficserver-9.2.4+ds/src/tscore/HostLookup.cc trafficserver-9.2.5+ds/src/tscore/HostLookup.cc --- trafficserver-9.2.4+ds/src/tscore/HostLookup.cc 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/src/tscore/HostLookup.cc 2024-07-23 21:42:39.000000000 +0000 @@ -33,6 +33,7 @@ #include "tscore/HostLookup.h" #include "tscpp/util/TextView.h" +#include #include #include #include diff -Nru trafficserver-9.2.4+ds/tests/gold_tests/cache/replay/cache-range-response.replay.yaml trafficserver-9.2.5+ds/tests/gold_tests/cache/replay/cache-range-response.replay.yaml --- trafficserver-9.2.4+ds/tests/gold_tests/cache/replay/cache-range-response.replay.yaml 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/tests/gold_tests/cache/replay/cache-range-response.replay.yaml 2024-07-23 21:42:39.000000000 +0000 @@ -111,3 +111,23 @@ fields: - [ Content-Range, { value: "bytes 0-10/100", as: equal}] - [ Via, { value: "uIcSsSfUpSeN:t cCSp sS", as: contains }] + # Revalidate and replace still returns appropriate server error + - client-request: + method: "GET" + version: "1.1" + url: /some/path + headers: + fields: + - [ Host, example.com ] + - [ uuid, 5 ] + - [ Range, bytes=0-10 ] + - [ If-Modified-Since, "Wed, 16 Mar 2022 22:52:09 GMT"] + server-response: + status: 404 + reason: Not Found + headers: + fields: + - [ Content-Length, 10 ] + - [ Cache-Control, max-age=300 ] + proxy-response: + status: 404 diff -Nru trafficserver-9.2.4+ds/tests/gold_tests/chunked_encoding/chunked_encoding.test.py trafficserver-9.2.5+ds/tests/gold_tests/chunked_encoding/chunked_encoding.test.py --- trafficserver-9.2.4+ds/tests/gold_tests/chunked_encoding/chunked_encoding.test.py 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/tests/gold_tests/chunked_encoding/chunked_encoding.test.py 2024-07-23 21:42:39.000000000 +0000 @@ -146,3 +146,99 @@ tr.Processes.Default.Streams.All = Testers.ExcludesExpression("content-length:", "Response should not include content length") # Transfer encoding to origin, but no content-length # No extra bytes in body seen by origin + + +class TestChunkedTrailers: + """Verify chunked trailer proxy behavior.""" + + _chunked_dropped_replay: str = "replays/chunked_trailer_dropped.replay.yaml" + _proxied_dropped_replay: str = "replays/chunked_trailer_proxied.replay.yaml" + + def __init__(self, configure_drop_trailers: bool): + """Create a test to verify chunked trailer behavior. + + :param configure_drop_trailers: Whether to configure ATS to drop + trailers or not. + """ + self._configure_drop_trailers = configure_drop_trailers + self._replay_file = self._chunked_dropped_replay if configure_drop_trailers else self._proxied_dropped_replay + behavior_description = "drop" if configure_drop_trailers else "proxy" + tr = Test.AddTestRun(f'Verify chunked tailers behavior: {behavior_description}') + self._configure_dns(tr) + self._configure_server(tr) + self._configure_ts(tr) + self._configure_client(tr) + + def _configure_dns(self, tr: 'TestRun') -> "Process": + """Configure DNS for the test run. + + :param tr: The TestRun to configure DNS for. + :return: The DNS process. + """ + name = 'dns-drop-trailers' if self._configure_drop_trailers else 'dns-proxy-trailers' + self._dns = tr.MakeDNServer(name, default='127.0.0.1') + return self._dns + + def _configure_server(self, tr: 'TestRun') -> 'Process': + """Configure the origin server for the test run. + + :param tr: The TestRun to configure the server for. + :return: The origin server process. + """ + name = 'server-drop-trailers' if self._configure_drop_trailers else 'server-proxy-trailers' + self._server = tr.AddVerifierServerProcess(name, self._replay_file) + if self._configure_drop_trailers: + self._server.Streams.All += Testers.ExcludesExpression('Client: ATS', 'Verify the Client trailer was dropped.') + self._server.Streams.All += Testers.ExcludesExpression('ETag: "abc"', 'Verify the ETag trailer was dropped.') + else: + self._server.Streams.All += Testers.ContainsExpression('Client: ATS', 'Verify the Client trailer was proxied.') + self._server.Streams.All += Testers.ContainsExpression('ETag: "abc"', 'Verify the ETag trailer was proxied.') + return self._server + + def _configure_ts(self, tr: 'TestRun') -> 'Process': + """Configure ATS for the test run. + + :param tr: The TestRun to configure ATS for. + :return: The ATS process. + """ + name = 'ts-drop-trailers' if self._configure_drop_trailers else 'ts-proxy-trailers' + ts = tr.MakeATSProcess(name, enable_cache=False) + self._ts = ts + port = self._server.Variables.http_port + ts.Disk.remap_config.AddLine(f'map / http://backend.example.com:{port}/') + ts.Disk.records_config.update( + { + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.debug.tags': 'http', + 'proxy.config.dns.nameservers': f'127.0.0.1:{self._dns.Variables.Port}', + 'proxy.config.dns.resolv_conf': 'NULL' + }) + if self._configure_drop_trailers: + ts.Disk.records_config.update({ + 'proxy.config.http.drop_chunked_trailers': 1, + }) + return ts + + def _configure_client(self, tr: 'TestRun') -> 'Process': + """Configure the client for the test run. + + :param tr: The TestRun to configure the client for. + :return: The client process. + """ + name = 'client-drop-trailers' if self._configure_drop_trailers else 'client-proxy-trailers' + self._client = tr.AddVerifierClientProcess(name, self._replay_file, http_ports=[self._ts.Variables.port]) + self._client.StartBefore(self._dns) + self._client.StartBefore(self._server) + self._client.StartBefore(self._ts) + + if self._configure_drop_trailers: + self._client.Streams.All += Testers.ExcludesExpression('Sever: ATS', 'Verify the Server trailer was dropped.') + self._client.Streams.All += Testers.ExcludesExpression('ETag: "def"', 'Verify the ETag trailer was dropped.') + else: + self._client.Streams.All += Testers.ContainsExpression('Sever: ATS', 'Verify the Server trailer was proxied.') + self._client.Streams.All += Testers.ContainsExpression('ETag: "def"', 'Verify the ETag trailer was proxied.') + return self._client + + +TestChunkedTrailers(configure_drop_trailers=True) +TestChunkedTrailers(configure_drop_trailers=False) diff -Nru trafficserver-9.2.4+ds/tests/gold_tests/chunked_encoding/replays/chunked_trailer_dropped.replay.yaml trafficserver-9.2.5+ds/tests/gold_tests/chunked_encoding/replays/chunked_trailer_dropped.replay.yaml --- trafficserver-9.2.4+ds/tests/gold_tests/chunked_encoding/replays/chunked_trailer_dropped.replay.yaml 1970-01-01 00:00:00.000000000 +0000 +++ trafficserver-9.2.5+ds/tests/gold_tests/chunked_encoding/replays/chunked_trailer_dropped.replay.yaml 2024-07-23 21:42:39.000000000 +0000 @@ -0,0 +1,68 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +meta: + version: "1.0" + +# Verify that we handle dropping chunked trailers correctly. This assumes ATS is +# configured to drop chunked trailers. + +sessions: +- transactions: + - client-request: + method: "POST" + version: "1.1" + url: /some/path + headers: + fields: + - [ Host, example.com ] + - [ Transfer-Encoding, chunked ] + - [ uuid, 1 ] + content: + transfer: plain + encoding: uri + # 3-byte chunk, abc. + # Then chunked trailers between 0\r\n and a final \r\n (per specification). + data: 3%0D%0Aabc%0D%0A0%0D%0AClient%3A%20ATS%0D%0AETag%3A%20%22abc%22%0D%0A%0D%0A + + proxy-request: + content: + transfer: plain + encoding: uri + # Note: same as client-request, but the trailer is dropped. + data: 3%0D%0Aabc%0D%0A0%0D%0A%0D%0A + verify: { as: equal } + + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Transfer-Encoding, chunked ] + - [ Content-Type, text/html ] + content: + transfer: plain + encoding: uri + # Note: same content as the client-request. + data: 3%0D%0Aabc%0D%0A0%0D%0ASever%3A%20ATS%0D%0AETag%3A%20%22def%22%0D%0A%0D%0A + + proxy-request: + content: + transfer: plain + encoding: uri + # Note: same as server-response, but the trailer is dropped. + data: 3%0D%0Aabc%0D%0A0%0D%0A%0D%0A + verify: { as: equal } diff -Nru trafficserver-9.2.4+ds/tests/gold_tests/chunked_encoding/replays/chunked_trailer_proxied.replay.yaml trafficserver-9.2.5+ds/tests/gold_tests/chunked_encoding/replays/chunked_trailer_proxied.replay.yaml --- trafficserver-9.2.4+ds/tests/gold_tests/chunked_encoding/replays/chunked_trailer_proxied.replay.yaml 1970-01-01 00:00:00.000000000 +0000 +++ trafficserver-9.2.5+ds/tests/gold_tests/chunked_encoding/replays/chunked_trailer_proxied.replay.yaml 2024-07-23 21:42:39.000000000 +0000 @@ -0,0 +1,68 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +meta: + version: "1.0" + +# Verify that we handle passing through chunked trailers correctly. This assumes +# ATS is configured to pass through (i.e., not drop) chunked trailers. + +sessions: +- transactions: + - client-request: + method: "POST" + version: "1.1" + url: /some/path + headers: + fields: + - [ Host, example.com ] + - [ Transfer-Encoding, chunked ] + - [ uuid, 1 ] + content: + transfer: plain + encoding: uri + # 3-byte chunk, abc. + # Then chunked trailers between 0\r\n and a final \r\n (per specification). + data: 3%0D%0Aabc%0D%0A0%0D%0AClient%3A%20ATS%0D%0AETag%3A%20%22abc%22%0D%0A%0D%0A + + proxy-request: + content: + transfer: plain + encoding: uri + # Same content as client-request above. + data: 3%0D%0Aabc%0D%0A0%0D%0AClient%3A%20ATS%0D%0AETag%3A%20%22abc%22%0D%0A%0D%0A + verify: { as: equal } + + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Transfer-Encoding, chunked ] + - [ Content-Type, text/html ] + content: + transfer: plain + encoding: uri + # Note: same content as the client-request. + data: 3%0D%0Aabc%0D%0A0%0D%0ASever%3A%20ATS%0D%0AETag%3A%20%22def%22%0D%0A%0D%0A + + proxy-request: + content: + transfer: plain + encoding: uri + # Same content as server-response above. + data: 3%0D%0Aabc%0D%0A0%0D%0ASever%3A%20ATS%0D%0AETag%3A%20%22def%22%0D%0A%0D%0A + verify: { as: equal } diff -Nru trafficserver-9.2.4+ds/tests/gold_tests/headers/gold/invalid_character_in_te_value.gold trafficserver-9.2.5+ds/tests/gold_tests/headers/gold/invalid_character_in_te_value.gold --- trafficserver-9.2.4+ds/tests/gold_tests/headers/gold/invalid_character_in_te_value.gold 1970-01-01 00:00:00.000000000 +0000 +++ trafficserver-9.2.5+ds/tests/gold_tests/headers/gold/invalid_character_in_te_value.gold 2024-07-23 21:42:39.000000000 +0000 @@ -0,0 +1,23 @@ +HTTP/1.1 400 Invalid HTTP Request +Date:`` +Connection: close +Server:`` +Cache-Control: no-store +Content-Type: text/html +Content-Language: en +Content-Length:`` + + + +Bad Request + + + +

Bad Request

+
+ + +Description: Could not process this request. + +
+ diff -Nru trafficserver-9.2.4+ds/tests/gold_tests/headers/good_request_after_bad.test.py trafficserver-9.2.5+ds/tests/gold_tests/headers/good_request_after_bad.test.py --- trafficserver-9.2.4+ds/tests/gold_tests/headers/good_request_after_bad.test.py 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/tests/gold_tests/headers/good_request_after_bad.test.py 2024-07-23 21:42:39.000000000 +0000 @@ -93,7 +93,7 @@ tr.Processes.Default.Command = 'printf "GET / HTTP/1.1\r\nhost: bob\r\ntransfer-encoding: \x08chunked\r\n\r\nGET / HTTP/1.1\r\nHost: boa\r\n\r\n" | nc 127.0.0.1 {}'.format( ts.Variables.port) tr.Processes.Default.ReturnCode = 0 -tr.Processes.Default.Streams.stdout = 'gold/bad_te_value.gold' +tr.Processes.Default.Streams.stdout = 'gold/invalid_character_in_te_value.gold' tr = Test.AddTestRun("Extra characters in content-length") tr.Processes.Default.Command = 'printf "GET / HTTP/1.1\r\nhost: bob\r\ncontent-length:+3\r\n\r\nGET / HTTP/1.1\r\nHost: boa\r\n\r\n" | nc 127.0.0.1 {}'.format( diff -Nru trafficserver-9.2.4+ds/tests/gold_tests/headers/normalized_ae_match_vary_cache.test.py trafficserver-9.2.5+ds/tests/gold_tests/headers/normalized_ae_match_vary_cache.test.py --- trafficserver-9.2.4+ds/tests/gold_tests/headers/normalized_ae_match_vary_cache.test.py 1970-01-01 00:00:00.000000000 +0000 +++ trafficserver-9.2.5+ds/tests/gold_tests/headers/normalized_ae_match_vary_cache.test.py 2024-07-23 21:42:39.000000000 +0000 @@ -0,0 +1,67 @@ +''' +Test cache matching with the normalized Accept-Encoding header field +and the Vary header field in response +''' +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +Test.Summary = ''' +Test cache matching with the normalized Accept-Encoding and the Vary header field in response +''' + +Test.ContinueOnFail = True + +testName = "NORMALIZE_AE_MATCH_VARY" + +replay_file = "replays/normalized_ae_varied_transactions.replay.yaml" +server = Test.MakeVerifierServerProcess("server", replay_file) + +ts = Test.MakeATSProcess("ts", enable_cache=True) +ts.Disk.remap_config.AddLine( + f"map http://www.ae-0.com http://127.0.0.1:{server.Variables.http_port}" + + ' @plugin=conf_remap.so @pparam=proxy.config.http.normalize_ae=0') +ts.Disk.remap_config.AddLine( + f"map http://www.ae-1.com http://127.0.0.1:{server.Variables.http_port}" + + ' @plugin=conf_remap.so @pparam=proxy.config.http.normalize_ae=1') +ts.Disk.remap_config.AddLine( + f"map http://www.ae-2.com http://127.0.0.1:{server.Variables.http_port}" + + ' @plugin=conf_remap.so @pparam=proxy.config.http.normalize_ae=2') +# disable normalize_ae=3 on 9.1 +ts.Disk.remap_config.AddLine( + f"map http://www.ae-3.com http://127.0.0.1:{server.Variables.http_port}" + + ' @plugin=conf_remap.so @pparam=proxy.config.http.normalize_ae=3') +ts.Disk.plugin_config.AddLine('xdebug.so --enable=x-cache') +ts.Disk.records_config.update( + { + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.debug.tags': 'http', + 'proxy.config.http.response_via_str': 3, + # the following variables could affect the results of alternate cache matching, + # define them with their default values explicitly + 'proxy.config.cache.limits.http.max_alts': 5, + 'proxy.config.http.cache.ignore_accept_mismatch': 2, + 'proxy.config.http.cache.ignore_accept_language_mismatch': 2, + 'proxy.config.http.cache.ignore_accept_encoding_mismatch': 2, + 'proxy.config.http.cache.ignore_accept_charset_mismatch': 2, + }) + +tr = Test.AddTestRun() +tr.Processes.Default.StartBefore(server) +tr.Processes.Default.StartBefore(ts) +tr.AddVerifierClientProcess("client", replay_file, http_ports=[ts.Variables.port]) +tr.StillRunningAfter = ts diff -Nru trafficserver-9.2.4+ds/tests/gold_tests/headers/replays/normalized_ae_varied_transactions.replay.yaml trafficserver-9.2.5+ds/tests/gold_tests/headers/replays/normalized_ae_varied_transactions.replay.yaml --- trafficserver-9.2.4+ds/tests/gold_tests/headers/replays/normalized_ae_varied_transactions.replay.yaml 1970-01-01 00:00:00.000000000 +0000 +++ trafficserver-9.2.5+ds/tests/gold_tests/headers/replays/normalized_ae_varied_transactions.replay.yaml 2024-07-23 21:42:39.000000000 +0000 @@ -0,0 +1,813 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +meta: + version: "1.0" + + blocks: + + - 404_response: &404_response + status: 404 + reason: "Not Found" + headers: + fields: + - [ Content-Length, 0 ] + +sessions: +- transactions: + + # Case 1 proxy.config.http.normalize_ae:0 + # load an alternate of no Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case1 + headers: + fields: + - [ Host, www.ae-0.com ] + - [ X-Debug, x-cache] + - [ uuid, 01 ] + + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Transfer-Encoding, chunked ] + - [ Cache-Control, max-age=300 ] + - [ Vary, Accept-Encoding ] + - [ Connection, close ] + - [ X-Response-Identifier, No-Accept-Encoding ] + content: + encoding: plain + data: "no Accept-Encoding" + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: No-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: miss, as: equal } ] + + # load an alternate of empty Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case1 + headers: + fields: + - [ Host, www.ae-0.com ] + - [ X-Debug, x-cache] + - [ Accept-Encoding, "" ] + - [ uuid, 02 ] + delay: 100ms + + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Transfer-Encoding, chunked ] + - [ Cache-Control, max-age=300 ] + - [ Vary, Accept-Encoding ] + - [ Connection, close ] + - [ X-Response-Identifier, Empty-Accept-Encoding ] + content: + encoding: plain + data: "Empty Accept-Encoding" + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: Empty-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: miss, as: equal } ] + + # Accept-Encoding header deflate would match the alternate of empty Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case1 + headers: + fields: + - [ Host, www.ae-0.com ] + - [ X-Debug, x-cache] + - [ uuid, 03 ] + - [ Accept-Encoding, deflate ] + delay: 100ms + + server-response: + <<: *404_response + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: Empty-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: hit-fresh, as: equal } ] + + # Accept-Encoding header br, compress would match the alternate of empty Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case1 + headers: + fields: + - [ Host, www.ae-0.com ] + - [ X-Debug, x-cache] + - [ uuid, 04 ] + - [ Accept-Encoding, "br, compress" ] + delay: 100ms + + server-response: + <<: *404_response + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: Empty-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: hit-fresh, as: equal } ] + + # load an alternate of gzip Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case1 + headers: + fields: + - [ Host, www.ae-0.com ] + - [ X-Debug, x-cache] + - [ Accept-Encoding, gzip;q=0.8 ] + - [ uuid, 05 ] + delay: 100ms + + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Transfer-Encoding, chunked ] + - [ Cache-Control, max-age=300 ] + - [ Vary, Accept-Encoding ] + - [ Connection, close ] + - [ X-Response-Identifier, Gzip-Accept-Encoding ] + content: + encoding: plain + data: "Gzip Accept-Encoding" + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: Gzip-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: miss, as: equal } ] + + # Accept-Encoding header br, compress, gzip would match the alternate of gzip Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case1 + headers: + fields: + - [ Host, www.ae-0.com ] + - [ X-Debug, x-cache] + - [ uuid, 06 ] + - [ Accept-Encoding, "br, compress, gzip" ] + delay: 100ms + + server-response: + <<: *404_response + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: Gzip-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: hit-fresh, as: equal } ] + + + # Case 2 proxy.config.http.normalize_ae:1 + # load an alternate of no Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case2 + headers: + fields: + - [ Host, www.ae-1.com ] + - [ X-Debug, x-cache] + - [ uuid, 11 ] + + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Transfer-Encoding, chunked ] + - [ Cache-Control, max-age=300 ] + - [ Vary, Accept-Encoding ] + - [ Connection, close ] + - [ X-Response-Identifier, No-Accept-Encoding ] + content: + encoding: plain + data: "no Accept-Encoding" + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: No-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: miss, as: equal } ] + + # empty Accept-Encoding header would match the alternate of no Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case2 + headers: + fields: + - [ Host, www.ae-1.com ] + - [ X-Debug, x-cache] + - [ Accept-Encoding, "" ] + - [ uuid, 12 ] + delay: 100ms + + server-response: + <<: *404_response + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: No-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: hit-fresh, as: equal } ] + + # Accept-Encoding header deflate would match the alternate of no Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case2 + headers: + fields: + - [ Host, www.ae-1.com ] + - [ X-Debug, x-cache] + - [ uuid, 13 ] + - [ Accept-Encoding, deflate ] + delay: 100ms + + server-response: + <<: *404_response + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: No-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: hit-fresh, as: equal } ] + + # Accept-Encoding header br, compress would match the alternate of no Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case2 + headers: + fields: + - [ Host, www.ae-1.com ] + - [ X-Debug, x-cache] + - [ uuid, 14 ] + - [ Accept-Encoding, "br, compress" ] + delay: 100ms + + server-response: + <<: *404_response + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: No-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: hit-fresh, as: equal } ] + + # load an alternate of gzip Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case2 + headers: + fields: + - [ Host, www.ae-1.com ] + - [ X-Debug, x-cache] + - [ Accept-Encoding, gzip;q=0.8 ] + - [ uuid, 15 ] + delay: 100ms + + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Transfer-Encoding, chunked ] + - [ Cache-Control, max-age=300 ] + - [ Vary, Accept-Encoding ] + - [ Connection, close ] + - [ X-Response-Identifier, Gzip-Accept-Encoding ] + content: + encoding: plain + data: "Gzip Accept-Encoding" + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: Gzip-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: miss, as: equal } ] + + # Accept-Encoding header br, compress, gzip would match the alternate of gzip Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case2 + headers: + fields: + - [ Host, www.ae-1.com ] + - [ X-Debug, x-cache] + - [ uuid, 16 ] + - [ Accept-Encoding, "br, compress, gzip" ] + delay: 100ms + + server-response: + <<: *404_response + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: Gzip-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: hit-fresh, as: equal } ] + + # Case 3 proxy.config.http.normalize_ae:2 + # load an alternate of no Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case3 + headers: + fields: + - [ Host, www.ae-2.com ] + - [ X-Debug, x-cache] + - [ uuid, 21 ] + + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Transfer-Encoding, chunked ] + - [ Cache-Control, max-age=300 ] + - [ Vary, Accept-Encoding ] + - [ Connection, close ] + - [ X-Response-Identifier, No-Accept-Encoding ] + content: + encoding: plain + data: "no Accept-Encoding" + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: No-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: miss, as: equal } ] + + # empty Accept-Encoding header would match the alternate of no Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case3 + headers: + fields: + - [ Host, www.ae-2.com ] + - [ X-Debug, x-cache] + - [ Accept-Encoding, "" ] + - [ uuid, 22 ] + delay: 100ms + + server-response: + <<: *404_response + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: No-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: hit-fresh, as: equal } ] + + # Accept-Encoding header deflate would match the alternate of no Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case3 + headers: + fields: + - [ Host, www.ae-2.com ] + - [ X-Debug, x-cache] + - [ uuid, 23 ] + - [ Accept-Encoding, deflate ] + delay: 100ms + + server-response: + <<: *404_response + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: No-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: hit-fresh, as: equal } ] + + # load an alternate of br Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case3 + headers: + fields: + - [ Host, www.ae-2.com ] + - [ X-Debug, x-cache] + - [ uuid, 24 ] + - [ Accept-Encoding, "br, compress" ] + delay: 100ms + + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Transfer-Encoding, chunked ] + - [ Cache-Control, max-age=300 ] + - [ Vary, Accept-Encoding ] + - [ Connection, close ] + - [ X-Response-Identifier, Br-Accept-Encoding ] + content: + encoding: plain + data: "br Accept-Encoding" + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: Br-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: miss, as: equal } ] + + # load an alternate of gzip Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case3 + headers: + fields: + - [ Host, www.ae-2.com ] + - [ X-Debug, x-cache] + - [ Accept-Encoding, gzip;q=0.8 ] + - [ uuid, 25 ] + delay: 100ms + + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Transfer-Encoding, chunked ] + - [ Cache-Control, max-age=300 ] + - [ Vary, Accept-Encoding ] + - [ Connection, close ] + - [ X-Response-Identifier, Gzip-Accept-Encoding ] + content: + encoding: plain + data: "Gzip Accept-Encoding" + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: Gzip-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: miss, as: equal } ] + + # Accept-Encoding header br, compress, gzip would match the alternate of br Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case3 + headers: + fields: + - [ Host, www.ae-2.com ] + - [ X-Debug, x-cache] + - [ uuid, 26 ] + - [ Accept-Encoding, "br, compress, gzip" ] + delay: 100ms + + server-response: + <<: *404_response + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: Br-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: hit-fresh, as: equal } ] + + # Accept-Encoding header compress, gzip would match the alternate of gzip Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case3 + headers: + fields: + - [ Host, www.ae-2.com ] + - [ X-Debug, x-cache] + - [ uuid, 27 ] + - [ Accept-Encoding, "compress, gzip" ] + delay: 100ms + + server-response: + <<: *404_response + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: Gzip-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: hit-fresh, as: equal } ] + + # Case 4 proxy.config.http.normalize_ae:3 + # load an alternate of no Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case4 + headers: + fields: + - [ Host, www.ae-3.com ] + - [ X-Debug, x-cache] + - [ uuid, 31 ] + + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Transfer-Encoding, chunked ] + - [ Cache-Control, max-age=300 ] + - [ Vary, Accept-Encoding ] + - [ Connection, close ] + - [ X-Response-Identifier, No-Accept-Encoding ] + content: + encoding: plain + data: "no Accept-Encoding" + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: No-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: miss, as: equal } ] + + # empty Accept-Encoding header would match the alternate of no Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case4 + headers: + fields: + - [ Host, www.ae-3.com ] + - [ X-Debug, x-cache] + - [ Accept-Encoding, "" ] + - [ uuid, 32 ] + delay: 100ms + + server-response: + <<: *404_response + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: No-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: hit-fresh, as: equal } ] + + # Accept-Encoding header deflate would match the alternate of no Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case4 + headers: + fields: + - [ Host, www.ae-3.com ] + - [ X-Debug, x-cache] + - [ uuid, 33 ] + - [ Accept-Encoding, deflate ] + delay: 100ms + + server-response: + <<: *404_response + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: No-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: hit-fresh, as: equal } ] + + # load an alternate of br Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case4 + headers: + fields: + - [ Host, www.ae-3.com ] + - [ X-Debug, x-cache] + - [ uuid, 34 ] + - [ Accept-Encoding, "br, compress" ] + delay: 100ms + + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Transfer-Encoding, chunked ] + - [ Cache-Control, max-age=300 ] + - [ Vary, Accept-Encoding ] + - [ Connection, close ] + - [ X-Response-Identifier, Br-Accept-Encoding ] + content: + encoding: plain + data: "br Accept-Encoding" + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: Br-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: miss, as: equal } ] + + # load an alternate of gzip Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case4 + headers: + fields: + - [ Host, www.ae-3.com ] + - [ X-Debug, x-cache] + - [ Accept-Encoding, gzip;q=0.8 ] + - [ uuid, 35 ] + delay: 100ms + + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Transfer-Encoding, chunked ] + - [ Cache-Control, max-age=300 ] + - [ Vary, Accept-Encoding ] + - [ Connection, close ] + - [ X-Response-Identifier, Gzip-Accept-Encoding ] + content: + encoding: plain + data: "Gzip Accept-Encoding" + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: Gzip-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: miss, as: equal } ] + + # NOTICE: This case should load an alternate of br, gzip Accept-Encoding header. + # However, due to the implementation of calculate_quality_of_match(), + # ATS matches the alternate of gzip Accept-Encoding header. + # The result is DIFFERENT from the description of proxy.config.http.normalize_ae: 3 + - client-request: + method: "GET" + version: "1.1" + url: /case4 + headers: + fields: + - [ Host, www.ae-3.com ] + - [ X-Debug, x-cache] + - [ uuid, 36 ] + - [ Accept-Encoding, "br, compress, gzip" ] + delay: 100ms + + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Transfer-Encoding, chunked ] + - [ Cache-Control, max-age=300 ] + - [ Vary, Accept-Encoding ] + - [ Connection, close ] + - [ X-Response-Identifier, Br-Gzip-Accept-Encoding ] + content: + encoding: plain + data: "Br, Gzip Accept-Encoding" + + proxy-response: + status: 200 + headers: + fields: + # - [ X-Response-Identifier, { value: Br-Gzip-Accept-Encoding, as: equal } ] + # - [ X-Cache, { value: miss, as: equal } ] + - [ X-Response-Identifier, { value: Gzip-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: hit-fresh, as: equal } ] + + # Accept-Encoding header compress, gzip would match the alternate of gzip Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case4 + headers: + fields: + - [ Host, www.ae-3.com ] + - [ X-Debug, x-cache] + - [ uuid, 37 ] + - [ Accept-Encoding, "compress, gzip" ] + delay: 100ms + + server-response: + <<: *404_response + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: Gzip-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: hit-fresh, as: equal } ] + + # Accept-Encoding header br;q=1.1 would match the alternate of br Accept-Encoding header + - client-request: + method: "GET" + version: "1.1" + url: /case4 + headers: + fields: + - [ Host, www.ae-3.com ] + - [ X-Debug, x-cache] + - [ uuid, 38 ] + - [ Accept-Encoding, "br;q=1.1" ] + delay: 100ms + + server-response: + <<: *404_response + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response-Identifier, { value: Br-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: hit-fresh, as: equal } ] + + # NOTICE: This case should make Accept-Encoding header br, gzip;q=0.8 match + # the alternate of br, gzip Accept-Encoding header. + # However, due to the implementation of calculate_quality_of_match(), + # ATS matches the alternate of gzip Accept-Encoding header. + # The result is DIFFERENT from the description of proxy.config.http.normalize_ae: 3 + - client-request: + method: "GET" + version: "1.1" + url: /case4 + headers: + fields: + - [ Host, www.ae-3.com ] + - [ X-Debug, x-cache] + - [ uuid, 39 ] + - [ Accept-Encoding, "br, gzip;q=0.8" ] + delay: 100ms + + server-response: + <<: *404_response + + proxy-response: + status: 200 + headers: + fields: + # - [ X-Response-Identifier, { value: Br-Gzip-Accept-Encoding, as: equal } ] + - [ X-Response-Identifier, { value: Gzip-Accept-Encoding, as: equal } ] + - [ X-Cache, { value: hit-fresh, as: equal } ] diff -Nru trafficserver-9.2.4+ds/tests/gold_tests/logging/gold/field-json-test.gold trafficserver-9.2.5+ds/tests/gold_tests/logging/gold/field-json-test.gold --- trafficserver-9.2.4+ds/tests/gold_tests/logging/gold/field-json-test.gold 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/tests/gold_tests/logging/gold/field-json-test.gold 2024-07-23 21:42:39.000000000 +0000 @@ -1,3 +1,4 @@ {"foo":"ab\td\/ef","foo-slice":"\td"} -{"foo":"ab\u001fd\/ef","foo-slice":"\u001fd"} -{"foo":"abc\u007fde","foo-slice":"c"} +{"foo":"-","foo-slice":""} +{"foo":"-","foo-slice":""} +{"foo":"ab\u00c2\u0080d\/ef","foo-slice":"\u00c2\u0080d"} diff -Nru trafficserver-9.2.4+ds/tests/gold_tests/logging/log-field-json.test.py trafficserver-9.2.5+ds/tests/gold_tests/logging/log-field-json.test.py --- trafficserver-9.2.4+ds/tests/gold_tests/logging/log-field-json.test.py 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/tests/gold_tests/logging/log-field-json.test.py 2024-07-23 21:42:39.000000000 +0000 @@ -106,6 +106,11 @@ ts.Variables.port) tr.Processes.Default.ReturnCode = 0 +tr = Test.AddTestRun() +tr.Processes.Default.Command = 'curl --verbose --header "Host: test-2" --header "Foo: ab\x80d/ef" http://localhost:{0}/test-4'.format( + ts.Variables.port) +tr.Processes.Default.ReturnCode = 0 + # Wait for log file to appear, then wait one extra second to make sure TS is done writing it. test_run = Test.AddTestRun() test_run.Processes.Default.Command = ( diff -Nru trafficserver-9.2.4+ds/tests/gold_tests/tls/ssl/passphrase.key trafficserver-9.2.5+ds/tests/gold_tests/tls/ssl/passphrase.key --- trafficserver-9.2.4+ds/tests/gold_tests/tls/ssl/passphrase.key 1970-01-01 00:00:00.000000000 +0000 +++ trafficserver-9.2.5+ds/tests/gold_tests/tls/ssl/passphrase.key 2024-07-23 21:42:39.000000000 +0000 @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFJDBWBgkqhkiG9w0BBQ0wSTAxBgkqhkiG9w0BBQwwJAQQBZQrPgU+cHs3Ls4O +gfcPBwICCAAwDAYIKoZIhvcNAgkFADAUBggqhkiG9w0DBwQIBRDrt5DRnIoEggTI +S5O31tiNE8pgNMZ9MAoiNfGGJHcnvQcOnP/bosrxfXRVrumLzxLhpXhPREtBiIUk +ksuPmvobWS7AcZIPD72RpCN8NZw3lTANHnN3N7HP7qgUDbXsYhT2ssuT+BQsNRhA +y8uh0tKysVCbVNClYJvgrM2xzU7JFghaeHkJkabYJ2FKnHVRIZwkwbJWDeW0Ce/V +r858mzdmbJGack2Rg3FT5xDAqmzUc6PWSZgBXkrOwbmHJehoWTzfMSl4uBsrFKnd +KGHQJ6m24DP4Am79BOce6YoM1P36i56Rwo/q7LHI5AAadVSTLMaoD8gey6Ny9ZO9 +eflyKDW80wqmJxDevEhCKqOQbunogBuVfyo4dc2G4XPfwBhN4Vp+dVcfx9TBTdGo +gxNEd8+Nr8Ihzoff6brst9iJrBx/uWkEblSQXlp1cI9qfv8w/ji4PeLJilRaHfwV +VSr2BupIseW2GDjOOiziFvgl7Crj2kOevThunNl/IdNf8LmidUCIRJimwh38KsLx +VyG8+VFpISnkgPd89S9UEUpmUJi5hshmqpWZXLSuYUrYPucqJSKJHpqPdzcTBWg3 +kH/82T5VCYWJ/lfsl7HcfZHxfeng8636ZYZsXMwUpX3mHEGA08fuUROuekN9konO +xXxvmtmWZcyJz+eVHCL+gqyP4ecfOmkvIVin2mXSneA420lmxyzY36pox4iZbqm3 +a8NpmUd+envWlJjq7dCHIsGjBfFr3hGyjDsE3ZRuoMnGGVbwM98Nrkw5bsKWUfXQ +N3PZFZKQT/cXxpUIW/g7TLXFmP4I7o2NycV/84/vfX2tlh6nFk67JdgX54m2Et9n +M8RMNb6gU8AWfZY2kDaDd44Qx/i/7huNsEmJ5u4ze0+GoN3R+Bj6fbEKqar/SP2v +9or8yK64+A1ZHXUf6W12n9VBFsALqDIbHKxRfWiYfLv2eTnpGtxzicGp1OZMBWD4 +b1wpzGz5QjkQ3OC8zNRqSmynIJcnTSviJbAlHBSogUmOK/NAeSe8OIznpAUCHzGU +zZylmM/2O1Fpf75iuqOL6flPGbXoT5IRirmP5KevJWbadBX3O5DPP2irjO+RiGf9 +0NdbLNvZh5WWUXycjUbnS36uzPiBKD+ZclgqZBH1UYPg26/p4hR1m3cCswg1AbsL +lwjF+8w73ULHSF5VsSAa9U7QZ1DiJXFzaOyCDuCBlzFYc9v1A+kYrQVpZ1fsSubd +k14BbrDlOuSfYWL8jpRg3RBBh41zCXa297fFG0GtqVVYG90Ij2za5od+fy/Q/W1I +SJYuZndyIpf1hvGfVwRCPKcXIr7mf+//SPHBKJe5aHrpVDznEpswG3Tjcz+qM7OZ +qZG4mfNUNUa6xWcVFSdZfXRszXzJdY0N3P2JFolpmJO3oDkbZoa63ILtTf355S9Z +UVMTwX1QxGsKFG0jz92s474R2Z58A7TyRiZLQw+JxiaIDCVxaW73tr+/pCjqQwkW +RT3iHNd/BeQnbl3RV8o+jE6wKMz10mulml7yq38vmyjHtBMSwPZz668T6lb161ti +vMh/B4/bQu22DRpdtQS3B5h3XATJ7bkoG+hQUHzowz0jiK93ICZumpCYBu5V58nr +QsIKSU9+bBOlU8y28KJgNuALBZgSZ/fs +-----END ENCRYPTED PRIVATE KEY----- diff -Nru trafficserver-9.2.4+ds/tests/gold_tests/tls/ssl/passphrase.pem trafficserver-9.2.5+ds/tests/gold_tests/tls/ssl/passphrase.pem --- trafficserver-9.2.4+ds/tests/gold_tests/tls/ssl/passphrase.pem 1970-01-01 00:00:00.000000000 +0000 +++ trafficserver-9.2.5+ds/tests/gold_tests/tls/ssl/passphrase.pem 2024-07-23 21:42:39.000000000 +0000 @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEfjCCAmagAwIBAgIUWqf2OgjUkTeH4qDkqxeaeOA9EVIwDQYJKoZIhvcNAQEL +BQAwVDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAklMMQ4wDAYDVQQKDAVZYWhvbzEN +MAsGA1UECwwERWRnZTEZMBcGA1UEAwwQc2lnbmVyLnlhaG9vLmNvbTAeFw0yNDA0 +MDIyMTU5MzNaFw0yNTA0MDIyMTU5MzNaMFoxCzAJBgNVBAYTAkFVMRMwEQYDVQQI +DApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQx +EzARBgNVBAMMCnBhc3NwaHJhc2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQDRSJlZF7fVu/8etpbSYDbPL0m2Q8DHKfwinK6nqbbF7OWbQoCeHpaEppyk +9iQ/eIPCtnDD0rdA1cC9DwdOfaeaBhjXy2OaLrJGaeTUhhNcLhSwbfX26dKn5EEi +B5bRaEruKsh/MmmSe691TT6kEfpFQCK4WO9B9UXejEtI7NZ4wskaO38UjVEYLguW +wJ25mnzWQpjhYWR2G1+2Q3SCtZ82cXKJTQWuOPJHmJ5FjQQpldFJg0PKf6zAY9Vr +vkggeHiLwNKTk5R+975EB9fLoV3R69zkqf2NoMVDTvG9jd974haT/iRO9fy2pGXt +ACaxoYoVEyUbbZd9i9aR3gmczqEFAgMBAAGjQjBAMB0GA1UdDgQWBBRRijjaYGCs +ZE5bO2i7l5JA+nlGtDAfBgNVHSMEGDAWgBS8vY4PSrVikT05kO3dCxqr9MMboTAN +BgkqhkiG9w0BAQsFAAOCAgEAX2O9IBogwv+338jsvXb+ZVwHLUHFkXugqXNEI8hm +A9JFcqHwsVfOJmYGuAEjGReyjzfZou5YuzPT14VvF+wnJPA6/PbWrAKxoioq4pho +2/LRQSqe4O+T+QcSX32Nsu8h5bnv6i9MSAAWltErhOTmQkWEqYIzCh86YuHloBll +txVJ/KvWu4xetHREo1OILV5w2a5jZ7AhTqe/Yx9NmRSvQIt4MRp4DBPS8nNaUwak +3rgJV8QCIFk4+S1FqSb+4t5O7VQh4aPSmsEKHkP1Km4qFtUa4BKpDTWQTjtC/c+2 +V/ja6vFJFApniTHLpsRuu7Ma8xVulHiGuNwcvlgBtDcRAzdLcCPHCrhHpWTkrG6p +OnqznwwlBFmZHa8yiu8EHZbxH8hrPdf8VguNOc2sPEaskllmebl+XJlD0d3ulwQj +g1Gv3em0/eRWBs0sTcjTX6s852QLHPeTgsn5Z+/VVOnFQ4rY/obrrmd/44QHDN2l +SoEHGWT6KWK+bUUytkm+uGdJjElsPYj2dXftTLc0n4AraRCEKATMHrH/dx3HuNez +YjR8oYsSQp/OpzsaYFPoid/03n66rbtLm7DSeS4SdLdnrs8f7CbEhyyZPtG8VyoI +/YMSkidOMhgfiOdGl2JcC4JDhJCOlH6cQwxU+jxLFBomqTkX03kZNzbXdiCb3SiG +sk8= +-----END CERTIFICATE----- diff -Nru trafficserver-9.2.4+ds/tests/gold_tests/tls/ssl/passphrase2.key trafficserver-9.2.5+ds/tests/gold_tests/tls/ssl/passphrase2.key --- trafficserver-9.2.4+ds/tests/gold_tests/tls/ssl/passphrase2.key 1970-01-01 00:00:00.000000000 +0000 +++ trafficserver-9.2.5+ds/tests/gold_tests/tls/ssl/passphrase2.key 2024-07-23 21:42:39.000000000 +0000 @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFJDBWBgkqhkiG9w0BBQ0wSTAxBgkqhkiG9w0BBQwwJAQQBZQrPgU+cHs3Ls4O +gfcPBwICCAAwDAYIKoZIhvcNAgkFADAUBggqhkiG9w0DBwQIBRDrt5DRnIoEggTI +S5O31tiNE8pgNMZ9MAoiNfGGJHcnvQcOnP/bosrxfXRVrumLzxLhpXhPREtBiIUk +ksuPmvobWS7AcZIPD72RpCN8NZw3lTANHnN3N7HP7qgUDbXsYhT2ssuT+BQsNRhA +y8uh0tKysVCbVNClYJvgrM2xzU7JFghaeHkJkabYJ2FKnHVRIZwkwbJWDeW0Ce/V +r858mzdmbJGack2Rg3FT5xDAqmzUc6PWSZgBXkrOwbmHJehoWTzfMSl4uBsrFKnd +KGHQJ6m24DP4Am79BOce6YoM1P36i56Rwo/q7LHI5AAadVSTLMaoD8gey6Ny9ZO9 +eflyKDW80wqmJxDevEhCKqOQbunogBuVfyo4dc2G4XPfwBhN4Vp+dVcfx9TBTdGo +gxNEd8+Nr8Ihzoff6brst9iJrBx/uWkEblSQXlp1cI9qfv8w/ji4PeLJilRaHfwV +VSr2BupIseW2GDjOOiziFvgl7Crj2kOevThunNl/IdNf8LmidUCIRJimwh38KsLx +VyG8+VFpISnkgPd89S9UEUpmUJi5hshmqpWZXLSuYUrYPucqJSKJHpqPdzcTBWg3 +kH/82T5VCYWJ/lfsl7HcfZHxfeng8636ZYZsXMwUpX3mHEGA08fuUROuekN9konO +xXxvmtmWZcyJz+eVHCL+gqyP4ecfOmkvIVin2mXSneA420lmxyzY36pox4iZbqm3 +a8NpmUd+envWlJjq7dCHIsGjBfFr3hGyjDsE3ZRuoMnGGVbwM98Nrkw5bsKWUfXQ +N3PZFZKQT/cXxpUIW/g7TLXFmP4I7o2NycV/84/vfX2tlh6nFk67JdgX54m2Et9n +M8RMNb6gU8AWfZY2kDaDd44Qx/i/7huNsEmJ5u4ze0+GoN3R+Bj6fbEKqar/SP2v +9or8yK64+A1ZHXUf6W12n9VBFsALqDIbHKxRfWiYfLv2eTnpGtxzicGp1OZMBWD4 +b1wpzGz5QjkQ3OC8zNRqSmynIJcnTSviJbAlHBSogUmOK/NAeSe8OIznpAUCHzGU +zZylmM/2O1Fpf75iuqOL6flPGbXoT5IRirmP5KevJWbadBX3O5DPP2irjO+RiGf9 +0NdbLNvZh5WWUXycjUbnS36uzPiBKD+ZclgqZBH1UYPg26/p4hR1m3cCswg1AbsL +lwjF+8w73ULHSF5VsSAa9U7QZ1DiJXFzaOyCDuCBlzFYc9v1A+kYrQVpZ1fsSubd +k14BbrDlOuSfYWL8jpRg3RBBh41zCXa297fFG0GtqVVYG90Ij2za5od+fy/Q/W1I +SJYuZndyIpf1hvGfVwRCPKcXIr7mf+//SPHBKJe5aHrpVDznEpswG3Tjcz+qM7OZ +qZG4mfNUNUa6xWcVFSdZfXRszXzJdY0N3P2JFolpmJO3oDkbZoa63ILtTf355S9Z +UVMTwX1QxGsKFG0jz92s474R2Z58A7TyRiZLQw+JxiaIDCVxaW73tr+/pCjqQwkW +RT3iHNd/BeQnbl3RV8o+jE6wKMz10mulml7yq38vmyjHtBMSwPZz668T6lb161ti +vMh/B4/bQu22DRpdtQS3B5h3XATJ7bkoG+hQUHzowz0jiK93ICZumpCYBu5V58nr +QsIKSU9+bBOlU8y28KJgNuALBZgSZ/fs +-----END ENCRYPTED PRIVATE KEY----- diff -Nru trafficserver-9.2.4+ds/tests/gold_tests/tls/ssl/passphrase2.pem trafficserver-9.2.5+ds/tests/gold_tests/tls/ssl/passphrase2.pem --- trafficserver-9.2.4+ds/tests/gold_tests/tls/ssl/passphrase2.pem 1970-01-01 00:00:00.000000000 +0000 +++ trafficserver-9.2.5+ds/tests/gold_tests/tls/ssl/passphrase2.pem 2024-07-23 21:42:39.000000000 +0000 @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEfjCCAmagAwIBAgIUWqf2OgjUkTeH4qDkqxeaeOA9EVIwDQYJKoZIhvcNAQEL +BQAwVDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAklMMQ4wDAYDVQQKDAVZYWhvbzEN +MAsGA1UECwwERWRnZTEZMBcGA1UEAwwQc2lnbmVyLnlhaG9vLmNvbTAeFw0yNDA0 +MDIyMTU5MzNaFw0yNTA0MDIyMTU5MzNaMFoxCzAJBgNVBAYTAkFVMRMwEQYDVQQI +DApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQx +EzARBgNVBAMMCnBhc3NwaHJhc2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQDRSJlZF7fVu/8etpbSYDbPL0m2Q8DHKfwinK6nqbbF7OWbQoCeHpaEppyk +9iQ/eIPCtnDD0rdA1cC9DwdOfaeaBhjXy2OaLrJGaeTUhhNcLhSwbfX26dKn5EEi +B5bRaEruKsh/MmmSe691TT6kEfpFQCK4WO9B9UXejEtI7NZ4wskaO38UjVEYLguW +wJ25mnzWQpjhYWR2G1+2Q3SCtZ82cXKJTQWuOPJHmJ5FjQQpldFJg0PKf6zAY9Vr +vkggeHiLwNKTk5R+975EB9fLoV3R69zkqf2NoMVDTvG9jd974haT/iRO9fy2pGXt +ACaxoYoVEyUbbZd9i9aR3gmczqEFAgMBAAGjQjBAMB0GA1UdDgQWBBRRijjaYGCs +ZE5bO2i7l5JA+nlGtDAfBgNVHSMEGDAWgBS8vY4PSrVikT05kO3dCxqr9MMboTAN +BgkqhkiG9w0BAQsFAAOCAgEAX2O9IBogwv+338jsvXb+ZVwHLUHFkXugqXNEI8hm +A9JFcqHwsVfOJmYGuAEjGReyjzfZou5YuzPT14VvF+wnJPA6/PbWrAKxoioq4pho +2/LRQSqe4O+T+QcSX32Nsu8h5bnv6i9MSAAWltErhOTmQkWEqYIzCh86YuHloBll +txVJ/KvWu4xetHREo1OILV5w2a5jZ7AhTqe/Yx9NmRSvQIt4MRp4DBPS8nNaUwak +3rgJV8QCIFk4+S1FqSb+4t5O7VQh4aPSmsEKHkP1Km4qFtUa4BKpDTWQTjtC/c+2 +V/ja6vFJFApniTHLpsRuu7Ma8xVulHiGuNwcvlgBtDcRAzdLcCPHCrhHpWTkrG6p +OnqznwwlBFmZHa8yiu8EHZbxH8hrPdf8VguNOc2sPEaskllmebl+XJlD0d3ulwQj +g1Gv3em0/eRWBs0sTcjTX6s852QLHPeTgsn5Z+/VVOnFQ4rY/obrrmd/44QHDN2l +SoEHGWT6KWK+bUUytkm+uGdJjElsPYj2dXftTLc0n4AraRCEKATMHrH/dx3HuNez +YjR8oYsSQp/OpzsaYFPoid/03n66rbtLm7DSeS4SdLdnrs8f7CbEhyyZPtG8VyoI +/YMSkidOMhgfiOdGl2JcC4JDhJCOlH6cQwxU+jxLFBomqTkX03kZNzbXdiCb3SiG +sk8= +-----END CERTIFICATE----- diff -Nru trafficserver-9.2.4+ds/tests/gold_tests/tls/ssl_key_dialog.test.py trafficserver-9.2.5+ds/tests/gold_tests/tls/ssl_key_dialog.test.py --- trafficserver-9.2.4+ds/tests/gold_tests/tls/ssl_key_dialog.test.py 1970-01-01 00:00:00.000000000 +0000 +++ trafficserver-9.2.5+ds/tests/gold_tests/tls/ssl_key_dialog.test.py 2024-07-23 21:42:39.000000000 +0000 @@ -0,0 +1,91 @@ +''' +''' +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding right ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +Test.Summary = ''' +Test that Trafficserver starts with default configurations. +''' + +ts = Test.MakeATSProcess("ts", enable_tls=True) +server = Test.MakeOriginServer("server") + +ts.addSSLfile("ssl/passphrase.pem") +ts.addSSLfile("ssl/passphrase.key") + +ts.addSSLfile("ssl/passphrase2.pem") +ts.addSSLfile("ssl/passphrase2.key") + +ts.Disk.remap_config.AddLine(f"map https://passphrase:{ts.Variables.ssl_port}/ http://127.0.0.1:{server.Variables.Port}") +ts.Disk.records_config.update( + { + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.debug.tags': 'ssl_load|http', + 'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir), + 'proxy.config.ssl.server.private_key.path': '{0}'.format(ts.Variables.SSLDir), + }) + +ts.Disk.ssl_multicert_config.AddLines( + [ + 'dest_ip=* ssl_cert_name=passphrase.pem ssl_key_name=passphrase.key ssl_key_dialog="exec:/bin/bash -c \'echo -n passphrase\'"', + ]) + +request_header = {"headers": "GET / HTTP/1.1\r\nHost: bogus\r\n\r\n", "timestamp": "1469733493.993", "body": ""} +response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": "success!"} +server.addResponse("sessionlog.json", request_header, response_header) + +tr = Test.AddTestRun("use a key with passphrase") +tr.Setup.Copy("ssl/signer.pem") +tr.Processes.Default.Command = f"curl -v --cacert ./signer.pem --resolve 'passphrase:{ts.Variables.ssl_port}:127.0.0.1' https://passphrase:{ts.Variables.ssl_port}/" +tr.ReturnCode = 0 +tr.Processes.Default.StartBefore(server) +tr.Processes.Default.StartBefore(Test.Processes.ts) +tr.Processes.Default.Streams.stderr.Content = Testers.ContainsExpression("200", "expected 200 OK response") +tr.Processes.Default.Streams.stdout.Content = Testers.ContainsExpression("success!", "expected success") +tr.StillRunningAfter = server +tr.StillRunningAfter = ts + +tr2 = Test.AddTestRun("Update config files") +# Update the multicert config +sslcertpath = ts.Disk.ssl_multicert_config.AbsPath +tr2.Disk.File(sslcertpath, id="ssl_multicert_config", typename="ats:config"), +tr2.Disk.ssl_multicert_config.AddLines( + [ + 'dest_ip=* ssl_cert_name=passphrase2.pem ssl_key_name=passphrase2.key ssl_key_dialog="exec:/bin/bash -c \'echo -n passphrase\'"', + ]) +tr2.StillRunningAfter = ts +tr2.StillRunningAfter = server +tr2.Processes.Default.Command = 'echo Updated configs' +# Need to copy over the environment so traffic_ctl knows where to find the unix domain socket +tr2.Processes.Default.Env = ts.Env +tr2.Processes.Default.ReturnCode = 0 + +tr2reload = Test.AddTestRun("Reload config") +tr2reload.StillRunningAfter = ts +tr2reload.StillRunningAfter = server +tr2reload.Processes.Default.Command = 'traffic_ctl config reload' +# Need to copy over the environment so traffic_ctl knows where to find the unix domain socket +tr2reload.Processes.Default.Env = ts.Env +tr2reload.Processes.Default.ReturnCode = 0 + +tr3 = Test.AddTestRun("use a key with passphrase") +tr3.Setup.Copy("ssl/signer.pem") +tr3.Processes.Default.Command = f"curl -v --cacert ./signer.pem --resolve 'passphrase:{ts.Variables.ssl_port}:127.0.0.1' https://passphrase:{ts.Variables.ssl_port}/" +tr3.ReturnCode = 0 +tr3.Processes.Default.Streams.stderr.Content = Testers.ContainsExpression("200", "expected 200 OK response") +tr3.Processes.Default.Streams.stdout.Content = Testers.ContainsExpression("success!", "expected success") +tr3.StillRunningAfter = server +tr3.StillRunningAfter = ts diff -Nru trafficserver-9.2.4+ds/tools/clang-format.sh trafficserver-9.2.5+ds/tools/clang-format.sh --- trafficserver-9.2.4+ds/tools/clang-format.sh 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/tools/clang-format.sh 2024-07-23 21:42:39.000000000 +0000 @@ -29,7 +29,7 @@ # Check for the option to just install clang-format without running it. just_install=0 - if [ $1 = "--install" ] ; then + if [ $# -gt 0 ] && [ $1 = "--install" ] ; then just_install=1 if [ $# -ne 1 ] ; then echo "No other arguments should be used with --install." diff -Nru trafficserver-9.2.4+ds/tools/package/trafficserver.spec trafficserver-9.2.5+ds/tools/package/trafficserver.spec --- trafficserver-9.2.4+ds/tools/package/trafficserver.spec 2024-04-03 15:38:30.000000000 +0000 +++ trafficserver-9.2.5+ds/tools/package/trafficserver.spec 2024-07-23 21:42:39.000000000 +0000 @@ -26,7 +26,7 @@ Summary: Apache Traffic Server, a reverse, forward and transparent HTTP proxy cache Name: trafficserver -Version: 9.2.4 +Version: 9.2.5 Release: %{release}%{?dist} License: Apache Software License 2.0 (AL2) Group: System Environment/Daemons