You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by bc...@apache.org on 2020/11/30 18:45:59 UTC
[trafficserver] branch master updated: Add negative caching tests
and fixes. (#7361)
This is an automated email from the ASF dual-hosted git repository.
bcall 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 8eb6826 Add negative caching tests and fixes. (#7361)
8eb6826 is described below
commit 8eb68266167d8f8b3fa3a00ca9f6b7889e8ec101
Author: Brian Neradt <br...@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.
---
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 a7f2538..d9d0025 100644
--- a/doc/admin-guide/files/records.config.en.rst
+++ b/doc/admin-guide/files/records.config.en.rst
@@ -1664,11 +1664,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
@@ -1686,7 +1684,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 7227bbf..639c2af 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 41a98e3..3950f32 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 af647d3..65b1efb 100644
--- a/proxy/http/HttpConfig.cc
+++ b/proxy/http/HttpConfig.cc
@@ -1038,7 +1038,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 becafac..6991b95 100644
--- a/proxy/http/HttpSM.cc
+++ b/proxy/http/HttpSM.cc
@@ -3055,7 +3055,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)
@@ -3111,8 +3111,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
@@ -6736,7 +6736,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 6a1585a..6256d5c 100644
--- a/proxy/http/HttpTransact.cc
+++ b/proxy/http/HttpTransact.cc
@@ -4402,7 +4402,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
@@ -4437,7 +4437,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;
@@ -4464,7 +4464,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);
@@ -4500,8 +4500,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;
@@ -4911,7 +4911,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);
}
@@ -6296,24 +6296,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 980d105..88ee1e2 100644
--- a/proxy/http/HttpTransact.h
+++ b/proxy/http/HttpTransact.h
@@ -738,8 +738,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