This is an automated email from the ASF dual-hosted git repository. masaori pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push: new 678d786c86 [compress] Add an option to do not compress partial object (#12121) 678d786c86 is described below commit 678d786c86d6e7625f97cc85c447a55aeee065be Author: Masaori Koshiba <masa...@apache.org> AuthorDate: Sun May 25 17:21:58 2025 -0500 [compress] Add an option to do not compress partial object (#12121) --- doc/admin-guide/plugins/compress.en.rst | 24 ++++++----- plugins/compress/compress.cc | 43 +++++++++++++++++--- plugins/compress/configuration.cc | 16 +++++--- plugins/compress/configuration.h | 9 +++-- .../pluginTest/compress/compress-range.test.py | 16 ++++++-- ...ig => cache-true-remove-accept-encoding.config} | 2 +- ...range.config => cache-true-remove-range.config} | 2 +- .../compress/replay/compress-and-range.replay.yaml | 46 +++++++++++++++++++--- 8 files changed, 123 insertions(+), 35 deletions(-) diff --git a/doc/admin-guide/plugins/compress.en.rst b/doc/admin-guide/plugins/compress.en.rst index 846212f142..81dec81dc8 100644 --- a/doc/admin-guide/plugins/compress.en.rst +++ b/doc/admin-guide/plugins/compress.en.rst @@ -108,20 +108,26 @@ range-request This config controls behavior of this plugin when a client send ``Range`` header and ``Accept-Encoding`` header in the same time. -============== ================================================================= -Value Description -============== ================================================================= -ignore-range Remove ``Range`` header if the request has both headers (Default) -false Same as ``ignore-range`` for compatiblity -no-compression Remove ``Accept-Encoding`` header if the request has both headers -none Do nothing -true Same as ``none`` for compatibility -============== ================================================================= +====================== ================================================================= +Value Description +====================== ================================================================= +none Do nothing +true Same as ``none`` for compatibility +remove-range Remove ``Range`` header if the request has both headers +remove-accept-encoding Remove ``Accept-Encoding`` header if the request has both headers +no-compression Do NOT compress Partial Content (default) +false Same as ``no-compression`` for compatiblity +====================== ================================================================= .. important:: Do NOT set this to ``none`` (or ``true``) if the cache config is set to ``false``. This combination will deliver corrupted content. + +.. important:: + + Some plugins (like cache_range_request) remove ``Range`` header. If you set ``remove-range`` or ``remove-accept-encoding``, be careful with the order of plugins. + compressible-content-type ------------------------- diff --git a/plugins/compress/compress.cc b/plugins/compress/compress.cc index 72556c586a..44e8235a0d 100644 --- a/plugins/compress/compress.cc +++ b/plugins/compress/compress.cc @@ -103,8 +103,8 @@ handle_range_request(TSMBuffer req_buf, TSMLoc req_loc, HostConfiguration *hc) debug("Both of Accept-Encoding and Range header are found in the request"); switch (hc->range_request_ctl()) { - case RangeRequestCtrl::IGNORE_RANGE: { - debug("Remove the Range header by ignore-range config"); + case RangeRequestCtrl::REMOVE_RANGE: { + debug("Remove the Range header by remove-range config"); while (range_hdr_field) { TSMLoc next_dup = TSMimeHdrFieldNextDup(req_buf, req_loc, range_hdr_field); TSMimeHdrFieldDestroy(req_buf, req_loc, range_hdr_field); @@ -113,8 +113,8 @@ handle_range_request(TSMBuffer req_buf, TSMLoc req_loc, HostConfiguration *hc) } break; } - case RangeRequestCtrl::NO_COMPRESSION: { - debug("Remove the Accept-Encoding header by no-compression config"); + case RangeRequestCtrl::REMOVE_ACCEPT_ENCODING: { + debug("Remove the Accept-Encoding header by remove-accept-encoding config"); while (accept_encoding_hdr_field) { TSMLoc next_dup = TSMimeHdrFieldNextDup(req_buf, req_loc, accept_encoding_hdr_field); TSMimeHdrFieldDestroy(req_buf, req_loc, accept_encoding_hdr_field); @@ -123,6 +123,10 @@ handle_range_request(TSMBuffer req_buf, TSMLoc req_loc, HostConfiguration *hc) } break; } + case RangeRequestCtrl::NO_COMPRESSION: + // Do NOT touch header - this config is referred by `transformable()` function + debug("no header modification by no-compression config"); + break; case RangeRequestCtrl::NONE: [[fallthrough]]; default: @@ -733,6 +737,33 @@ transformable(TSHttpTxn txnp, bool server, HostConfiguration *host_configuration return 0; } + // check Partial Object is transformable + if (host_configuration->range_request_ctl() == RangeRequestCtrl::NO_COMPRESSION) { + // check Range header in client request + // CAVETE: some plugin (- e.g. cache_range_request) tweaks client headers + TSMLoc range_hdr_field = TSMimeHdrFieldFind(cbuf, chdr, TS_MIME_FIELD_RANGE, TS_MIME_LEN_RANGE); + if (range_hdr_field != TS_NULL_MLOC) { + debug("Range header found in the request and range_request is configured as no_compression"); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + TSHandleMLocRelease(cbuf, chdr, range_hdr_field); + TSHandleMLocRelease(cbuf, TS_NULL_MLOC, chdr); + return 0; + } + + // check Content-Range header in (cached) server response + TSMLoc content_range_hdr_field = TSMimeHdrFieldFind(bufp, hdr_loc, TS_MIME_FIELD_CONTENT_RANGE, TS_MIME_LEN_CONTENT_RANGE); + if (content_range_hdr_field != TS_NULL_MLOC) { + debug("Content-Range header found in the response and range_request is configured as no_compression"); + TSHandleMLocRelease(bufp, hdr_loc, content_range_hdr_field); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + TSHandleMLocRelease(cbuf, TS_NULL_MLOC, chdr); + return 0; + } + + TSHandleMLocRelease(bufp, hdr_loc, content_range_hdr_field); + TSHandleMLocRelease(cbuf, chdr, range_hdr_field); + } + // the only compressible method is currently GET. int method_length; const char *method = TSHttpHdrMethodGet(cbuf, chdr, &method_length); @@ -966,8 +997,8 @@ transform_plugin(TSCont contp, TSEvent event, void *edata) * 1. Reads the client request header * 2. For global plugin, get host configuration from global config * For remap plugin, get host configuration from configs populated through remap - * 3. Check for Accept encoding - * 4. Remove Range header + * 3. Check for Accept-Encoding header + * 4. Check for Range header * 5. Schedules TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK and TS_HTTP_TXN_CLOSE_HOOK for * further processing */ diff --git a/plugins/compress/configuration.cc b/plugins/compress/configuration.cc index 9447bd6a3c..dd95952f97 100644 --- a/plugins/compress/configuration.cc +++ b/plugins/compress/configuration.cc @@ -272,16 +272,22 @@ HostConfiguration::compression_algorithms() return compression_algorithms_; } +/** + "true" and "false" are compatibility with old version, will be removed + */ void HostConfiguration::set_range_request(const std::string &token) { - // "true" and "false" are compatibility with old version, will be removed - if (token == "false" || token == "ignore-range") { - range_request_ctl_ = RangeRequestCtrl::IGNORE_RANGE; - } else if (token == "true" || token == "none") { + if (token == "true" || token == "none") { range_request_ctl_ = RangeRequestCtrl::NONE; - } else if (token == "no-compression") { + } else if (token == "false" || token == "no-compression") { range_request_ctl_ = RangeRequestCtrl::NO_COMPRESSION; + } else if (token == "remove-range") { + range_request_ctl_ = RangeRequestCtrl::REMOVE_RANGE; + } else if (token == "remove-accept-encoding") { + range_request_ctl_ = RangeRequestCtrl::REMOVE_ACCEPT_ENCODING; + } else { + error("invalid token for range_request: %s", token.c_str()); } } diff --git a/plugins/compress/configuration.h b/plugins/compress/configuration.h index f710375a13..22b2173c59 100644 --- a/plugins/compress/configuration.h +++ b/plugins/compress/configuration.h @@ -42,9 +42,10 @@ enum CompressionAlgorithm { }; enum class RangeRequestCtrl : int { - IGNORE_RANGE = 0, ///< Ignore Range Header (default) - NO_COMPRESSION = 1, ///< Do NOT compress if it's a range request - NONE = 2, ///< Do nothing + NONE = 0, ///< Do nothing + NO_COMPRESSION = 1, ///< Do NOT compress Partial Content (default) + REMOVE_RANGE = 2, ///< Remove Range Header + REMOVE_ACCEPT_ENCODING = 3, ///< Remove Accept-Encoding Header }; class HostConfiguration : private atscppapi::noncopyable @@ -148,7 +149,7 @@ private: int compression_algorithms_; unsigned int minimum_content_length_; - RangeRequestCtrl range_request_ctl_{RangeRequestCtrl::IGNORE_RANGE}; + RangeRequestCtrl range_request_ctl_ = RangeRequestCtrl::NO_COMPRESSION; StringContainer compressible_content_types_; StringContainer allows_; // maintain backwards compatibility/usability out of the box diff --git a/tests/gold_tests/pluginTest/compress/compress-range.test.py b/tests/gold_tests/pluginTest/compress/compress-range.test.py index 42c1e19e8b..0b4b874758 100644 --- a/tests/gold_tests/pluginTest/compress/compress-range.test.py +++ b/tests/gold_tests/pluginTest/compress/compress-range.test.py @@ -42,13 +42,23 @@ class CompressPluginTest: "proxy.config.http.insert_response_via_str": 2, }) - self.ts.Setup.Copy("etc/cache-true-ignore-range.config") + self.ts.Setup.Copy("etc/cache-true-remove-range.config") + self.ts.Setup.Copy("etc/cache-true-remove-accept-encoding.config") self.ts.Setup.Copy("etc/cache-true-no-compression.config") self.ts.Disk.remap_config.AddLines( { - f"map /cache-true-ignore-range/ http://127.0.0.1:{self.server.Variables.http_port}/ @plugin=compress.so @pparam={Test.RunDirectory}/cache-true-ignore-range.config", - f"map /cache-true-no-compression/ http://127.0.0.1:{self.server.Variables.http_port}/ @plugin=compress.so @pparam={Test.RunDirectory}/cache-true-no-compression.config", + f""" +map /cache-true-remove-range/ http://127.0.0.1:{self.server.Variables.http_port}/ \ + @plugin=compress.so \ + @pparam={Test.RunDirectory}/cache-true-remove-range.config +map /cache-true-remove-accept-encoding/ http://127.0.0.1:{self.server.Variables.http_port}/ \ + @plugin=compress.so \ + @pparam={Test.RunDirectory}/cache-true-remove-accept-encoding.config +map /cache-true-no-compression/ http://127.0.0.1:{self.server.Variables.http_port}/ \ + @plugin=compress.so \ + @pparam={Test.RunDirectory}/cache-true-no-compression.config +""" }) def run(self): diff --git a/tests/gold_tests/pluginTest/compress/etc/cache-true-ignore-range.config b/tests/gold_tests/pluginTest/compress/etc/cache-true-remove-accept-encoding.config similarity index 73% copy from tests/gold_tests/pluginTest/compress/etc/cache-true-ignore-range.config copy to tests/gold_tests/pluginTest/compress/etc/cache-true-remove-accept-encoding.config index c961699cc0..5fd5911ce5 100644 --- a/tests/gold_tests/pluginTest/compress/etc/cache-true-ignore-range.config +++ b/tests/gold_tests/pluginTest/compress/etc/cache-true-remove-accept-encoding.config @@ -1,5 +1,5 @@ cache true -range-request ignore-range +range-request remove-accept-encoding compressible-content-type application/json supported-algorithms gzip minimum-content-length 0 diff --git a/tests/gold_tests/pluginTest/compress/etc/cache-true-ignore-range.config b/tests/gold_tests/pluginTest/compress/etc/cache-true-remove-range.config similarity index 79% rename from tests/gold_tests/pluginTest/compress/etc/cache-true-ignore-range.config rename to tests/gold_tests/pluginTest/compress/etc/cache-true-remove-range.config index c961699cc0..a1bbadc146 100644 --- a/tests/gold_tests/pluginTest/compress/etc/cache-true-ignore-range.config +++ b/tests/gold_tests/pluginTest/compress/etc/cache-true-remove-range.config @@ -1,5 +1,5 @@ cache true -range-request ignore-range +range-request remove-range compressible-content-type application/json supported-algorithms gzip minimum-content-length 0 diff --git a/tests/gold_tests/pluginTest/compress/replay/compress-and-range.replay.yaml b/tests/gold_tests/pluginTest/compress/replay/compress-and-range.replay.yaml index 8582997504..071446448d 100644 --- a/tests/gold_tests/pluginTest/compress/replay/compress-and-range.replay.yaml +++ b/tests/gold_tests/pluginTest/compress/replay/compress-and-range.replay.yaml @@ -45,14 +45,14 @@ sessions: # # ``` # cache true - # range-request ignore-range + # range-request remove-range #``` # # 1-1: Accept-Encoding only - client-request: method: "GET" version: "1.1" - url: /cache-true-ignore-range/ + url: /cache-true-remove-range/ headers: fields: - [ uuid, 1-1] @@ -73,7 +73,7 @@ sessions: - client-request: method: "GET" version: "1.1" - url: /cache-true-ignore-range/ + url: /cache-true-remove-range/ headers: fields: - [ uuid, 1-2] @@ -98,7 +98,7 @@ sessions: - client-request: method: "GET" version: "1.1" - url: /cache-true-ignore-range/ + url: /cache-true-remove-range/ headers: fields: - [ uuid, 1-3] @@ -125,14 +125,14 @@ sessions: # # ``` # cache true - # range-request no-compression + # range-request remove-accept-encoding #``` # # 2-1: Range and Accept-Encoding - client-request: method: "GET" version: "1.1" - url: /cache-true-no-compression/ + url: /cache-true-remove-accept-encoding/ headers: fields: - [ uuid, 2-1] @@ -154,3 +154,37 @@ sessions: fields: - [ Content-Length, { value: 10, as: equal } ] + # Test Case 3 + # + # ``` + # cache true + # range-request no-compression + #``` + # + # 3-1: Range and Accept-Encoding + - client-request: + method: "GET" + version: "1.1" + url: /cache-true-no-compression/ + headers: + fields: + - [ uuid, 3-1] + - [ Host, example.com ] + - [ Range, 0-9 ] + - [ Accept-Encoding, gzip ] + + proxy-request: + headers: + fields: + - [ Range, { as: present } ] + - [ Accept-Encoding, { as: present } ] + + server-response: + <<: *origin-server-response-206 + + proxy-response: + status: 206 + headers: + fields: + - [ Content-Length, { value: 10, as: equal } ] +