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