242 lines
6.9 KiB
Diff
242 lines
6.9 KiB
Diff
From fcf5722af75fdbf58dd425dd68d0beaa49bab4f4 Mon Sep 17 00:00:00 2001
|
|
From: Martin Blix Grydeland <martin@varnish-software.com>
|
|
Date: Thu, 29 Sep 2022 14:38:05 +0200
|
|
Subject: [PATCH] Add all well-known headers to the perfect hash lookup table
|
|
|
|
Origin: https://github.com/varnishcache/varnish-cache/commit/fcf5722af75fdbf58dd425dd68d0beaa49bab4f4
|
|
|
|
This expands the perfect hash lookup table to be able to match any entry
|
|
in the list of well-known headers from tbl/http_headers.h.
|
|
|
|
Previously only the headers that had a non-zero filter flag section was
|
|
kept in the fast match table.
|
|
|
|
Fixes: VSV00010
|
|
---
|
|
bin/varnishd/cache/cache_http.c | 148 +++++++++++++++++++------------
|
|
bin/varnishtest/tests/f00010.vtc | 19 ++++
|
|
2 files changed, 112 insertions(+), 55 deletions(-)
|
|
create mode 100644 bin/varnishtest/tests/f00010.vtc
|
|
|
|
diff --git a/bin/varnishd/cache/cache_http.c b/bin/varnishd/cache/cache_http.c
|
|
index 194055c3ca..827197dedf 100644
|
|
--- a/bin/varnishd/cache/cache_http.c
|
|
+++ b/bin/varnishd/cache/cache_http.c
|
|
@@ -65,73 +65,113 @@ const char H__Reason[] = "\010:reason:";
|
|
* A suitable algorithm can be found with `gperf`:
|
|
*
|
|
* tr '" ,' ' ' < include/tbl/http_headers.h |
|
|
- * awk '$1 == "H(" && $4 != "0" {print$2}' |
|
|
+ * awk '$1 == "H(" {print $2}' |
|
|
* gperf --ignore-case
|
|
*
|
|
*/
|
|
|
|
+#define GPERF_MIN_WORD_LENGTH 2
|
|
+#define GPERF_MAX_WORD_LENGTH 19
|
|
+#define GPERF_MAX_HASH_VALUE 79
|
|
+
|
|
static const unsigned char http_asso_values[256] = {
|
|
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
|
|
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
|
|
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
|
|
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
|
|
- 39, 39, 39, 39, 39, 25, 39, 0, 20, 5, 39, 39, 39, 15, 0, 39,
|
|
- 10, 39, 0, 39, 15, 10, 39, 39, 0, 39, 39, 39, 39, 39, 39, 39,
|
|
- 39, 39, 39, 39, 39, 25, 39, 0, 20, 5, 39, 39, 39, 15, 0, 39,
|
|
- 10, 39, 0, 39, 15, 10, 39, 39, 0, 39, 39, 39, 39, 39, 39, 39,
|
|
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
|
|
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
|
|
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
|
|
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
|
|
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
|
|
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
|
|
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
|
|
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39
|
|
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 0, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 80, 80, 5, 80, 20, 0, 0,
|
|
+ 5, 10, 5, 5, 80, 0, 15, 0, 20, 80,
|
|
+ 40, 80, 0, 35, 10, 20, 55, 45, 0, 0,
|
|
+ 80, 80, 80, 80, 80, 80, 80, 5, 80, 20,
|
|
+ 0, 0, 5, 10, 5, 5, 80, 0, 15, 0,
|
|
+ 20, 80, 40, 80, 0, 35, 10, 20, 55, 45,
|
|
+ 0, 0, 80, 80, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
|
|
+ 80, 80, 80, 80, 80, 80
|
|
};
|
|
|
|
static struct http_hdrflg {
|
|
char *hdr;
|
|
unsigned flag;
|
|
-} http_hdrflg[38 + 1] = { // MAX_HASH_VALUE
|
|
- { NULL },
|
|
- { NULL },
|
|
- { H_TE },
|
|
- { H_Age },
|
|
- { NULL },
|
|
+} http_hdrflg[GPERF_MAX_HASH_VALUE + 1] = {
|
|
+ { NULL }, { NULL }, { NULL }, { NULL },
|
|
+ { H_Date },
|
|
{ H_Range },
|
|
{ NULL },
|
|
- { H_Upgrade },
|
|
+ { H_Referer },
|
|
+ { H_Age },
|
|
+ { H_From },
|
|
+ { H_Keep_Alive },
|
|
+ { H_Retry_After },
|
|
+ { H_TE },
|
|
{ H_If_Range },
|
|
- { NULL },
|
|
- { H_Connection },
|
|
- { NULL },
|
|
+ { H_ETag },
|
|
+ { H_X_Forwarded_For },
|
|
+ { H_Expect },
|
|
{ H_Trailer },
|
|
- { H_If_None_Match },
|
|
- { NULL },
|
|
- { NULL },
|
|
- { NULL },
|
|
- { H_Transfer_Encoding },
|
|
- { H_Proxy_Authenticate },
|
|
- { H_Proxy_Authorization },
|
|
- { H_Keep_Alive },
|
|
- { NULL },
|
|
- { NULL },
|
|
{ H_If_Match },
|
|
- { H_HTTP2_Settings },
|
|
- { NULL },
|
|
- { NULL },
|
|
- { NULL },
|
|
- { H_Content_Range },
|
|
+ { H_Host },
|
|
+ { H_Accept_Language },
|
|
+ { H_Accept },
|
|
+ { H_If_Modified_Since },
|
|
+ { H_If_None_Match },
|
|
{ H_If_Unmodified_Since },
|
|
{ NULL },
|
|
+ { H_Cookie },
|
|
+ { H_Upgrade },
|
|
+ { H_Last_Modified },
|
|
+ { H_Accept_Charset },
|
|
+ { H_Accept_Encoding },
|
|
+ { H_Content_MD5 },
|
|
+ { H_Content_Type },
|
|
+ { H_Content_Range },
|
|
+ { NULL }, { NULL },
|
|
+ { H_Content_Language },
|
|
+ { H_Transfer_Encoding },
|
|
+ { H_Authorization },
|
|
+ { H_Content_Length },
|
|
+ { H_User_Agent },
|
|
+ { H_Server },
|
|
+ { H_Expires },
|
|
+ { H_Location },
|
|
{ NULL },
|
|
- { H_If_Modified_Since },
|
|
+ { H_Set_Cookie },
|
|
+ { H_Content_Encoding },
|
|
+ { H_Max_Forwards },
|
|
{ H_Cache_Control },
|
|
{ NULL },
|
|
+ { H_Connection },
|
|
+ { H_Pragma },
|
|
{ NULL },
|
|
+ { H_Accept_Ranges },
|
|
+ { H_HTTP2_Settings },
|
|
+ { H_Allow },
|
|
+ { H_Content_Location },
|
|
{ NULL },
|
|
+ { H_Proxy_Authenticate },
|
|
+ { H_Vary },
|
|
{ NULL },
|
|
- { H_Accept_Ranges }
|
|
+ { H_WWW_Authenticate },
|
|
+ { H_Warning },
|
|
+ { H_Via },
|
|
+ { NULL }, { NULL }, { NULL }, { NULL },
|
|
+ { NULL }, { NULL }, { NULL }, { NULL },
|
|
+ { NULL }, { NULL }, { NULL }, { NULL },
|
|
+ { NULL }, { NULL }, { NULL },
|
|
+ { H_Proxy_Authorization }
|
|
};
|
|
|
|
static struct http_hdrflg *
|
|
@@ -145,12 +185,12 @@ http_hdr_flags(const char *b, const char *e)
|
|
assert(b <= e);
|
|
u = (unsigned)(e - b);
|
|
assert(b + u == e);
|
|
- if (u < 2 || u > 19) // MIN_WORD_LENGTH & MAX_WORD_LENGTH
|
|
- return(NULL);
|
|
- if (u > 3)
|
|
- u += http_asso_values[((const uint8_t*)b)[3]];
|
|
- if (u > 38) // MAX_HASH_VALUE
|
|
- return(NULL);
|
|
+ if (u < GPERF_MIN_WORD_LENGTH || u > GPERF_MAX_WORD_LENGTH)
|
|
+ return (NULL);
|
|
+ u += http_asso_values[((const uint8_t *)b)[u - 1]] +
|
|
+ http_asso_values[((const uint8_t *)b)[0]];
|
|
+ if (u > GPERF_MAX_HASH_VALUE)
|
|
+ return (NULL);
|
|
retval = &http_hdrflg[u];
|
|
if (retval->hdr == NULL)
|
|
return(NULL);
|
|
@@ -168,11 +208,9 @@ http_init_hdr(char *hdr, int flg)
|
|
|
|
hdr[0] = strlen(hdr + 1);
|
|
f = http_hdr_flags(hdr + 1, hdr + hdr[0]);
|
|
- if (flg) {
|
|
- AN(f);
|
|
- assert(f->hdr == hdr);
|
|
- f->flag = flg;
|
|
- }
|
|
+ AN(f);
|
|
+ assert(f->hdr == hdr);
|
|
+ f->flag = flg;
|
|
}
|
|
|
|
void
|
|
diff --git a/bin/varnishtest/tests/f00010.vtc b/bin/varnishtest/tests/f00010.vtc
|
|
new file mode 100644
|
|
index 0000000000..b381b5cf37
|
|
--- /dev/null
|
|
+++ b/bin/varnishtest/tests/f00010.vtc
|
|
@@ -0,0 +1,19 @@
|
|
+varnishtest "Do not allow critical headers to be marked hop-by-hop"
|
|
+
|
|
+varnish v1 -vcl {
|
|
+ backend default none;
|
|
+} -start
|
|
+
|
|
+client c1 {
|
|
+ txreq -hdr "Connection: Content-Length" -body "asdf"
|
|
+ rxresp
|
|
+ expect resp.status == 400
|
|
+ expect_close
|
|
+} -run
|
|
+
|
|
+client c2 {
|
|
+ txreq -hdr "Connection: Host"
|
|
+ rxresp
|
|
+ expect resp.status == 400
|
|
+ expect_close
|
|
+} -run
|