MEDIUM: cache: Add "Origin" header to secondary cache key

This patch add a hash of the Origin header to the cache's secondary key.
This enables to manage store responses that have a "Vary: Origin" header
in the cache when vary is enabled.
This cannot be considered as a means to manage CORS requests though, it
only processes the Origin header and hashes the presented value without
any form of URI normalization.

This need was expressed by Philipp Hossner in GitHub issue #251.

Co-Authored-by: Philipp Hossner <philipp.hossner@posteo.de>
This commit is contained in:
Remi Tricot-Le Breton 2023-10-03 14:33:41 +02:00 committed by William Lallemand
parent 544e320f80
commit a5e96425a2
4 changed files with 60 additions and 5 deletions

View File

@ -17178,7 +17178,7 @@ The cache won't store and won't deliver objects in these cases:
- If the response is not a 200
- If the response contains a Vary header and either the process-vary option is
disabled, or a currently unmanaged header is specified in the Vary value (only
accept-encoding and referer are managed for now)
accept-encoding, referer and origin are managed for now)
- If the Content-Length + the headers size is greater than "max-object-size"
- If the response is not cacheable
- If the response does not have an explicit expiration time (s-maxage or max-age
@ -17229,8 +17229,10 @@ process-vary <on/off>
Enable or disable the processing of the Vary header. When disabled, a response
containing such a header will never be cached. When enabled, we need to calculate
a preliminary hash for a subset of request headers on all the incoming requests
(which might come with a cpu cost) which will be used to build a secondary key
for a given request (see RFC 7234#4.1). The default value is off (disabled).
(which might come with a cpu cost) which will be used to build a secondary
key for a given request (see RFC 7234#4.1). The secondary key is built out of
the contents of the 'accept-encoding', 'referer' and 'origin' headers for
now. The default value is off (disabled).
max-secondary-entries <number>
Define the maximum number of simultaneous secondary entries with the same primary

View File

@ -157,7 +157,7 @@ static forceinline char *hmsg_show_flags(char *buf, size_t len, const char *deli
* request/response pairs, because they depend on the responses' optional Vary
* header. The different sizes can be found in the vary_information object (see
* cache.c).*/
#define HTTP_CACHE_SEC_KEY_LEN (sizeof(uint32_t)+sizeof(uint64_t))
#define HTTP_CACHE_SEC_KEY_LEN (sizeof(uint32_t)+sizeof(uint64_t)+sizeof(uint64_t))
/* Redirect flags */

View File

@ -77,6 +77,20 @@ server s1 {
-hdr "Content-Encoding: gzip" \
-bodylen 57
rxreq
expect req.url == "/origin-referer-accept-encoding"
txresp -hdr "Vary: origin,referer,accept-encoding" \
-hdr "Cache-Control: max-age=5" \
-hdr "Content-Encoding: gzip" \
-bodylen 58
rxreq
expect req.url == "/origin-referer-accept-encoding"
txresp -hdr "Vary: origin,referer,accept-encoding" \
-hdr "Cache-Control: max-age=5" \
-hdr "Content-Encoding: gzip" \
-bodylen 59
# Multiple Accept-Encoding headers
rxreq
expect req.url == "/multiple_headers"
@ -315,6 +329,43 @@ client c1 -connect ${h1_fe_sock} {
expect resp.http.X-Cache-Hit == 1
# Mixed Vary (Accept-Encoding + Referer + Origin)
txreq -url "/origin-referer-accept-encoding" \
-hdr "Accept-Encoding: br, gzip" \
-hdr "Referer: referer" \
-hdr "Origin: origin"
rxresp
expect resp.status == 200
expect resp.bodylen == 58
expect resp.http.X-Cache-Hit == 0
txreq -url "/origin-referer-accept-encoding" \
-hdr "Accept-Encoding: br, gzip" \
-hdr "Referer: referer" \
-hdr "Origin: origin"
rxresp
expect resp.status == 200
expect resp.bodylen == 58
expect resp.http.X-Cache-Hit == 1
txreq -url "/origin-referer-accept-encoding" \
-hdr "Accept-Encoding: br, gzip" \
-hdr "Referer: referer" \
-hdr "Origin: other-origin"
rxresp
expect resp.status == 200
expect resp.bodylen == 59
expect resp.http.X-Cache-Hit == 0
txreq -url "/origin-referer-accept-encoding" \
-hdr "Accept-Encoding: br, gzip" \
-hdr "Referer: referer" \
-hdr "Origin: other-origin"
rxresp
expect resp.status == 200
expect resp.bodylen == 59
expect resp.http.X-Cache-Hit == 1
# Multiple Accept-encoding headers
txreq -url "/multiple_headers" \
-hdr "Accept-Encoding: gzip" \

View File

@ -93,6 +93,7 @@ struct show_cache_ctx {
enum vary_header_bit {
VARY_ACCEPT_ENCODING = (1 << 0),
VARY_REFERER = (1 << 1),
VARY_ORIGIN = (1 << 2),
VARY_LAST /* should always be last */
};
@ -143,6 +144,7 @@ static int accept_encoding_bitmap_cmp(const void *ref, const void *new, unsigned
const struct vary_hashing_information vary_information[] = {
{ IST("accept-encoding"), VARY_ACCEPT_ENCODING, sizeof(uint32_t), &accept_encoding_normalizer, &accept_encoding_bitmap_cmp },
{ IST("referer"), VARY_REFERER, sizeof(uint64_t), &default_normalizer, NULL },
{ IST("origin"), VARY_ORIGIN, sizeof(uint64_t), &default_normalizer, NULL },
};
@ -2370,7 +2372,7 @@ static int accept_encoding_normalizer(struct htx *htx, struct ist hdr_name,
#undef ACCEPT_ENCODING_MAX_ENTRIES
/*
* Normalizer used by default for the Referer header. It only
* Normalizer used by default for the Referer and Origin header. It only
* calculates a hash of the whole value using xxhash algorithm.
* Only the first occurrence of the header will be taken into account in the
* hash.