This is an automated email from the ASF dual-hosted git repository. bcall pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit 1ba43047641e1db238ee15a6fa1a1d8dcd371bc5 Author: Brian Neradt <brian.ner...@gmail.com> AuthorDate: Mon Nov 30 12:45:48 2020 -0600 Add negative caching tests and fixes. (#7361) This adds test coverage for the negative caching feature and makes some fixes as a result of the test's findings. (cherry picked from commit 8eb68266167d8f8b3fa3a00ca9f6b7889e8ec101) --- doc/admin-guide/files/records.config.en.rst | 4 +- doc/admin-guide/performance/index.en.rst | 4 +- mgmt/RecordsConfig.cc | 2 +- proxy/http/HttpConfig.cc | 2 +- proxy/http/HttpSM.cc | 9 +- proxy/http/HttpTransact.cc | 38 ++-- proxy/http/HttpTransact.h | 19 +- .../autest-site/verifier_server.test.ext | 4 + tests/gold_tests/cache/negative-caching.test.py | 163 ++++++++++++++++ ...negative-caching-300-second-timeout.replay.yaml | 72 +++++++ .../replay/negative-caching-customized.replay.yaml | 164 ++++++++++++++++ .../replay/negative-caching-default.replay.yaml | 206 +++++++++++++++++++++ .../replay/negative-caching-disabled.replay.yaml | 201 ++++++++++++++++++++ .../replay/negative-caching-no-timeout.replay.yaml | 53 ++++++ .../replay/negative-caching-timeout.replay.yaml | 84 +++++++++ 15 files changed, 993 insertions(+), 32 deletions(-) diff --git a/doc/admin-guide/files/records.config.en.rst b/doc/admin-guide/files/records.config.en.rst index bc53bff..88cbfe1 100644 --- a/doc/admin-guide/files/records.config.en.rst +++ b/doc/admin-guide/files/records.config.en.rst @@ -1625,11 +1625,9 @@ Negative Response Caching ====================== ===================================================== ``204`` No Content ``305`` Use Proxy - ``400`` Bad Request ``403`` Forbidden ``404`` Not Found ``414`` URI Too Long - ``405`` Method Not Allowed ``500`` Internal Server Error ``501`` Not Implemented ``502`` Bad Gateway @@ -1647,7 +1645,7 @@ Negative Response Caching How long (in seconds) |TS| keeps the negative responses valid in cache. This value only affects negative responses that do NOT have explicit ``Expires:`` or ``Cache-Control:`` lifetimes set by the server. -.. ts:cv:: CONFIG proxy.config.http.negative_caching_list STRING 204 305 403 404 405 414 500 501 502 503 504 +.. ts:cv:: CONFIG proxy.config.http.negative_caching_list STRING 204 305 403 404 414 500 501 502 503 504 :reloadable: The HTTP status code for negative caching. Default values are mentioned above. The unwanted status codes can be diff --git a/doc/admin-guide/performance/index.en.rst b/doc/admin-guide/performance/index.en.rst index 623cdae..f3bd176 100644 --- a/doc/admin-guide/performance/index.en.rst +++ b/doc/admin-guide/performance/index.en.rst @@ -495,7 +495,7 @@ Error responses from origins are consistent and costly If error responses are costly for your origin server to generate, you may elect to have |TS| cache these responses for a period of time. The default behavior is to consider all of these responses to be uncacheable, which will lead to every -client request to result in an origin request. +client request resulting in an origin request. This behavior is controlled by both enabling the feature via :ts:cv:`proxy.config.http.negative_caching_enabled` and setting the cache time @@ -504,7 +504,7 @@ status code for negative caching can be set with :ts:cv:`proxy.config.http.negat CONFIG proxy.config.http.negative_caching_enabled INT 1 CONFIG proxy.config.http.negative_caching_lifetime INT 10 - CONFIG proxy.config.http.negative_caching_list STRING 204 305 403 404 405 414 500 501 502 503 504 + CONFIG proxy.config.http.negative_caching_list STRING 204 305 403 404 414 500 501 502 503 504 SSL-Specific Options ~~~~~~~~~~~~~~~~~~~~ diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index b9854f9..7120fa5 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -503,7 +503,7 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.http.negative_caching_lifetime", RECD_INT, "1800", RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , - {RECT_CONFIG, "proxy.config.http.negative_caching_list", RECD_STRING, "204 305 403 404 405 414 500 501 502 503 504", RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL} + {RECT_CONFIG, "proxy.config.http.negative_caching_list", RECD_STRING, "204 305 403 404 414 500 501 502 503 504", RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , // ######################### diff --git a/proxy/http/HttpConfig.cc b/proxy/http/HttpConfig.cc index b32e39c..9b55951 100644 --- a/proxy/http/HttpConfig.cc +++ b/proxy/http/HttpConfig.cc @@ -1036,7 +1036,7 @@ set_negative_caching_list(const char *name, RecDataT dtype, RecData data, HttpCo HttpStatusBitset set; // values from proxy.config.http.negative_caching_list if (0 == strcasecmp("proxy.config.http.negative_caching_list", name) && RECD_STRING == dtype && data.rec_string) { - // parse the list of status code + // parse the list of status codes ts::TextView status_list(data.rec_string, strlen(data.rec_string)); auto is_sep{[](char c) { return isspace(c) || ',' == c || ';' == c; }}; while (!status_list.ltrim_if(is_sep).empty()) { diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc index 93e61f8..61bb2c0 100644 --- a/proxy/http/HttpSM.cc +++ b/proxy/http/HttpSM.cc @@ -3021,7 +3021,7 @@ HttpSM::tunnel_handler_server(int event, HttpTunnelProducer *p) // the reason string being written to the client and a bad CL when reading from cache. // I didn't find anywhere this appended reason is being used, so commenting it out. /* - if (t_state.negative_caching && p->bytes_read == 0) { + if (t_state.is_cacheable_and_negative_caching_is_enabled && p->bytes_read == 0) { int reason_len; const char *reason = t_state.hdr_info.server_response.reason_get(&reason_len); if (reason == NULL) @@ -3077,8 +3077,8 @@ HttpSM::tunnel_handler_server(int event, HttpTunnelProducer *p) } // turn off negative caching in case there are multiple server contacts - if (t_state.negative_caching) { - t_state.negative_caching = false; + if (t_state.is_cacheable_and_negative_caching_is_enabled) { + t_state.is_cacheable_and_negative_caching_is_enabled = false; } // If we had a ground fill, check update our status @@ -6725,7 +6725,8 @@ HttpSM::setup_server_transfer() nbytes = server_transfer_init(buf, hdr_size); - if (t_state.negative_caching && t_state.hdr_info.server_response.status_get() == HTTP_STATUS_NO_CONTENT) { + if (t_state.is_cacheable_and_negative_caching_is_enabled && + t_state.hdr_info.server_response.status_get() == HTTP_STATUS_NO_CONTENT) { int s = sizeof("No Content") - 1; buf->write("No Content", s); nbytes += s; diff --git a/proxy/http/HttpTransact.cc b/proxy/http/HttpTransact.cc index c9a1c47..74f5720 100644 --- a/proxy/http/HttpTransact.cc +++ b/proxy/http/HttpTransact.cc @@ -4437,7 +4437,7 @@ HttpTransact::handle_cache_operation_on_forward_server_response(State *s) client_response_code = server_response_code; base_response = &s->hdr_info.server_response; - s->negative_caching = is_negative_caching_appropriate(s) && cacheable; + s->is_cacheable_and_negative_caching_is_enabled = cacheable && s->txn_conf->negative_caching_enabled; // determine the correct cache action given the original cache action, // cacheability of server response, and request method @@ -4472,7 +4472,7 @@ HttpTransact::handle_cache_operation_on_forward_server_response(State *s) } } else if (s->cache_info.action == CACHE_DO_WRITE) { - if (!cacheable && !s->negative_caching) { + if (!cacheable) { s->cache_info.action = CACHE_DO_NO_ACTION; } else if (s->method == HTTP_WKSIDX_HEAD) { s->cache_info.action = CACHE_DO_NO_ACTION; @@ -4499,7 +4499,7 @@ HttpTransact::handle_cache_operation_on_forward_server_response(State *s) // before issuing a 304 if (s->cache_info.action == CACHE_DO_WRITE || s->cache_info.action == CACHE_DO_NO_ACTION || s->cache_info.action == CACHE_DO_REPLACE) { - if (s->negative_caching) { + if (s->is_cacheable_and_negative_caching_is_enabled) { HTTPHdr *resp; s->cache_info.object_store.create(); s->cache_info.object_store.request_set(&s->hdr_info.client_request); @@ -4535,8 +4535,8 @@ HttpTransact::handle_cache_operation_on_forward_server_response(State *s) SET_VIA_STRING(VIA_PROXY_RESULT, VIA_PROXY_SERVER_REVALIDATED); } } - } else if (s->negative_caching) { - s->negative_caching = false; + } else if (s->is_cacheable_and_negative_caching_is_enabled) { + s->is_cacheable_and_negative_caching_is_enabled = false; } break; @@ -4946,7 +4946,7 @@ HttpTransact::set_headers_for_cache_write(State *s, HTTPInfo *cache_info, HTTPHd sites yields no insight. So the assert is removed and we keep the behavior that if the response in @a cache_info is already set, we don't override it. */ - if (!s->negative_caching || !cache_info->response_get()->valid()) { + if (!s->is_cacheable_and_negative_caching_is_enabled || !cache_info->response_get()->valid()) { cache_info->response_set(response); } @@ -6353,24 +6353,24 @@ HttpTransact::is_response_cacheable(State *s, HTTPHdr *request, HTTPHdr *respons } } - // default cacheability - if (!s->txn_conf->negative_caching_enabled) { - if ((response_code == HTTP_STATUS_OK) || (response_code == HTTP_STATUS_NOT_MODIFIED) || - (response_code == HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION) || (response_code == HTTP_STATUS_MOVED_PERMANENTLY) || - (response_code == HTTP_STATUS_MULTIPLE_CHOICES) || (response_code == HTTP_STATUS_GONE)) { - TxnDebug("http_trans", "[is_response_cacheable] YES by default "); - return true; - } else { - TxnDebug("http_trans", "[is_response_cacheable] NO by default"); - return false; - } + if ((response_code == HTTP_STATUS_OK) || (response_code == HTTP_STATUS_NOT_MODIFIED) || + (response_code == HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION) || (response_code == HTTP_STATUS_MOVED_PERMANENTLY) || + (response_code == HTTP_STATUS_MULTIPLE_CHOICES) || (response_code == HTTP_STATUS_GONE)) { + TxnDebug("http_trans", "[is_response_cacheable] YES response code seems fine"); + return true; } + // Notice that the following are not overridable by negative caching. if (response_code == HTTP_STATUS_SEE_OTHER || response_code == HTTP_STATUS_UNAUTHORIZED || response_code == HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED) { return false; } - // let is_negative_caching_approriate decide what to do - return true; + // The response code does not look appropriate for caching. Check, however, + // whether the user has specified it should be cached via negative response + // caching configuration. + if (is_negative_caching_appropriate(s)) { + return true; + } + return false; /* Since we weren't caching response obtained with Authorization (the cache control stuff was commented out previously) I've moved this check to is_request_cache_lookupable(). diff --git a/proxy/http/HttpTransact.h b/proxy/http/HttpTransact.h index f9900a2..a5ee5cf 100644 --- a/proxy/http/HttpTransact.h +++ b/proxy/http/HttpTransact.h @@ -757,8 +757,23 @@ public: bool client_connection_enabled = true; bool acl_filtering_performed = false; - // for negative caching - bool negative_caching = false; + /// True if negative caching is enabled and the response is cacheable. + /// + /// Note carefully that this being true does not necessarily imply that the + /// response code was negative. It means that (a) the response was + /// cacheable apart from response code considerations, and (b) concerning + /// the response code one of the following was true: + /// + /// * The response was a negative response code configured cacheable + /// by the user via negative response caching configuration, or ... + /// + /// * The response code was an otherwise cacheable positive repsonse + /// value (such as a 200 response, for example). + /// + /// TODO: We should consider refactoring this variable and its use. For now + /// I'm giving it an awkwardly long name to make sure the meaning of it is + /// clear in its various contexts. + bool is_cacheable_and_negative_caching_is_enabled = false; // for authenticated content caching CacheAuth_t www_auth_content = CACHE_AUTH_NONE; diff --git a/tests/gold_tests/autest-site/verifier_server.test.ext b/tests/gold_tests/autest-site/verifier_server.test.ext index 52cc92c..3852e22 100755 --- a/tests/gold_tests/autest-site/verifier_server.test.ext +++ b/tests/gold_tests/autest-site/verifier_server.test.ext @@ -51,6 +51,8 @@ def _configure_server(obj, process, name, replay_path, http_ports=None, https_po if http_ports is None: get_port(process, "http_port") http_ports = [process.Variables.http_port] + else: + process.Variables['http_port'] = http_ports[0] if len(http_ports) > 0: command += "--listen " @@ -60,6 +62,8 @@ def _configure_server(obj, process, name, replay_path, http_ports=None, https_po if https_ports is None: get_port(process, "https_port") https_ports = [process.Variables.https_port] + else: + process.Variables['https_port'] = https_ports[0] if len(https_ports) > 0: command += '--listen-https ' diff --git a/tests/gold_tests/cache/negative-caching.test.py b/tests/gold_tests/cache/negative-caching.test.py new file mode 100644 index 0000000..3152ae5 --- /dev/null +++ b/tests/gold_tests/cache/negative-caching.test.py @@ -0,0 +1,163 @@ +''' +Test negative caching. +''' +# 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 = ''' +Test negative caching. +''' + +# +# Negative caching disabled. +# +ts = Test.MakeATSProcess("ts-disabled") +replay_file = "replay/negative-caching-disabled.replay.yaml" +server = Test.MakeVerifierServerProcess("server-disabled", replay_file) +ts.Disk.records_config.update({ + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.debug.tags': 'http', + 'proxy.config.http.insert_age_in_response': 0, + + 'proxy.config.http.negative_caching_enabled': 0 +}) +ts.Disk.remap_config.AddLine( + 'map / http://127.0.0.1:{0}'.format(server.Variables.http_port) +) +tr = Test.AddTestRun("Verify correct behavior without negative caching enabled.") +tr.Processes.Default.StartBefore(server) +tr.Processes.Default.StartBefore(ts) +tr.AddVerifierClientProcess("client-disabled", replay_file, http_ports=[ts.Variables.port]) + +# +# Negative caching enabled with otherwise default configuration. +# +ts = Test.MakeATSProcess("ts-default") +replay_file = "replay/negative-caching-default.replay.yaml" +server = Test.MakeVerifierServerProcess("server-default", replay_file) +ts.Disk.records_config.update({ + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.debug.tags': 'http', + 'proxy.config.http.insert_age_in_response': 0, + + 'proxy.config.http.negative_caching_enabled': 1 +}) +ts.Disk.remap_config.AddLine( + 'map / http://127.0.0.1:{0}'.format(server.Variables.http_port) +) +tr = Test.AddTestRun("Verify default negative caching behavior") +tr.Processes.Default.StartBefore(server) +tr.Processes.Default.StartBefore(ts) +tr.AddVerifierClientProcess("client-default", replay_file, http_ports=[ts.Variables.port]) + +# +# Customized response caching for negative caching configuration. +# +ts = Test.MakeATSProcess("ts-customized") +replay_file = "replay/negative-caching-customized.replay.yaml" +server = Test.MakeVerifierServerProcess("server-customized", replay_file) +ts.Disk.records_config.update({ + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.debug.tags': 'http', + 'proxy.config.http.insert_age_in_response': 0, + + 'proxy.config.http.negative_caching_enabled': 1, + 'proxy.config.http.negative_caching_list': "400" +}) +ts.Disk.remap_config.AddLine( + 'map / http://127.0.0.1:{0}'.format(server.Variables.http_port) +) +tr = Test.AddTestRun("Verify customized negative caching list") +tr.Processes.Default.StartBefore(server) +tr.Processes.Default.StartBefore(ts) +tr.AddVerifierClientProcess("client-customized", replay_file, http_ports=[ts.Variables.port]) + +# +# Verify correct proxy.config.http.negative_caching_lifetime behavior. +# +ts = Test.MakeATSProcess("ts-lifetime") +ts.Disk.records_config.update({ + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.debug.tags': 'http', + 'proxy.config.http.insert_age_in_response': 0, + + 'proxy.config.http.negative_caching_enabled': 1, + 'proxy.config.http.negative_caching_lifetime': 2 +}) +# This should all behave the same as the default enabled case above. +tr = Test.AddTestRun("Add a 404 response to the cache") +replay_file = "replay/negative-caching-default.replay.yaml" +server = tr.AddVerifierServerProcess("server-lifetime-no-cc", replay_file) +# Use the same port across the two servers so that the remap config will work +# across both. +server_port = server.Variables.http_port +tr.AddVerifierClientProcess("client-lifetime-no-cc", replay_file, http_ports=[ts.Variables.port]) +ts.Disk.remap_config.AddLine( + 'map / http://127.0.0.1:{0}'.format(server_port) +) +tr.Processes.Default.StartBefore(ts) +tr.StillRunningAfter = ts + +# Wait enough time that the item should be aged out of the cache. +tr = Test.AddTestRun("Wait for cached object to be stale.") +tr.Processes.Default.Command = "sleep 4" +tr.StillRunningAfter = ts + +# Verify the item is retrieved from the server instead of the cache. +replay_file = "replay/negative-caching-timeout.replay.yaml" +tr = Test.AddTestRun("Make sure object is stale") +tr.AddVerifierServerProcess("server-timeout", replay_file, http_ports=[server_port]) +tr.AddVerifierClientProcess("client-timeout", replay_file, http_ports=[ts.Variables.port]) +tr.StillRunningAfter = ts + +# +# Verify that the server's Cache-Control overrides the +# proxy.config.http.negative_caching_lifetime. +# +ts = Test.MakeATSProcess("ts-lifetime-2") +ts.Disk.records_config.update({ + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.debug.tags': 'http', + 'proxy.config.http.insert_age_in_response': 0, + + 'proxy.config.http.negative_caching_enabled': 1, + 'proxy.config.http.negative_caching_lifetime': 2 +}) +tr = Test.AddTestRun("Add a 404 response with explicit max-age=300 to the cache") +replay_file = "replay/negative-caching-300-second-timeout.replay.yaml" +server = tr.AddVerifierServerProcess("server-lifetime-cc", replay_file) +# Use the same port across the two servers so that the remap config will work +# across both. +server_port = server.Variables.http_port +tr.AddVerifierClientProcess("client-lifetime-cc", replay_file, http_ports=[ts.Variables.port]) +ts.Disk.remap_config.AddLine( + 'map / http://127.0.0.1:{0}'.format(server_port) +) +tr.Processes.Default.StartBefore(ts) +tr.StillRunningAfter = ts + +# Wait enough time that the item should be aged out of the cache if +# proxy.config.http.negative_caching_lifetime is incorrectly used. +tr = Test.AddTestRun("Wait for cached object to be stale if lifetime is incorrectly used.") +tr.Processes.Default.Command = "sleep 4" +tr.StillRunningAfter = ts + +# Verify the item is retrieved from the cache instead of going to the origin. +replay_file = "replay/negative-caching-no-timeout.replay.yaml" +tr = Test.AddTestRun("Make sure object is fresh") +tr.AddVerifierServerProcess("server-no-timeout", replay_file, http_ports=[server_port]) +tr.AddVerifierClientProcess("client-no-timeout", replay_file, http_ports=[ts.Variables.port]) +tr.StillRunningAfter = ts diff --git a/tests/gold_tests/cache/replay/negative-caching-300-second-timeout.replay.yaml b/tests/gold_tests/cache/replay/negative-caching-300-second-timeout.replay.yaml new file mode 100644 index 0000000..999b8cd --- /dev/null +++ b/tests/gold_tests/cache/replay/negative-caching-300-second-timeout.replay.yaml @@ -0,0 +1,72 @@ +# 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. + +# +# Create a cached response with a max-age of 300 seconds. +# +# This replay file assumes that negative caching is configured to result in the +# caching of 404 responses (as is the case with default negative caching +# configuration.) +# + +meta: + version: "1.0" + + blocks: + - request_404_item: &request_404_item + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/404_300_second_timeout + headers: + fields: + - [ Host, example.com ] + +sessions: +- transactions: + + - all: { headers: { fields: [[ uuid, 21 ]]}} + <<: *request_404_item + + # Populate the cache with a 404 response. + server-response: + status: 404 + reason: "Not Found" + headers: + fields: + - [ Content-Length, 32 ] + - [ Cache-Control, max-age=300 ] + + proxy-response: + status: 404 + + - all: { headers: { fields: [[ uuid, 22 ]]}} + <<: *request_404_item + + # 404 responses should be cached when negative caching is enabled, so this + # should not get to the server. But if it does, return a 200 so the test + # knows that something went wrong. + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Content-Length, 0 ] + + # Expect the cached 404 response. + proxy-response: + status: 404 diff --git a/tests/gold_tests/cache/replay/negative-caching-customized.replay.yaml b/tests/gold_tests/cache/replay/negative-caching-customized.replay.yaml new file mode 100644 index 0000000..6d51bd3 --- /dev/null +++ b/tests/gold_tests/cache/replay/negative-caching-customized.replay.yaml @@ -0,0 +1,164 @@ +# 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. + +# +# This replay file assumes a negative caching configuration in which 400 +# responses, and only 400 responses, are cached. This is done via +# `proxy.config.http.negative_caching_list`. +# + +meta: + version: "1.0" + + blocks: + - 200_response: &200_response + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Content-Length, 16 ] + - [ Cache-Control, max-age=300 ] + +sessions: +- transactions: + + # + # Test 1: Verify that a 404 response is not cached since the custom + # negative_caching_list excludes it. + # + - all: { headers: { fields: [[ uuid, 1 ]]}} + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/404 + headers: + fields: + - [ Host, example.com ] + + server-response: + status: 404 + reason: "Not Found" + headers: + fields: + - [ Content-Length, 8 ] + + proxy-response: + status: 404 + + # Request the same item again. It should not be cached and the request should + # be forwarded to the server. + - all: { headers: { fields: [[ uuid, 2 ]]}} + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/404 + headers: + fields: + - [ Host, example.com ] + + # Since 404 responses are customized to not be cached, this will go + # through. + <<: *200_response + + # Expect the server's 200 response. + proxy-response: + status: 200 + + # + # Test 2: Verify that a 400 response is cached since the custom + # negative_caching_list includes it. + # + - all: { headers: { fields: [[ uuid, 3 ]]}} + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/400 + headers: + fields: + - [ Host, example.com ] + + server-response: + status: 400 + reason: "Bad Request" + headers: + fields: + - [ Content-Length, 8 ] + + proxy-response: + status: 400 + + # Repeat the request and verify the response comes from the cache. + - all: { headers: { fields: [[ uuid, 4 ]]}} + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/400 + headers: + fields: + - [ Host, example.com ] + + # By customization, the 400 will be cached and this will not go through. + <<: *200_response + + # Expect the cached 400 response. + proxy-response: + status: 400 + + # + # Test 3: Verify that a 200 response is cached since it is a non-negative + # response. + # + - all: { headers: { fields: [[ uuid, 5 ]]}} + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/200 + headers: + fields: + - [ Host, example.com ] + + <<: *200_response + + proxy-response: + status: 200 + + - all: { headers: { fields: [[ uuid, 6 ]]}} + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/200 + headers: + fields: + - [ Host, example.com ] + + # This should not go to the server since the 200 response is cached. + server-response: + status: 400 + reason: "Bad Request" + headers: + fields: + - [ Content-Length, 8 ] + + # Expect the cached 200 response. + proxy-response: + status: 200 diff --git a/tests/gold_tests/cache/replay/negative-caching-default.replay.yaml b/tests/gold_tests/cache/replay/negative-caching-default.replay.yaml new file mode 100644 index 0000000..f06f30c --- /dev/null +++ b/tests/gold_tests/cache/replay/negative-caching-default.replay.yaml @@ -0,0 +1,206 @@ +# 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. + +# +# This replay file assumes a configuration with negative caching enabled with +# otherwise default conciguration. +# + +meta: + version: "1.0" + + blocks: + - 200_response: &200_response + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Content-Length, 16 ] + - [ Cache-Control, max-age=300 ] + +sessions: +- transactions: + + # + # Test 1: Verify that a 404 response is cached. + # + - all: { headers: { fields: [[ uuid, 1 ]]}} + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/404 + headers: + fields: + - [ Host, example.com ] + + server-response: + status: 404 + reason: "Not Found" + headers: + fields: + - [ Content-Length, 8 ] + + proxy-response: + status: 404 + + # Repeat the request and verify that it is served from the cache. + - all: { headers: { fields: [[ uuid, 2 ]]}} + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/404 + headers: + fields: + - [ Host, example.com ] + + # 404 responses should be cached when negative caching is enabled, so this + # should not get to the server. But if it does, return a 200 so the test + # knows that something went wrong. + <<: *200_response + + # Verify the cached 404 response is served. + proxy-response: + status: 404 + + # + # Test 2: Verify that a 400 response is not cached. + # + - all: { headers: { fields: [[ uuid, 3 ]]}} + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/400 + headers: + fields: + - [ Host, example.com ] + + server-response: + status: 400 + reason: "Bad Request" + headers: + fields: + - [ Content-Length, 8 ] + + proxy-response: + status: 400 + + # Repeat the request and verify that the request is forwarded to the server, + # not replied with any incorrectly cached response. + - all: { headers: { fields: [[ uuid, 4 ]]}} + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/400 + headers: + fields: + - [ Host, example.com ] + + # 400 responses should not be cached. Verify this goes to the server + # by returning and expecting a 200 response. + <<: *200_response + + # Verify that the origin's 200 response is served back. + proxy-response: + status: 200 + + # + # Test 3: Verify that a 200 response is cached. + # + - all: { headers: { fields: [[ uuid, 5 ]]}} + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/200 + headers: + fields: + - [ Host, example.com ] + + <<: *200_response + + proxy-response: + status: 200 + + - all: { headers: { fields: [[ uuid, 6 ]]}} + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/200 + headers: + fields: + - [ Host, example.com ] + + # This should not go to the server, but if it does return a 400 so we catch + # it. + server-response: + status: 400 + reason: "Bad Request" + headers: + fields: + - [ Content-Length, 8 ] + + # Verify that the cached 200 response is served. + proxy-response: + status: 200 + + # + # Test 4: Verify that a 405 response is not cached. + # + - all: { headers: { fields: [[ uuid, 7 ]]}} + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/405 + headers: + fields: + - [ Host, example.com ] + + server-response: + status: 405 + reason: "Method Not Allowed" + headers: + fields: + - [ Content-Length, 8 ] + + proxy-response: + status: 405 + + # Repeat the request and verify that the request is forwarded to the server, + # not replied with any incorrectly cached response. + - all: { headers: { fields: [[ uuid, 8 ]]}} + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/405 + headers: + fields: + - [ Host, example.com ] + + # 405 responses should not be cached. Verify this goes to the server + # by returning and expecting a 200 response. + <<: *200_response + + # Verify that the origin's 200 response is served back. + proxy-response: + status: 200 diff --git a/tests/gold_tests/cache/replay/negative-caching-disabled.replay.yaml b/tests/gold_tests/cache/replay/negative-caching-disabled.replay.yaml new file mode 100644 index 0000000..1ef338a --- /dev/null +++ b/tests/gold_tests/cache/replay/negative-caching-disabled.replay.yaml @@ -0,0 +1,201 @@ +# 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. + +# +# This replay file assumes a configuration without negative caching enabled. +# + +meta: + version: "1.0" + + blocks: + - request_for_path_200: &request_for_path_200 + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/200 + headers: + fields: + - [ Host, example.com ] + + - request_for_path_404: &request_for_path_404 + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/404 + headers: + fields: + - [ Host, example.com ] + + - request_for_no_cache_control_response: &request_for_no_cache_control_response + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/no_cache_control + headers: + fields: + - [ Host, example.com ] + + - request_for_404_with_cc: &request_for_404_with_cc + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/404_with_cc + headers: + fields: + - [ Host, example.com ] + +sessions: +- transactions: + + # + # Test 1: Verify that a 200 response is cached. + # + - all: { headers: { fields: [[ uuid, 1 ]]}} + <<: *request_for_path_200 + + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Content-Length, 16 ] + - [ Cache-Control, max-age=300 ] + + proxy-response: + status: 200 + + - all: { headers: { fields: [[ uuid, 2 ]]}} + <<: *request_for_path_200 + + # This should not go through to the server. Return a non-200 response to + # verify it is served from cache. + server-response: + status: 400 + reason: "Bad Request" + headers: + fields: + - [ Content-Length, 0 ] + + # Expect the cached 200 response. + proxy-response: + status: 200 + + # + # Test 2: Verify that a 404 response is not cached. + # + - all: { headers: { fields: [[ uuid, 3 ]]}} + <<: *request_for_path_404 + + server-response: + status: 404 + reason: "Not Found" + headers: + fields: + - [ Content-Length, 8 ] + + proxy-response: + status: 404 + + - all: { headers: { fields: [[ uuid, 4 ]]}} + <<: *request_for_path_404 + + # 404 responses should not be cached. Verify this goes to the server + # by returning and expecting a 200 response. + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Content-Length, 16 ] + - [ Cache-Control, max-age=300 ] + + # Expect the non-cached, origin server 200 response. + proxy-response: + status: 200 + + # + # Test 3: Verify that without Cache-Control, a 200 response is not cached. + # + - all: { headers: { fields: [[ uuid, 5 ]]}} + <<: *request_for_no_cache_control_response + + # Reply without a cache-control header. Should not be cached. + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Content-Length, 16 ] + + proxy-response: + status: 200 + + - all: { headers: { fields: [[ uuid, 6 ]]}} + <<: *request_for_no_cache_control_response + + # Expect this to go to the origin server since the previous 200 should not + # have been cached. + server-response: + status: 404 + reason: "Not Found" + headers: + fields: + - [ Content-Length, 8 ] + + # Since there was no Cache-Control, expect the non-cached, origin server + # 404 response. + proxy-response: + status: 404 + + # + # Test 4: Verify that a negative response is cached if it has a Cache-Control + # header. Such a header indicates that the server thinks this is OK to cache. + # + - all: { headers: { fields: [[ uuid, 7 ]]}} + <<: *request_for_404_with_cc + + # Reply with a negative response containing a Cache-Control header. + server-response: + status: 404 + reason: "Not Found" + headers: + fields: + - [ Content-Length, 16 ] + - [ Cache-Control, max-age=300 ] + + proxy-response: + status: 404 + + - all: { headers: { fields: [[ uuid, 8 ]]}} + <<: *request_for_404_with_cc + + # This should be served out of cache, therefore the origin server should + # not see this. + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Content-Length, 16 ] + + # Expect the cached 404 response. + proxy-response: + status: 404 diff --git a/tests/gold_tests/cache/replay/negative-caching-no-timeout.replay.yaml b/tests/gold_tests/cache/replay/negative-caching-no-timeout.replay.yaml new file mode 100644 index 0000000..6f15278 --- /dev/null +++ b/tests/gold_tests/cache/replay/negative-caching-no-timeout.replay.yaml @@ -0,0 +1,53 @@ +# 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. + +# +# Try a get request on /path/404_300_second_timeout and verify it is still in +# the cache. This is used to verify that the object was not aged out of the +# cache. +# + +meta: + version: "1.0" + +sessions: +- transactions: + + # + # Test 1: Verify that the 404 response is is still valid. + # + - all: { headers: { fields: [[ uuid, 23 ]]}} + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/404_300_second_timeout + headers: + fields: + - [ Host, example.com ] + + # This should not go to the server. Verify we get the cached 404 response + # instead of this new 403 response. + server-response: + status: 403 + reason: "Forbidden" + headers: + fields: + - [ Content-Length, 8 ] + + # Expect the cached 404 response. + proxy-response: + status: 404 diff --git a/tests/gold_tests/cache/replay/negative-caching-timeout.replay.yaml b/tests/gold_tests/cache/replay/negative-caching-timeout.replay.yaml new file mode 100644 index 0000000..02cf1e9 --- /dev/null +++ b/tests/gold_tests/cache/replay/negative-caching-timeout.replay.yaml @@ -0,0 +1,84 @@ +# 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. + +# +# Try a get request on /path/404 and verify it is not cached. This is used +# to verify that the object was aged out of the cache. +# + +meta: + version: "1.0" + + blocks: + - 403_response: &403_response + server-response: + status: 403 + reason: "Forbidden" + headers: + fields: + - [ Content-Length, 8 ] + + - 404_response: &404_response + server-response: + status: 404 + reason: "Not Found" + headers: + fields: + - [ Content-Length, 0 ] + +sessions: +- transactions: + + # + # Test 1: Verify that a 404 response is no longer in the cache. + # + - all: { headers: { fields: [[ uuid, 10 ]]}} + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/404 + headers: + fields: + - [ Host, example.com ] + + # This should go to the server. Verify we get a 403 response instead of the + # previously cached 404. + <<: *403_response + + # Expect the origin server 403, not the stale, cached 404. + proxy-response: + status: 403 + + # For good measure, verify that the new 403 response is cached. + - all: { headers: { fields: [[ uuid, 11 ]]}} + client-request: + method: "GET" + version: "1.1" + scheme: "http" + url: /path/404 + headers: + fields: + - [ Host, example.com ] + + # 403 responses should be cached when negative caching is enabled, so this + # should not get to the server. But if it does, return a 404 so the test + # knows that something went wrong. + <<: *404_response + + # Expect the cached 403 response. + proxy-response: + status: 403