This is an automated email from the ASF dual-hosted git repository. lserris 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 b5c45a344 Add slice config to strip Range header for HEAD requests (#9238) b5c45a344 is described below commit b5c45a34495a218475efdc825f01c38eda4a68a5 Author: Serris Lew <serrisn...@gmail.com> AuthorDate: Thu Jan 12 13:54:43 2023 -0800 Add slice config to strip Range header for HEAD requests (#9238) * Add slice plugin config to strip Range header for HEAD requests * Remove trailing whitespaces * Add Head to config name for clarity * Add verification directives to autest replay Co-authored-by: Serris Lew <lser...@apple.com> --- doc/admin-guide/plugins/slice.en.rst | 4 ++ plugins/experimental/slice/Config.cc | 4 ++ plugins/experimental/slice/Config.h | 5 +- plugins/experimental/slice/server.cc | 8 +++ plugins/experimental/slice/util.cc | 17 +++-- .../slice/replay/slice_range.replay.yaml | 83 ++++++++++++++++++++++ .../pluginTest/slice/slice_rm_range.test.py | 70 ++++++++++++++++++ 7 files changed, 183 insertions(+), 8 deletions(-) diff --git a/doc/admin-guide/plugins/slice.en.rst b/doc/admin-guide/plugins/slice.en.rst index 8426c18b0..c3a875eeb 100644 --- a/doc/admin-guide/plugins/slice.en.rst +++ b/doc/admin-guide/plugins/slice.en.rst @@ -135,6 +135,10 @@ The slice plugin supports the following options:: can improve cache miss latency. -f for short + --strip-range-for-head (optional) + Enable slice plugin to strip Range header for HEAD requests. + -h for short + Examples:: @plugin=slice.so @pparam=--blockbytes=1000000 @plugin=cache_range_requests.so diff --git a/plugins/experimental/slice/Config.cc b/plugins/experimental/slice/Config.cc index 5cd71d473..65ca648ba 100644 --- a/plugins/experimental/slice/Config.cc +++ b/plugins/experimental/slice/Config.cc @@ -124,6 +124,7 @@ Config::fromArgs(int const argc, char const *const argv[]) {const_cast<char *>("skip-header"), required_argument, nullptr, 's'}, {const_cast<char *>("blockbytes-test"), required_argument, nullptr, 't'}, {const_cast<char *>("prefetch-count"), required_argument, nullptr, 'f'}, + {const_cast<char *>("strip-range-for-head"), no_argument, nullptr, 'h'}, {nullptr, 0, nullptr, 0}, }; @@ -226,6 +227,9 @@ Config::fromArgs(int const argc, char const *const argv[]) case 'f': { m_prefetchcount = atoi(optarg); } break; + case 'h': { + m_head_strip_range = true; + } break; default: break; } diff --git a/plugins/experimental/slice/Config.h b/plugins/experimental/slice/Config.h index d1dceb99e..c83badc52 100644 --- a/plugins/experimental/slice/Config.h +++ b/plugins/experimental/slice/Config.h @@ -44,8 +44,9 @@ struct Config { int m_paceerrsecs{0}; // -1 disable logging, 0 no pacing, max 60s int m_prefetchcount{0}; // 0 disables prefetching enum RefType { First, Relative }; - RefType m_reftype{First}; // reference slice is relative to request - bool m_head_req{false}; // HEAD request + RefType m_reftype{First}; // reference slice is relative to request + bool m_head_req{false}; // HEAD request + bool m_head_strip_range{false}; // strip range header for head requests std::string m_skip_header; std::string m_crr_ims_header; diff --git a/plugins/experimental/slice/server.cc b/plugins/experimental/slice/server.cc index d79425921..7861c3c12 100644 --- a/plugins/experimental/slice/server.cc +++ b/plugins/experimental/slice/server.cc @@ -111,6 +111,14 @@ handleFirstServerHeader(Data *const data, TSCont const contp) // Should run TSVIONSetBytes(output_io, hlen + bodybytes); int64_t const hlen = TSHttpHdrLengthGet(header.m_buffer, header.m_lochdr); int64_t const clen = contentLengthFrom(header); + if (data->m_config->m_head_req && TS_HTTP_STATUS_OK == header.status()) { + DEBUG_LOG("HEAD request stripped Range header: expects 200"); + TSVIONBytesSet(output_vio, hlen); + TSHttpHdrPrint(header.m_buffer, header.m_lochdr, output_buf); + data->m_bytessent = hlen; + TSVIOReenable(output_vio); + return HeaderState::Good; + } DEBUG_LOG("Passthru bytes: header: %" PRId64 " body: %" PRId64, hlen, clen); if (clen != INT64_MAX) { TSVIONBytesSet(output_vio, hlen + clen); diff --git a/plugins/experimental/slice/util.cc b/plugins/experimental/slice/util.cc index 60b7a175d..b91636b02 100644 --- a/plugins/experimental/slice/util.cc +++ b/plugins/experimental/slice/util.cc @@ -79,12 +79,17 @@ request_block(TSCont contp, Data *const data) // reuse the incoming client header, just change the range HttpHeader header(data->m_req_hdrmgr.m_buffer, data->m_req_hdrmgr.m_lochdr); - // add/set sub range key and add slicer tag - bool const rangestat = header.setKeyVal(TS_MIME_FIELD_RANGE, TS_MIME_LEN_RANGE, rangestr, rangelen); - - if (!rangestat) { - ERROR_LOG("Error trying to set range request header %s", rangestr); - return false; + // if configured, remove range header from head requests + if (data->m_config->m_head_req && data->m_config->m_head_strip_range) { + header.removeKey(TS_MIME_FIELD_RANGE, TS_MIME_LEN_RANGE); + } else { + // add/set sub range key and add slicer tag + bool const rangestat = header.setKeyVal(TS_MIME_FIELD_RANGE, TS_MIME_LEN_RANGE, rangestr, rangelen); + + if (!rangestat) { + ERROR_LOG("Error trying to set range request header %s", rangestr); + return false; + } } header.removeKey(SLICE_CRR_HEADER.data(), SLICE_CRR_HEADER.size()); diff --git a/tests/gold_tests/pluginTest/slice/replay/slice_range.replay.yaml b/tests/gold_tests/pluginTest/slice/replay/slice_range.replay.yaml new file mode 100644 index 000000000..793ec66c5 --- /dev/null +++ b/tests/gold_tests/pluginTest/slice/replay/slice_range.replay.yaml @@ -0,0 +1,83 @@ +# 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" + +sessions: +- transactions: + - client-request: + method: "HEAD" + version: "1.1" + url: /no/range + headers: + fields: + - [ Host, example.com ] + - [ X-Request, request ] + - [ Range, bytes=0-5 ] + - [ uuid, 1 ] + + proxy-request: + headers: + fields: + - [ Range, { as: absent } ] + + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Content-Length, 16 ] + - [ X-Response, response ] + + proxy-response: + status: 200 + headers: + fields: + - [ X-Response, { value: response, as: equal } ] + - [ Content-Length, { value: "16", as: equal} ] + + - client-request: + method: "HEAD" + version: "1.1" + url: /with/range + headers: + fields: + - [ Host, example.com ] + - [ X-Request, request ] + - [ Range, bytes=0-5 ] + - [ uuid, 2 ] + + proxy-request: + headers: + fields: + - [ Range, { as: present } ] + + server-response: + status: 206 + headers: + fields: + - [ Content-Length, 6 ] + - [ X-Response, response ] + - [ Content-Range, bytes 0-5/16 ] + + proxy-response: + status: 206 + headers: + fields: + - [ Content-Length, { value: "6", as: equal} ] + - [ Content-Range, { value: "bytes 0-5/16", as: equal} ] + - [ X-Response, { value: response, as: equal } ] \ No newline at end of file diff --git a/tests/gold_tests/pluginTest/slice/slice_rm_range.test.py b/tests/gold_tests/pluginTest/slice/slice_rm_range.test.py new file mode 100644 index 000000000..ab8101a34 --- /dev/null +++ b/tests/gold_tests/pluginTest/slice/slice_rm_range.test.py @@ -0,0 +1,70 @@ +''' +Verify ATS slice plugin config: @pparam=--strip-range-for-head +''' +# 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. + +Test.Summary = ''' +Verify ATS slice plugin config: @pparam=--strip-range-for-head +''' +Test.SkipUnless( + Condition.PluginExists('slice.so'), + Condition.PluginExists('cache_range_requests.so'), +) + + +class SliceStripRangeForHeadRequestTest: + replay_file = "replay/slice_range.replay.yaml" + + def __init__(self): + """Initialize the Test processes for the test runs.""" + self._server = Test.MakeVerifierServerProcess("server", SliceStripRangeForHeadRequestTest.replay_file) + self._configure_trafficserver() + + def _configure_trafficserver(self): + """Configure Traffic Server.""" + self._ts = Test.MakeATSProcess("ts", enable_cache=False) + + self._ts.Disk.remap_config.AddLines([ + f"map /no/range http://127.0.0.1:{self._server.Variables.http_port} \ + @plugin=slice.so @pparam=--blockbytes-test=10 @pparam=--strip-range-for-head \ + @plugin=cache_range_requests.so", + f"map /with/range http://127.0.0.1:{self._server.Variables.http_port} \ + @plugin=slice.so @pparam=--blockbytes-test=10 \ + @plugin=cache_range_requests.so", + ]) + + self._ts.Disk.records_config.update({ + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.debug.tags': 'http|slice|cache_range_requests', + }) + + def _test_head_request_range_header(self): + tr = Test.AddTestRun() + + tr.AddVerifierClientProcess( + "client", + SliceStripRangeForHeadRequestTest.replay_file, + http_ports=[self._ts.Variables.port]) + + tr.Processes.Default.StartBefore(self._server) + tr.Processes.Default.StartBefore(self._ts) + + def run(self): + self._test_head_request_range_header() + + +SliceStripRangeForHeadRequestTest().run()