MINOR: cache: Improve accept_encoding_normalizer

Turn the "Accept-Encoding" value to lower case before processing it.
Calculate the CRC on every token instead of a sorted concatenation of
them all (in order to avoir copying them) then XOR all the CRCs into a
single hash (while ignoring duplicates).
This commit is contained in:
Remi Tricot-Le Breton 2020-11-30 17:06:03 +01:00 committed by William Lallemand
parent f67442efdb
commit 8bb72aa82f
2 changed files with 39 additions and 23 deletions

View File

@ -187,8 +187,9 @@ client c1 -connect ${h1_fe_sock} {
expect resp.http.content-type == "text/plain" expect resp.http.content-type == "text/plain"
expect resp.http.X-Cache-Hit == 1 expect resp.http.X-Cache-Hit == 1
# The accept-encoding normalizer function sorts alphabeticaly the values # The accept-encoding normalizer function converts the header values
# before calculating the secondary key # to lower case then calculates the hash of every sub part before
# sorting the hashes and xor'ing them (while removing duplicates).
txreq -url "/accept-encoding-multiple" -hdr "Accept-Encoding: first,second" txreq -url "/accept-encoding-multiple" -hdr "Accept-Encoding: first,second"
rxresp rxresp
expect resp.status == 200 expect resp.status == 200
@ -207,6 +208,12 @@ client c1 -connect ${h1_fe_sock} {
expect resp.bodylen == 51 expect resp.bodylen == 51
expect resp.http.X-Cache-Hit == 1 expect resp.http.X-Cache-Hit == 1
txreq -url "/accept-encoding-multiple" -hdr "Accept-Encoding: FirsT,SECOND,first"
rxresp
expect resp.status == 200
expect resp.bodylen == 51
expect resp.http.X-Cache-Hit == 1
# Unmanaged vary # Unmanaged vary
txreq -url "/unmanaged" -hdr "Accept-Encoding: first_value" txreq -url "/unmanaged" -hdr "Accept-Encoding: first_value"
rxresp rxresp
@ -270,7 +277,7 @@ client c1 -connect ${h1_fe_sock} {
expect resp.bodylen == 57 expect resp.bodylen == 57
expect resp.http.X-Cache-Hit == 1 expect resp.http.X-Cache-Hit == 1
# The following requests are trated by a backend that does not cache # The following requests are treated by a backend that does not cache
# responses containing a Vary header # responses containing a Vary header
txreq -url "/no_vary_support" txreq -url "/no_vary_support"
rxresp rxresp

View File

@ -1791,10 +1791,14 @@ struct flt_ops cache_ops = {
int accept_encoding_cmp(const void *a, const void *b) int accept_encoding_cmp(const void *a, const void *b)
{ {
const struct ist ist_a = *(const struct ist*)a; unsigned int int_a = *(unsigned int*)a;
const struct ist ist_b = *(const struct ist*)b; unsigned int int_b = *(unsigned int*)b;
return istdiff(ist_a, ist_b); if (int_a < int_b)
return -1;
if (int_a > int_b)
return 1;
return 0;
} }
#define ACCEPT_ENCODING_MAX_ENTRIES 16 #define ACCEPT_ENCODING_MAX_ENTRIES 16
@ -1804,33 +1808,38 @@ int accept_encoding_cmp(const void *a, const void *b)
* for the newly constructed buffer. * for the newly constructed buffer.
* Returns 0 in case of success. * Returns 0 in case of success.
*/ */
static int accept_encoding_normalizer(struct ist value, char *buf, unsigned int *buf_len) static int accept_encoding_normalizer(struct ist full_value, char *buf, unsigned int *buf_len)
{ {
struct ist values[ACCEPT_ENCODING_MAX_ENTRIES] = {{}}; unsigned int values[ACCEPT_ENCODING_MAX_ENTRIES] = {};
size_t count = 0; size_t count = 0;
char *comma = NULL; char *comma = NULL;
struct buffer *trash = get_trash_chunk(); unsigned int hash_value = 0;
int hash_value = 0; unsigned int prev = 0, curr = 0;
/* Turn accept-encoding value to lower case */
full_value = ist2bin_lc(istptr(full_value), full_value);
/* The hash will be built out of a sorted list of accepted encodings. */ /* The hash will be built out of a sorted list of accepted encodings. */
while (count < (ACCEPT_ENCODING_MAX_ENTRIES - 1) && (comma = istchr(value, ',')) != NULL) { while (count < (ACCEPT_ENCODING_MAX_ENTRIES - 1) && (comma = istchr(full_value, ',')) != NULL) {
size_t length = comma - istptr(value); size_t length = comma - istptr(full_value);
values[count++] = hash_crc32(istptr(full_value), length);
full_value = istadv(full_value, length + 1);
values[count++] = isttrim(value, length);
value = istadv(value, length + 1);
} }
values[count++] = value; values[count++] = hash_crc32(istptr(full_value), istlen(full_value));
if (count == ACCEPT_ENCODING_MAX_ENTRIES)
return 1;
/* Sort the values alphabetically. */ /* Sort the values alphabetically. */
qsort(values, count, sizeof(struct ist), &accept_encoding_cmp); qsort(values, count, sizeof(*values), &accept_encoding_cmp);
while (count) while (count) {
chunk_istcat(trash, values[--count]); curr = values[--count];
if (curr != prev) {
hash_value = hash_crc32(b_orig(trash), b_data(trash)); hash_value ^= curr;
}
prev = curr;
}
memcpy(buf, &hash_value, sizeof(hash_value)); memcpy(buf, &hash_value, sizeof(hash_value));
*buf_len = sizeof(hash_value); *buf_len = sizeof(hash_value);