This is a crudely hacked together proof-of-concept where a "perfect hash"
is used to find out if a given HTTP header has filtering flags.

I expect, but am far from sure, that this will perform better than the
current sequential code.

If anybody has a chance to beat this up in some kind of a performance
test, I would be very interested to hear the results.

-- 
Poul-Henning Kamp       | UNIX since Zilog Zeus 3.20
p...@freebsd.org         | TCP/IP since RFC 956
FreeBSD committer       | BSD since 4.3-tahoe
Never attribute to malice what can adequately be explained by incompetence.
diff --git a/bin/varnishd/cache/cache_http.c b/bin/varnishd/cache/cache_http.c
index 09fce7def..ef09a5f8f 100644
--- a/bin/varnishd/cache/cache_http.c
+++ b/bin/varnishd/cache/cache_http.c
@@ -57,6 +57,124 @@ const char H__Status[]	= "\010:status:";
 const char H__Proto[]	= "\007:proto:";
 const char H__Reason[]	= "\010:reason:";
 
+
+/*--------------------------------------------------------------------
+ * Generated with gperf --ignore-case over tbl/http_headers.h
+ * where third arg non-zero.
+ */
+
+static const unsigned char asso_values[] = {
+	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
+};
+
+static struct foobar {
+	char		*hdr;
+	unsigned	flag;
+} foobar[] = {
+	{ NULL },
+	{ NULL },
+	{ H_TE },
+	{ H_Age },
+	{ NULL },
+	{ H_Range },
+	{ NULL },
+	{ H_Upgrade },
+	{ H_If_Range },
+	{ NULL },
+	{ H_Connection },
+	{ NULL },
+	{ 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_If_Unmodified_Since },
+	{ NULL },
+	{ NULL },
+	{ H_If_Modified_Since },
+	{ H_Cache_Control },
+	{ NULL },
+	{ NULL },
+	{ NULL },
+	{ NULL },
+	{ H_Accept_Ranges }
+};
+
+static struct foobar *
+hdr_hash(const char *b, const char *e)
+{
+	unsigned u;
+	struct foobar *retval;
+
+	if (e == NULL)
+		return(NULL);
+	assert(e > b);
+	u = (unsigned)(e - b);
+	if (u < 1 || u > 19)
+		return(NULL);
+	if (u > 3)
+		u += asso_values[((const uint8_t*)b)[3]];
+	if (u > 38)
+		return(NULL);
+	retval = &foobar[u];
+	if (retval->hdr == NULL)
+		return(NULL);
+	if (strncasecmp(retval->hdr + 1, b, e - b))
+		return(NULL);
+	return(retval);
+}
+
+static void
+hdr_init(char *hdr, int flg)
+{
+	struct foobar *f;
+
+	hdr[0] = strlen(hdr + 1);
+	f = hdr_hash(hdr + 1, hdr + hdr[0]);
+	if (!flg)
+		return;
+	AN(f);
+	assert(f->hdr == hdr);
+	f->flag = flg;
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+HTTP_Init(void)
+{
+
+#define HTTPH(a, b, c) hdr_init(b, c);
+#include "tbl/http_headers.h"
+}
+
 /*--------------------------------------------------------------------
  * These two functions are in an incestuous relationship with the
  * order of macros in include/tbl/vsl_tags_http.h
@@ -735,6 +853,7 @@ http_DoConnection(struct http *hp, enum sess_close sc_close)
 	const char *h, *b, *e;
 	enum sess_close retval;
 	unsigned u, v;
+	struct foobar *f;
 
 	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
 	assert(sc_close == SC_REQ_CLOSE || sc_close == SC_RESP_CLOSE);
@@ -756,13 +875,9 @@ http_DoConnection(struct http *hp, enum sess_close sc_close)
 			retval = SC_NULL;
 
 		/* Refuse removal of well-known-headers if they would pass. */
-/*lint -save -e506 [constant value boolean] */
-#define HTTPH(a, x, c)						\
-		if (!((c) & HTTPH_R_PASS) &&			\
-		    strlen(a) == u && !strncasecmp(a, b, u))	\
+		f = hdr_hash(b, e);
+		if (f != NULL && !(f->flag & HTTPH_R_PASS))
 			return (SC_RX_BAD);
-#include "tbl/http_headers.h"
-/*lint -restore */
 
 		for (v = HTTP_HDR_FIRST; v < hp->nhd; v++) {
 			Tcheck(hp->hd[v]);
@@ -898,13 +1013,16 @@ http_PutResponse(struct http *to, const char *proto, uint16_t status,
 static inline int
 http_isfiltered(const struct http *fm, unsigned u, unsigned how)
 {
+	const char *e;
+	const struct foobar *f;
+
 	if (fm->hdf[u] & HDF_FILTER)
 		return (1);
-#define HTTPH(a, b, c) \
-	if (((c) & how) && http_IsHdr(&fm->hd[u], (b))) \
-		return (1);
-#include "tbl/http_headers.h"
-	return (0);
+	e = strchr(fm->hd[u].b, ':');
+	if (e == NULL)
+		return (0);
+	f = hdr_hash(fm->hd[u].b, e);
+	return (f != NULL && f->flag & how);
 }
 
 int
@@ -1313,13 +1431,3 @@ http_Unset(struct http *hp, const char *hdr)
 	}
 	hp->nhd = v;
 }
-
-/*--------------------------------------------------------------------*/
-
-void
-HTTP_Init(void)
-{
-
-#define HTTPH(a, b, c) b[0] = (char)strlen(b + 1);
-#include "tbl/http_headers.h"
-}
_______________________________________________
varnish-dev mailing list
varnish-dev@varnish-cache.org
https://www.varnish-cache.org/lists/mailman/listinfo/varnish-dev

Reply via email to