This is an automated email from the ASF dual-hosted git repository.
bneradt 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 a2ea029215 Add percentage limit for stale cache age (#13547)
a2ea029215 is described below
commit a2ea029215f514577bb415712efb4a77050196cb
Author: Brian Neradt <[email protected]>
AuthorDate: Tue Aug 18 16:47:52 2026 -0500
Add percentage limit for stale cache age (#13547)
A fixed stale-age window can let short-lived cached responses remain
usable for many times their original freshness lifetime. This makes
serving stale content disproportionately risky for responses with a
short max-age.
This adds an optional percentage limit and applies the smaller of the
percentage-based and absolute stale-age windows. The default keeps the
existing behavior, while transaction overrides and supported scripting
interfaces can opt in per use case.
Fixes: #12252
---
doc/admin-guide/files/records.yaml.en.rst | 58 +++++++---
doc/admin-guide/plugins/lua.en.rst | 1 +
.../api/functions/TSHttpOverridableConfig.en.rst | 1 +
.../api/types/TSOverridableConfigKey.en.rst | 1 +
include/cripts/Configs.hpp | 1 +
include/proxy/http/HttpConfig.h | 1 +
include/proxy/http/OverridableConfigDefs.h | 3 +-
include/ts/apidefs.h.in | 1 +
src/proxy/http/HttpConfig.cc | 4 +-
src/proxy/http/HttpTransact.cc | 14 ++-
src/records/RecordsConfig.cc | 6 +-
tests/gold_tests/cache/proxy_serve_stale.test.py | 3 +
.../cache/replay/max_stale_age_percent.replay.yaml | 117 +++++++++++++++++++++
tests/gold_tests/records/gold/full_records.yaml | 1 +
.../records/legacy_config/full_records.config | 1 +
15 files changed, 195 insertions(+), 18 deletions(-)
diff --git a/doc/admin-guide/files/records.yaml.en.rst
b/doc/admin-guide/files/records.yaml.en.rst
index 25c4bec22e..f076dabbaf 100644
--- a/doc/admin-guide/files/records.yaml.en.rst
+++ b/doc/admin-guide/files/records.yaml.en.rst
@@ -2032,9 +2032,10 @@ Origin Server Connect Attempts
:overridable:
Specifies how long (in seconds) |TS| remembers that an origin server was
unreachable.
- During this window, if a stale cached response exists and its age is within
the cached response's ``max-age`` plus
- :ts:cv:`proxy.config.http.cache.max_stale_age`, |TS| serves the stale
content directly
- without attempting to contact the origin server.
+ During this window, if a stale cached response exists and its age is within
the limits configured by
+ :ts:cv:`proxy.config.http.cache.max_stale_age` and
+ :ts:cv:`proxy.config.http.cache.max_stale_age_percent`, |TS| serves the
stale content directly without attempting
+ to contact the origin server.
.. ts:cv:: CONFIG proxy.config.http.uncacheable_requests_bypass_parent INT 1
:reloadable:
@@ -2128,8 +2129,8 @@ Negative Response Caching
current stale content is preserved and served. Note this is considered only
on a revalidation of
already cached content. A revalidation failure means a connection failure
or a 50x response code.
When considering replying with a stale response in these negative
revalidating circumstances,
- |TS| will respect the :ts:cv:`proxy.config.http.cache.max_stale_age`
configuration and will not
- use a cached response older than ``max_stale_age`` seconds plus ``max-age``
of cached content.
+ |TS| will respect the :ts:cv:`proxy.config.http.cache.max_stale_age` and
+ :ts:cv:`proxy.config.http.cache.max_stale_age_percent` limits.
A value of ``0`` disables serving stale content and a value of ``1``
enables keeping and serving stale content if revalidation fails.
@@ -2155,7 +2156,8 @@ Negative Response Caching
behavior with regard to whether it considers a stale object to be fresh
enough to serve out of
cache when revalidation fails. As mentioned above in
:ts:cv:`proxy.config.http.negative_revalidating_enabled`,
- :ts:cv:`proxy.config.http.cache.max_stale_age` is used for that
determination.
+ :ts:cv:`proxy.config.http.cache.max_stale_age` and
+ :ts:cv:`proxy.config.http.cache.max_stale_age_percent` are used for that
determination.
This configuration defaults to 1,800 seconds (30 minutes).
@@ -2654,7 +2656,35 @@ Cache Control
:reloadable:
:overridable:
- The maximum age in seconds allowed for a stale response before it cannot be
cached.
+ The maximum number of seconds that a stale response can be served after its
``max-age`` freshness
+ lifetime has passed.
+
+ When :ts:cv:`proxy.config.http.cache.max_stale_age_percent` is enabled, the
smaller of the
+ absolute and percentage limits is used.
+
+.. ts:cv:: CONFIG proxy.config.http.cache.max_stale_age_percent INT 0
+ :reloadable:
+ :overridable:
+
+ Limits the stale response lifetime to a percentage of its ``max-age``
freshness lifetime. The
+ valid range is ``0`` to ``100``. A value of ``0`` disables the percentage
limit. When enabled,
+ |TS| uses the smaller of this limit and
+ :ts:cv:`proxy.config.http.cache.max_stale_age`.
+
+ For example, a value of ``25`` allows a response with a one-hour freshness
lifetime
+ (``Cache-Control: max-age=3600``) to be served stale for up to 15 minutes
(25% of one hour),
+ provided that the absolute stale age limit is at least 15 minutes.
+
+ Percentage limits are calculated in whole seconds and rounded down. If the
calculated limit is
+ less than one second, no stale window is allowed. For example, a value of
``1`` with
+ ``Cache-Control: max-age=99`` produces a zero-second stale window.
+
+ A value of ``0`` applies no percentage limit. For example, with the default
+ :ts:cv:`proxy.config.http.cache.max_stale_age` of seven days, a response
with a one-hour
+ freshness lifetime can be served stale for up to seven days after that
freshness lifetime ends.
+
+ Responses without ``max-age`` are controlled by
:ts:cv:`proxy.config.http.cache.max_stale_age`
+ alone.
.. ts:cv:: CONFIG proxy.config.http.cache.guaranteed_min_lifetime INT 0
:reloadable:
@@ -3241,13 +3271,15 @@ Dynamic Content & Content Negotiation
===== ======================================================================
``0`` Default. Disable cache and go to origin server.
``1`` Return a ``502`` error on a cache miss.
- ``2`` Serve stale if object's age is under ``max-age`` +
- :ts:cv:`proxy.config.http.cache.max_stale_age`. Otherwise, go to
- origin server.
+ ``2`` Serve stale if the object's age is within the
+ :ts:cv:`proxy.config.http.cache.max_stale_age` and
+ :ts:cv:`proxy.config.http.cache.max_stale_age_percent` limits.
+ Otherwise, go to the origin server.
``3`` Return a ``502`` error on a cache miss or serve stale on a cache
- revalidate if object's age is under ``max-age`` +
- :ts:cv:`proxy.config.http.cache.max_stale_age`. Otherwise, go to
- origin server.
+ revalidate if the object's age is within the
+ :ts:cv:`proxy.config.http.cache.max_stale_age` and
+ :ts:cv:`proxy.config.http.cache.max_stale_age_percent` limits.
+ Otherwise, go to the origin server.
``4`` Return a ``502`` error on either a cache miss or on a revalidation.
``5`` Retry Cache Read on a Cache Write Lock failure. This option together
with :ts:cv:`proxy.config.cache.enable_read_while_writer`
configuration
diff --git a/doc/admin-guide/plugins/lua.en.rst
b/doc/admin-guide/plugins/lua.en.rst
index c5e7f784ce..0716e89c11 100644
--- a/doc/admin-guide/plugins/lua.en.rst
+++ b/doc/admin-guide/plugins/lua.en.rst
@@ -4822,6 +4822,7 @@ Http config constants
TS_LUA_CONFIG_BODY_FACTORY_RESPONSE_SUPPRESSION_MODE
TS_LUA_CONFIG_HTTP_CACHE_POST_METHOD
TS_LUA_CONFIG_HTTP_CACHE_TARGETED_CACHE_CONTROL_HEADERS
+ TS_LUA_CONFIG_HTTP_CACHE_MAX_STALE_AGE_PERCENT
TS_LUA_CONFIG_LAST_ENTRY
:ref:`TOP <admin-plugins-ts-lua>`
diff --git a/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst
b/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst
index 43d98b40ad..19e992d259 100644
--- a/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst
+++ b/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst
@@ -199,6 +199,7 @@ TSOverridableConfigKey Value
Confi
:enumerator:`TS_CONFIG_BODY_FACTORY_RESPONSE_SUPPRESSION_MODE`
:ts:cv:`proxy.config.body_factory.response_suppression_mode`
:enumerator:`TS_CONFIG_HTTP_CACHE_POST_METHOD`
:ts:cv:`proxy.config.http.cache.post_method`
:enumerator:`TS_CONFIG_HTTP_CACHE_TARGETED_CACHE_CONTROL_HEADERS`
:ts:cv:`proxy.config.http.cache.targeted_cache_control_headers`
+:enumerator:`TS_CONFIG_HTTP_CACHE_MAX_STALE_AGE_PERCENT`
:ts:cv:`proxy.config.http.cache.max_stale_age_percent`
========================================================================
====================================================================
Examples
diff --git a/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst
b/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst
index 4ce7c1712d..d9ae419c29 100644
--- a/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst
+++ b/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst
@@ -166,6 +166,7 @@ Enumeration Members
.. enumerator:: TS_CONFIG_HTTP_CACHE_IGNORE_QUERY
.. enumerator:: TS_CONFIG_HTTP_CACHE_POST_METHOD
.. enumerator:: TS_CONFIG_HTTP_CACHE_TARGETED_CACHE_CONTROL_HEADERS
+.. enumerator:: TS_CONFIG_HTTP_CACHE_MAX_STALE_AGE_PERCENT
Description
diff --git a/include/cripts/Configs.hpp b/include/cripts/Configs.hpp
index 79460327e7..013f84a9d9 100644
--- a/include/cripts/Configs.hpp
+++ b/include/cripts/Configs.hpp
@@ -101,6 +101,7 @@ private:
cripts::IntConfig
max_open_write_retries{"proxy.config.http.cache.max_open_write_retries"};
cripts::IntConfig
max_open_write_retry_timeout{"proxy.config.http.cache.max_open_write_retry_timeout"};
cripts::IntConfig
max_stale_age{"proxy.config.http.cache.max_stale_age"};
+ cripts::IntConfig
max_stale_age_percent{"proxy.config.http.cache.max_stale_age_percent"};
cripts::IntConfig
open_read_retry_time{"proxy.config.http.cache.open_read_retry_time"};
cripts::IntConfig
open_write_fail_action{"proxy.config.http.cache.open_write_fail_action"};
diff --git a/include/proxy/http/HttpConfig.h b/include/proxy/http/HttpConfig.h
index 5bf58f7d7d..887ac1cb64 100644
--- a/include/proxy/http/HttpConfig.h
+++ b/include/proxy/http/HttpConfig.h
@@ -705,6 +705,7 @@ struct OverridableHttpConfigParams {
MgmtInt cache_guaranteed_min_lifetime = 0;
MgmtInt cache_guaranteed_max_lifetime = 31536000;
MgmtInt cache_max_stale_age = 604800;
+ MgmtInt cache_max_stale_age_percent = 0;
///////////////////////////////////////////////////
// connection variables. timeouts are in seconds //
diff --git a/include/proxy/http/OverridableConfigDefs.h
b/include/proxy/http/OverridableConfigDefs.h
index bf00fc3def..864461b1c8 100644
--- a/include/proxy/http/OverridableConfigDefs.h
+++ b/include/proxy/http/OverridableConfigDefs.h
@@ -252,6 +252,7 @@
X(HTTP_NEGATIVE_REVALIDATING_LIST,
negative_revalidating_list,
"proxy.config.http.negative_revalidating_list", STRING,
HttpStatusCodeList_Conv) \
X(HTTP_CACHE_POST_METHOD, cache_post_method,
"proxy.config.http.cache.post_method",
INT, GENERIC) \
X(HTTP_CACHE_TARGETED_CACHE_CONTROL_HEADERS,
targeted_cache_control_headers,
"proxy.config.http.cache.targeted_cache_control_headers", STRING,
TargetedCacheControlHeaders_Conv) \
- X(SSL_CLIENT_CA_CERT_PATH, ssl_client_ca_cert_path,
"proxy.config.ssl.client.CA.cert.path",
STRING, NONE)
+ X(SSL_CLIENT_CA_CERT_PATH, ssl_client_ca_cert_path,
"proxy.config.ssl.client.CA.cert.path",
STRING, NONE) \
+ X(HTTP_CACHE_MAX_STALE_AGE_PERCENT,
cache_max_stale_age_percent,
"proxy.config.http.cache.max_stale_age_percent", INT,
GENERIC)
// clang-format on
diff --git a/include/ts/apidefs.h.in b/include/ts/apidefs.h.in
index f34ffdb1a3..8e110942b0 100644
--- a/include/ts/apidefs.h.in
+++ b/include/ts/apidefs.h.in
@@ -918,6 +918,7 @@ enum TSOverridableConfigKey {
TS_CONFIG_HTTP_CACHE_POST_METHOD,
TS_CONFIG_HTTP_CACHE_TARGETED_CACHE_CONTROL_HEADERS,
TS_CONFIG_SSL_CLIENT_CA_CERT_PATH,
+ TS_CONFIG_HTTP_CACHE_MAX_STALE_AGE_PERCENT,
TS_CONFIG_LAST_ENTRY,
};
diff --git a/src/proxy/http/HttpConfig.cc b/src/proxy/http/HttpConfig.cc
index f0b1b535c3..08a3ed2363 100644
--- a/src/proxy/http/HttpConfig.cc
+++ b/src/proxy/http/HttpConfig.cc
@@ -1109,6 +1109,7 @@ HttpConfig::startup()
HttpEstablishStaticConfigLongLong(c.oride.cache_guaranteed_max_lifetime,
"proxy.config.http.cache.guaranteed_max_lifetime");
HttpEstablishStaticConfigLongLong(c.oride.cache_max_stale_age,
"proxy.config.http.cache.max_stale_age");
+ HttpEstablishStaticConfigLongLong(c.oride.cache_max_stale_age_percent,
"proxy.config.http.cache.max_stale_age_percent");
HttpEstablishStaticConfigByte(c.oride.srv_enabled,
"proxy.config.srv_enabled");
@@ -1456,7 +1457,8 @@ HttpConfig::reconfigure()
params->oride.cache_guaranteed_min_lifetime =
m_master.oride.cache_guaranteed_min_lifetime;
params->oride.cache_guaranteed_max_lifetime =
m_master.oride.cache_guaranteed_max_lifetime;
- params->oride.cache_max_stale_age = m_master.oride.cache_max_stale_age;
+ params->oride.cache_max_stale_age =
m_master.oride.cache_max_stale_age;
+ params->oride.cache_max_stale_age_percent =
m_master.oride.cache_max_stale_age_percent;
params->oride.srv_enabled = m_master.oride.srv_enabled;
diff --git a/src/proxy/http/HttpTransact.cc b/src/proxy/http/HttpTransact.cc
index 79e9fc5fa2..e638ed14a4 100644
--- a/src/proxy/http/HttpTransact.cc
+++ b/src/proxy/http/HttpTransact.cc
@@ -6396,8 +6396,20 @@ HttpTransact::is_stale_cache_response_returnable(State
*s)
time_t current_age =
HttpTransactCache::calculate_document_age(s->cache_info.object_read->request_sent_time_get(),
s->cache_info.object_read->response_received_time_get(),
cached_response, cached_response->get_date(), s->current.now);
+
+ MgmtInt max_age = get_max_age(cached_response);
+ MgmtInt max_stale_age = s->txn_conf->cache_max_stale_age;
+ MgmtInt max_stale_percentage =
+ std::clamp(s->txn_conf->cache_max_stale_age_percent,
static_cast<MgmtInt>(0), static_cast<MgmtInt>(100));
+
+ if (max_stale_percentage > 0 && max_age >= 0) {
+ MgmtInt percent_max_stale_age = max_age * max_stale_percentage / 100;
+
+ max_stale_age = std::min(max_stale_age, percent_max_stale_age);
+ }
+
// Negative age is overflow
- if ((current_age < 0) || (current_age > s->txn_conf->cache_max_stale_age +
get_max_age(cached_response))) {
+ if ((current_age < 0) || (current_age > max_age + max_stale_age)) {
TxnDbg(dbg_ctl_http_trans, "document age is too large %" PRId64,
(int64_t)current_age);
return false;
}
diff --git a/src/records/RecordsConfig.cc b/src/records/RecordsConfig.cc
index f011c0ccd7..1eec9cce82 100644
--- a/src/records/RecordsConfig.cc
+++ b/src/records/RecordsConfig.cc
@@ -633,8 +633,8 @@ static constexpr RecordElement RecordsConfig[] =
// #
// # 0 - default. disable cache and goto origin
// # 1 - return error if cache miss
- // # 2 - serve stale until proxy.config.http.cache.max_stale_age,
then goto origin, if revalidate
- // # 3 - return error if cache miss or serve stale until
proxy.config.http.cache.max_stale_age, then goto origin, if revalidate
+ // # 2 - serve stale within the configured stale age limits, then
goto origin, if revalidate
+ // # 3 - return error if cache miss or serve stale within the
configured stale age limits, then goto origin, if revalidate
// # 4 - return error if cache miss or if revalidate
// # 5 - retry cache read (read-while-writer) on write lock failure,
goto origin if retries exhausted
// # 6 - retry cache read on write lock failure, if retries exhausted
serve stale if allowed, otherwise goto origin
@@ -660,6 +660,8 @@ static constexpr RecordElement RecordsConfig[] =
,
{RECT_CONFIG, "proxy.config.http.cache.max_stale_age", RECD_INT, "604800",
RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL}
,
+ {RECT_CONFIG, "proxy.config.http.cache.max_stale_age_percent", RECD_INT,
"0", RECU_DYNAMIC, RR_NULL, RECC_INT, "[0-100]", RECA_NULL}
+ ,
{RECT_CONFIG, "proxy.config.http.cache.range.lookup", RECD_INT, "1",
RECU_NULL, RR_NULL, RECC_NULL, nullptr, RECA_NULL}
,
{RECT_CONFIG, "proxy.config.http.cache.range.write", RECD_INT, "0",
RECU_NULL, RR_NULL, RECC_NULL, nullptr, RECA_NULL}
diff --git a/tests/gold_tests/cache/proxy_serve_stale.test.py
b/tests/gold_tests/cache/proxy_serve_stale.test.py
index 95e620a204..3ff64c7af3 100644
--- a/tests/gold_tests/cache/proxy_serve_stale.test.py
+++ b/tests/gold_tests/cache/proxy_serve_stale.test.py
@@ -23,5 +23,8 @@ Test.ContinueOnFail = True
# Verify that stale content is served when the parent is down.
Test.ATSReplayTest(replay_file="replay/proxy_serve_stale.replay.yaml")
+# Verify that stale content respects the percentage maximum stale age.
+Test.ATSReplayTest(replay_file="replay/max_stale_age_percent.replay.yaml")
+
# Verify that stale content is served when the origin server is down.
Test.ATSReplayTest(replay_file="replay/proxy_serve_stale_origin_down.replay.yaml")
diff --git a/tests/gold_tests/cache/replay/max_stale_age_percent.replay.yaml
b/tests/gold_tests/cache/replay/max_stale_age_percent.replay.yaml
new file mode 100644
index 0000000000..f2f0174018
--- /dev/null
+++ b/tests/gold_tests/cache/replay/max_stale_age_percent.replay.yaml
@@ -0,0 +1,117 @@
+# 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"
+
+ blocks:
+
+ - origin_response: &origin_response
+ server-response:
+ status: 500
+ reason: "Internal Server Error"
+ headers:
+ fields:
+ - [ Content-Length, 16 ]
+ - [ X-Response, should_not_see ]
+
+autest:
+ description: 'Verify the percentage maximum stale age limit'
+
+ dns:
+ name: 'dns-max-stale-age-percent'
+
+ server:
+ name: 'server-max-stale-age-percent'
+
+ client:
+ name: 'client-max-stale-age-percent'
+
+ ats:
+ name: 'ts-max-stale-age-percent'
+ process_config:
+ enable_cache: true
+
+ records_config:
+ proxy.config.http.push_method_enabled: 1
+ proxy.config.http.parent_proxy.fail_threshold: 1
+ proxy.config.http.parent_proxy.total_connect_attempts: 1
+ proxy.config.http.cache.max_stale_age: 100
+ proxy.config.http.cache.max_stale_age_percent: 50
+ proxy.config.http.parent_proxy.self_detect: 0
+
+ parent_config:
+ - 'dest_domain=. parent="localhost:82" round_robin=consistent_hash
go_direct=false'
+
+ remap_config:
+ - from: "http://example.com/"
+ to: "http://localhost:{SERVER_HTTP_PORT}/"
+
+sessions:
+- transactions:
+
+ # Populate the cache with a four-second freshness lifetime.
+ - client-request:
+ method: "PUSH"
+ version: "1.1"
+ url: /percentage
+ headers:
+ fields:
+ - [ Host, example.com ]
+ - [ uuid, push ]
+ - [ Content-Length, 73 ]
+ content:
+ encoding: plain
+ data: "HTTP/1.1 200 OK\nContent-Length: 6\nCache-Control:
public,max-age=4\n\nCACHED"
+
+ <<: *origin_response
+
+ proxy-response:
+ status: 201
+
+ # At five seconds old, the object is stale but remains within the two-second
+ # percentage stale window.
+ - client-request:
+ delay: 5s
+ method: "GET"
+ version: "1.1"
+ url: /percentage
+ headers:
+ fields:
+ - [ Host, example.com ]
+ - [ uuid, within_percentage_limit ]
+
+ <<: *origin_response
+
+ proxy-response:
+ status: 200
+
+ # At eight seconds old, the object exceeds max-age (4 seconds) plus 50%
+ # (2 seconds), even though the absolute stale age limit is 100 seconds.
+ - client-request:
+ delay: 3s
+ method: "GET"
+ version: "1.1"
+ url: /percentage
+ headers:
+ fields:
+ - [ Host, example.com ]
+ - [ uuid, past_percentage_limit ]
+
+ <<: *origin_response
+
+ proxy-response:
+ status: 502
diff --git a/tests/gold_tests/records/gold/full_records.yaml
b/tests/gold_tests/records/gold/full_records.yaml
index 1123e2cbb1..d1502ce4b8 100644
--- a/tests/gold_tests/records/gold/full_records.yaml
+++ b/tests/gold_tests/records/gold/full_records.yaml
@@ -163,6 +163,7 @@ records:
max_open_read_retries: -1
max_open_write_retries: 1
max_stale_age: 604800
+ max_stale_age_percent: 0
open_read_retry_time: 10
open_write_fail_action: 0
post_method: 0
diff --git a/tests/gold_tests/records/legacy_config/full_records.config
b/tests/gold_tests/records/legacy_config/full_records.config
index d7b640dae3..128ce0c862 100644
--- a/tests/gold_tests/records/legacy_config/full_records.config
+++ b/tests/gold_tests/records/legacy_config/full_records.config
@@ -183,6 +183,7 @@ CONFIG proxy.config.http.cache.open_write_fail_action INT 0
CONFIG proxy.config.http.cache.when_to_revalidate INT 0
CONFIG proxy.config.http.cache.required_headers INT 2
CONFIG proxy.config.http.cache.max_stale_age INT 604800
+CONFIG proxy.config.http.cache.max_stale_age_percent INT 0
CONFIG proxy.config.http.cache.range.lookup INT 1
CONFIG proxy.config.http.cache.range.write INT 0
CONFIG proxy.config.http.cache.heuristic_min_lifetime INT 3600