From: phk Date: Fri, 18 Aug 2006 19:53:43 +0000 (+0000) Subject: Do a better job on Connection: header processing in client requests. X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ea061c082449ee5f83b1f74ae48d126609ef6b67;p=varnish Do a better job on Connection: header processing in client requests. Add a flag field for each HTTP header and define a bit HDF_FILTER to mean "filter this out", and initialize to zero all relevant places. If HDF_FILTER is set, do not copy the header across when filtering. Run through Connection: header (if present) and set HDF_FILTER on any header that matches a word in the contents. If we are not HTTP/1.1 and have no Connection header, we close the session when this reqest is done. If we have a Connection header, we respect that. git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@832 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- diff --git a/varnish-cache/bin/varnishd/cache.h b/varnish-cache/bin/varnishd/cache.h index 4d8d0784..499132ba 100644 --- a/varnish-cache/bin/varnishd/cache.h +++ b/varnish-cache/bin/varnishd/cache.h @@ -73,6 +73,8 @@ struct http { } logtag; struct http_hdr hd[HTTP_HDR_MAX]; + unsigned char hdf[HTTP_HDR_MAX]; +#define HDF_FILTER (1 << 0) /* Filtered by Connection */ unsigned nhd; }; @@ -360,6 +362,7 @@ int http_RecvSome(int fd, struct http *hp); int http_RecvHead(struct http *hp, int fd); int http_DissectRequest(struct http *sp, int fd); int http_DissectResponse(struct http *sp, int fd); +void http_DoConnection(struct sess *sp); #define HTTPH(a, b, c, d, e, f, g) extern char b[]; #include "http_headers.h" diff --git a/varnish-cache/bin/varnishd/cache_center.c b/varnish-cache/bin/varnishd/cache_center.c index 761bae04..6fc1a3a2 100644 --- a/varnish-cache/bin/varnishd/cache_center.c +++ b/varnish-cache/bin/varnishd/cache_center.c @@ -565,10 +565,7 @@ cnt_recv(struct sess *sp) return (0); } - if (http_GetHdr(sp->http, H_Connection, &b) && !strcmp(b, "close")) - sp->doclose = "Connection:"; - else if (strcmp(sp->http->hd[HTTP_HDR_PROTO].b, "HTTP/1.1")) - sp->doclose = "not HTTP/1.1"; + http_DoConnection(sp); sp->backend = sp->vcl->backend[0]; diff --git a/varnish-cache/bin/varnishd/cache_http.c b/varnish-cache/bin/varnishd/cache_http.c index cf9a6df3..934ff5da 100644 --- a/varnish-cache/bin/varnishd/cache_http.c +++ b/varnish-cache/bin/varnishd/cache_http.c @@ -99,35 +99,47 @@ http_IsHdr(struct http_hdr *hh, char *hdr) /*--------------------------------------------------------------------*/ -int -http_GetHdr(struct http *hp, const char *hdr, char **ptr) +static unsigned +http_findhdr(struct http *hp, unsigned l, const char *hdr) { - unsigned u, l; - char *p; + unsigned u; - l = hdr[0]; - assert(l == strlen(hdr + 1)); - assert(hdr[l] == ':'); - hdr++; for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) { assert(hp->hd[u].b != NULL); assert(hp->hd[u].e != NULL); - if (hp->hd[u].e < hp->hd[u].b + l) + if (hp->hd[u].e < hp->hd[u].b + l + 1) continue; - if (hp->hd[u].b[l-1] != ':') + if (hp->hd[u].b[l] != ':') continue; if (strncasecmp(hdr, hp->hd[u].b, l)) continue; - p = hp->hd[u].b + l; - while (isspace(*p)) - p++; - *ptr = p; - return (1); + return (u); } - *ptr = NULL; return (0); } +int +http_GetHdr(struct http *hp, const char *hdr, char **ptr) +{ + unsigned u, l; + char *p; + + l = hdr[0]; + assert(l == strlen(hdr + 1)); + assert(hdr[l] == ':'); + hdr++; + u = http_findhdr(hp, l - 1, hdr); + if (u == 0) { + *ptr = NULL; + return (0); + } + p = hp->hd[u].b + l; + while (isspace(*p)) + p++; + *ptr = p; + return (1); +} + /*--------------------------------------------------------------------*/ int @@ -165,6 +177,43 @@ http_GetHdrField(struct http *hp, const char *hdr, const char *field, char **ptr /*--------------------------------------------------------------------*/ +void +http_DoConnection(struct sess *sp) +{ + struct http *hp = sp->http; + char *p, *q; + int i; + unsigned u; + + if (!http_GetHdr(hp, H_Connection, &p)) { + if (strcmp(hp->hd[HTTP_HDR_PROTO].b, "HTTP/1.1")) + sp->doclose = "not HTTP/1.1"; + return; + } + VSL(SLT_Debug, sp->fd, "DoConnect(%s)", p); + for (; *p; p++) { + if (isspace(*p)) + continue; + if (*p == ',') + continue; + for (q = p + 1; *q; q++) + if (*q == ',' || isspace(*q)) + break; + i = q - p; + if (i == 5 && !strncasecmp(p, "close", i)) + sp->doclose = "Connection: close"; + u = http_findhdr(hp, i, p); + if (u != 0) + hp->hdf[u] |= HDF_FILTER; + VSL(SLT_Debug, sp->fd, "FLD(%.*s) u = %u", q - p, p, u); + if (!*q) + break; + p = q; + } +} + +/*--------------------------------------------------------------------*/ + int http_HdrIs(struct http *hp, const char *hdr, const char *val) { @@ -275,6 +324,7 @@ http_dissect_hdrs(struct http *hp, int fd, char *p) hp->conds = 1; if (hp->nhd < HTTP_HDR_MAX) { + hp->hdf[hp->nhd] = 0; hp->hd[hp->nhd].b = p; hp->hd[hp->nhd].e = q; VSLH(HTTP_T_Header, fd, hp, hp->nhd); @@ -577,6 +627,7 @@ http_seth(int fd, struct http *to, unsigned n, enum httptag tag, const char *fm) assert(fm != NULL); to->hd[n].b = (void*)(uintptr_t)fm; to->hd[n].e = (void*)(uintptr_t)strchr(fm, '\0'); + to->hdf[n] = 0; VSLH(tag, fd, to, n); } @@ -588,6 +639,7 @@ http_copyh(int fd, struct http *to, struct http *fm, unsigned n, enum httptag ta assert(fm->hd[n].b != NULL); to->hd[n].b = fm->hd[n].b; to->hd[n].e = fm->hd[n].e; + to->hdf[n] = fm->hdf[n]; VSLH(tag, fd, to, n); } @@ -664,6 +716,8 @@ http_FilterHeader(int fd, struct http *to, struct http *fm, unsigned how) CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); to->nhd = HTTP_HDR_FIRST; for (u = HTTP_HDR_FIRST; u < fm->nhd; u++) { + if (fm->hdf[u] & HDF_FILTER) + continue; #define HTTPH(a, b, c, d, e, f, g) \ if (((e) & how) && http_IsHdr(&fm->hd[u], (b))) \ continue;