From e6e492d93022192b4473507062b95c6d84bcebd0 Mon Sep 17 00:00:00 2001 From: Serris Lew Date: Mon, 1 Nov 2021 12:32:48 -0700 Subject: [PATCH 1/2] serve stale when dns lookups fails --- proxy/http/HttpTransact.cc | 18 ++--- .../gold/serve_stale_dns_fail.gold | 57 +++++++++++++ .../proxy_serve_stale_dns_fail.test.py | 79 +++++++++++++++++++ 3 files changed, 144 insertions(+), 10 deletions(-) create mode 100644 tests/gold_tests/proxy_protocol/gold/serve_stale_dns_fail.gold create mode 100644 tests/gold_tests/proxy_protocol/proxy_serve_stale_dns_fail.test.py diff --git a/proxy/http/HttpTransact.cc b/proxy/http/HttpTransact.cc index 90d642dec5d..2ccfd47b32c 100644 --- a/proxy/http/HttpTransact.cc +++ b/proxy/http/HttpTransact.cc @@ -1969,6 +1969,13 @@ HttpTransact::OSDNSLookup(State *s) } else { TxnDebug("http_seq", "[HttpTransact::OSDNSLookup] DNS Lookup unsuccessful"); + // Even with unsuccessful DNS lookup, return stale object from cache if applicable + if (is_cache_hit(s->cache_lookup_result) && is_stale_cache_response_returnable(s)) { + s->source = SOURCE_CACHE; + TxnDebug("http_trans", "[hscno] serving stale doc to client"); + build_response_from_cache(s, HTTP_WARNING_CODE_REVALIDATION_FAILED); + return; + } // output the DNS failure error message SET_VIA_STRING(VIA_DETAIL_TUNNEL, VIA_DETAIL_TUNNEL_NO_FORWARD); // Set to internal server error so later logging will pick up SQUID_LOG_ERR_DNS_FAIL @@ -2669,16 +2676,7 @@ HttpTransact::HandleCacheOpenReadHitFreshness(State *s) SET_VIA_STRING(VIA_CACHE_RESULT, VIA_IN_CACHE_STALE); } - if (!s->force_dns) { // If DNS is not performed before - if (need_to_revalidate(s)) { - TRANSACT_RETURN(SM_ACTION_API_CACHE_LOOKUP_COMPLETE, - CallOSDNSLookup); // content needs to be revalidated and we did not perform a dns ....calling DNS lookup - } else { // document can be served can cache - TRANSACT_RETURN(SM_ACTION_API_CACHE_LOOKUP_COMPLETE, HttpTransact::HandleCacheOpenReadHit); - } - } else { // we have done dns . Its up to HandleCacheOpenReadHit to decide to go OS or serve from cache - TRANSACT_RETURN(SM_ACTION_API_CACHE_LOOKUP_COMPLETE, HttpTransact::HandleCacheOpenReadHit); - } + TRANSACT_RETURN(SM_ACTION_API_CACHE_LOOKUP_COMPLETE, HttpTransact::HandleCacheOpenReadHit); } /////////////////////////////////////////////////////////////////////////////// diff --git a/tests/gold_tests/proxy_protocol/gold/serve_stale_dns_fail.gold b/tests/gold_tests/proxy_protocol/gold/serve_stale_dns_fail.gold new file mode 100644 index 00000000000..77271e28e45 --- /dev/null +++ b/tests/gold_tests/proxy_protocol/gold/serve_stale_dns_fail.gold @@ -0,0 +1,57 @@ +`` +> GET / HTTP/1.1 +> Host: `` +> User-Agent: curl/`` +> Accept: */* +`` +< HTTP/1.1 200 OK +< Server: ATS`` +< Accept-Ranges: bytes +< Content-Length: 6 +< Cache-Control: public, max-age=5 +< Expires: `` +< Age: `` +< Date: `` +< Connection: keep-alive +`` +> GET / HTTP/1.1 +> Host: `` +> User-Agent: curl/`` +> Accept: */* +`` +< HTTP/1.1 500 Cannot find server. +< Date: `` +< Server: ATS`` +< Cache-Control: no-store +< Content-Type: `` +< Content-Language: `` +< Content-Length: `` +< Connection: keep-alive +`` +> GET / HTTP/1.1 +> Host: `` +> User-Agent: curl/`` +> Accept: */* +`` +< HTTP/1.1 200 OK +< Server: ATS`` +< Accept-Ranges: bytes +< Content-Length: 6 +< Cache-Control: public, max-age=5 +< Age: `` +< Date: `` +< Connection: keep-alive +`` +> GET / HTTP/1.1 +> Host: `` +> User-Agent: curl/`` +> Accept: */* +`` +< HTTP/1.1 500 Cannot find server. +< Date: `` +< Server: ATS`` +< Cache-Control: no-store +< Content-Type: `` +< Content-Language: `` +< Content-Length: `` +`` \ No newline at end of file diff --git a/tests/gold_tests/proxy_protocol/proxy_serve_stale_dns_fail.test.py b/tests/gold_tests/proxy_protocol/proxy_serve_stale_dns_fail.test.py new file mode 100644 index 00000000000..2e647a31663 --- /dev/null +++ b/tests/gold_tests/proxy_protocol/proxy_serve_stale_dns_fail.test.py @@ -0,0 +1,79 @@ +''' +Test proxy serving stale content when DNS lookup fails +''' +# 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.ContinueOnFail = True +# Set up hierarchical caching processes +ts_child = Test.MakeATSProcess("ts_child") +ts_parent = Test.MakeATSProcess("ts_parent") +server_name = "http://unknown.domain.com/" + +Test.testName = "STALE" + +# Config child proxy to route to parent proxy +ts_child.Disk.records_config.update({ + 'proxy.config.url_remap.pristine_host_hdr': 1, + 'proxy.config.http.cache.max_stale_age': 30, + 'proxy.config.http.parent_proxy.self_detect': 0, +}) +ts_child.Disk.parent_config.AddLine( + f'dest_domain=. parent=localhost:{ts_parent.Variables.port} round_robin=consistent_hash go_direct=false' +) +ts_child.Disk.remap_config.AddLine( + f'map http://localhost:{ts_child.Variables.port} {server_name}' +) + +# Configure parent proxy +ts_parent.Disk.records_config.update({ + 'proxy.config.url_remap.pristine_host_hdr': 1, + 'proxy.config.http.cache.max_stale_age': 30, +}) +ts_parent.Disk.remap_config.AddLine( + f'map http://localhost:{ts_parent.Variables.port} {server_name}' +) +ts_parent.Disk.remap_config.AddLine( + f'map {server_name} {server_name}' +) + +# Object to push to proxies +stale_5 = "HTTP/1.1 200 OK\nServer: ATS/10.0.0\nAccept-Ranges: bytes\nContent-Length: 6\nCache-Control: public, max-age=5\n\nCACHED" +stale_30 = "HTTP/1.1 200 OK\nServer: ATS/10.0.0\nAccept-Ranges: bytes\nContent-Length: 6\nCache-Control: public, max-age=30\n\nCACHED" + + +# Testing scenarios +child_curl_request = ( + # Test child serving stale with failed DNS OS lookup + f'curl -X PUSH -d "{stale_5}" "http://localhost:{ts_child.Variables.port}";' + f'curl -X PUSH -d "{stale_30}" "http://localhost:{ts_parent.Variables.port}";' + f'sleep 10; curl -s -v http://localhost:{ts_child.Variables.port};' + f'sleep 40; curl -s -v http://localhost:{ts_child.Variables.port};' + # Test parent serving stale with failed DNS OS lookup + f'curl -X PUSH -d "{stale_5}" "http://localhost:{ts_parent.Variables.port}";' + f'sleep 10; curl -s -v http://localhost:{ts_parent.Variables.port};' + f'sleep 40; curl -s -v http://localhost:{ts_parent.Variables.port};' +) + +# Test case for when parent server is down but child proxy can serve cache object +tr = Test.AddTestRun() +tr.Processes.Default.Command = child_curl_request +tr.Processes.Default.ReturnCode = 0 +tr.Processes.Default.StartBefore(ts_child) +tr.Processes.Default.StartBefore(ts_parent) +tr.Processes.Default.Streams.stderr = "gold/serve_stale_dns_fail.gold" +tr.StillRunningAfter = ts_child +tr.StillRunningAfter = ts_parent From 407c5cb1ecfd9f0f9b4ce46490309994205b3fc4 Mon Sep 17 00:00:00 2001 From: Serris Lew Date: Tue, 7 Dec 2021 16:38:13 -0800 Subject: [PATCH 2/2] updated max-age in autest to run shorter --- .../proxy_serve_stale_dns_fail.test.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/gold_tests/proxy_protocol/proxy_serve_stale_dns_fail.test.py b/tests/gold_tests/proxy_protocol/proxy_serve_stale_dns_fail.test.py index 2e647a31663..4334dd5c788 100644 --- a/tests/gold_tests/proxy_protocol/proxy_serve_stale_dns_fail.test.py +++ b/tests/gold_tests/proxy_protocol/proxy_serve_stale_dns_fail.test.py @@ -28,7 +28,7 @@ # Config child proxy to route to parent proxy ts_child.Disk.records_config.update({ 'proxy.config.url_remap.pristine_host_hdr': 1, - 'proxy.config.http.cache.max_stale_age': 30, + 'proxy.config.http.cache.max_stale_age': 10, 'proxy.config.http.parent_proxy.self_detect': 0, }) ts_child.Disk.parent_config.AddLine( @@ -41,7 +41,7 @@ # Configure parent proxy ts_parent.Disk.records_config.update({ 'proxy.config.url_remap.pristine_host_hdr': 1, - 'proxy.config.http.cache.max_stale_age': 30, + 'proxy.config.http.cache.max_stale_age': 10, }) ts_parent.Disk.remap_config.AddLine( f'map http://localhost:{ts_parent.Variables.port} {server_name}' @@ -52,20 +52,20 @@ # Object to push to proxies stale_5 = "HTTP/1.1 200 OK\nServer: ATS/10.0.0\nAccept-Ranges: bytes\nContent-Length: 6\nCache-Control: public, max-age=5\n\nCACHED" -stale_30 = "HTTP/1.1 200 OK\nServer: ATS/10.0.0\nAccept-Ranges: bytes\nContent-Length: 6\nCache-Control: public, max-age=30\n\nCACHED" +stale_10 = "HTTP/1.1 200 OK\nServer: ATS/10.0.0\nAccept-Ranges: bytes\nContent-Length: 6\nCache-Control: public, max-age=10\n\nCACHED" # Testing scenarios child_curl_request = ( # Test child serving stale with failed DNS OS lookup f'curl -X PUSH -d "{stale_5}" "http://localhost:{ts_child.Variables.port}";' - f'curl -X PUSH -d "{stale_30}" "http://localhost:{ts_parent.Variables.port}";' - f'sleep 10; curl -s -v http://localhost:{ts_child.Variables.port};' - f'sleep 40; curl -s -v http://localhost:{ts_child.Variables.port};' + f'curl -X PUSH -d "{stale_10}" "http://localhost:{ts_parent.Variables.port}";' + f'sleep 7; curl -s -v http://localhost:{ts_child.Variables.port};' + f'sleep 15; curl -s -v http://localhost:{ts_child.Variables.port};' # Test parent serving stale with failed DNS OS lookup f'curl -X PUSH -d "{stale_5}" "http://localhost:{ts_parent.Variables.port}";' - f'sleep 10; curl -s -v http://localhost:{ts_parent.Variables.port};' - f'sleep 40; curl -s -v http://localhost:{ts_parent.Variables.port};' + f'sleep 7; curl -s -v http://localhost:{ts_parent.Variables.port};' + f'sleep 15; curl -s -v http://localhost:{ts_parent.Variables.port};' ) # Test case for when parent server is down but child proxy can serve cache object