txresp -hdr "Vary: accept-encoding" \
-hdr "Cache-Control: max-age=5" \
-bodylen 256
+
+ # Repeated Origin / Referer headers: duplicates are not cached.
+ rxreq
+ expect req.url == "/repeated-origin"
+ txresp -hdr "Vary: origin" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 270
+
+ rxreq
+ expect req.url == "/repeated-origin"
+ txresp -hdr "Vary: origin" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 271
+
+ rxreq
+ expect req.url == "/repeated-origin"
+ txresp -hdr "Vary: origin" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 281
+
+ rxreq
+ expect req.url == "/repeated-referer"
+ txresp -hdr "Vary: referer" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 292
+
+ rxreq
+ expect req.url == "/repeated-referer"
+ txresp -hdr "Vary: referer" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 292
+
+ rxreq
+ expect req.url == "/repeated-referer"
+ txresp -hdr "Vary: referer" \
+ -hdr "Cache-Control: max-age=5" \
+ -bodylen 303
} -start
server s2 {
expect resp.http.content-encoding == "<undef>"
expect resp.http.X-Cache-Hit == 0
+ # Repeated origin or referers are not cached since not valid.
+
+ # Two origins -> not cached, first request is a miss.
+ txreq -url "/repeated-origin" \
+ -hdr "Origin: origin_a" \
+ -hdr "Origin: origin_b"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 270
+ expect resp.http.X-Cache-Hit == 0
+
+ # Same two origins again -> still a miss, the response was not stored.
+ txreq -url "/repeated-origin" \
+ -hdr "Origin: origin_a" \
+ -hdr "Origin: origin_b"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 271
+ expect resp.http.X-Cache-Hit == 0
+
+ # A single origin is well-formed and must be cached normally, without
+ # being affected by the malformed requests above.
+ txreq -url "/repeated-origin" \
+ -hdr "Origin: origin_a"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 281
+ expect resp.http.X-Cache-Hit == 0
+
+ # Same single origin again -> cache hit on its own entry.
+ txreq -url "/repeated-origin" \
+ -hdr "Origin: origin_a"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 281
+ expect resp.http.X-Cache-Hit == 1
+
+ # Repeated Referer headers behave the same way.
+ txreq -url "/repeated-referer" \
+ -hdr "Referer: referer_a" \
+ -hdr "Referer: referer_b"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 292
+ expect resp.http.X-Cache-Hit == 0
+
+ # Same two referers again -> still a miss.
+ txreq -url "/repeated-referer" \
+ -hdr "Referer: referer_a" \
+ -hdr "Referer: referer_b"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 292
+ expect resp.http.X-Cache-Hit == 0
+
+ # A single referer is well-formed and must be cached normally.
+ txreq -url "/repeated-referer" \
+ -hdr "Referer: referer_a"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 303
+ expect resp.http.X-Cache-Hit == 0
+
+ # Same single referer again -> cache hit on its own entry.
+ txreq -url "/repeated-referer" \
+ -hdr "Referer: referer_a"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 303
+ expect resp.http.X-Cache-Hit == 1
+
# The following requests are treated by a backend that does not cache
# responses containing a Vary header
txreq -url "/no_vary_support"
#undef ACCEPT_ENCODING_MAX_ENTRIES
/*
- * 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.
+ * Normalizer used by default for the Referer and Origin header. It calculates
+ * a hash of the whole value using xxhash algorithm. Both headers are single-
+ * valued, but we can't predict how servers would handle extra occurrences,
+ * so better just ignore the secondary keys in case of extra entry, by
+ * returning -1. That way we continue to hash only the full header line.
* Returns 0 in case of success, 1 if the hash buffer should be filled with 0s
- * and -1 in case of error.
+ * and -1 in case of error (header present more than once).
*/
static int default_normalizer(struct htx *htx, struct ist hdr_name,
char *buf, unsigned int *buf_len)
retval = 0;
write_u64(buf, XXH3(istptr(ctx.value), istlen(ctx.value), cache_hash_seed));
*buf_len = sizeof(uint64_t);
+
+ /* Make sure the header is unique and disable caching on duplicate */
+ if (http_find_header(htx, hdr_name, &ctx, 1))
+ retval = -1;
}
return retval;
* implementation) of a given request. We have to calculate all the hashes
* in advance because the actual Vary signature won't be known until the first
* response.
- * Only the first occurrence of every header will be taken into account in the
- * hash.
* If the header is not present, the hash portion of the given header will be
* filled with zeros.
* Returns 0 in case of success.
* Calculate the secondary key for a request for which we already have a known
* vary signature. The key is made by aggregating hashes calculated for every
* header mentioned in the vary signature.
- * Only the first occurrence of every header will be taken into account in the
- * hash.
* If the header is not present, the hash portion of the given header will be
* filled with zeros.
* Returns 0 in case of success.