]> err.no Git - varnish/commitdiff
Do a better job on Connection: header processing in client requests.
authorphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Fri, 18 Aug 2006 19:53:43 +0000 (19:53 +0000)
committerphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Fri, 18 Aug 2006 19:53:43 +0000 (19:53 +0000)
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

varnish-cache/bin/varnishd/cache.h
varnish-cache/bin/varnishd/cache_center.c
varnish-cache/bin/varnishd/cache_http.c

index 4d8d0784b4f2ebe7da0107e8c2309d6477314bd0..499132ba84a8f56d88b1de3a7fbf9a8466004dda 100644 (file)
@@ -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"
index 761bae043d698c8cc868e5ba8a41fa3a3fe9fe48..6fc1a3a2920cdae991efe5d2daa79dac670ac3ba 100644 (file)
@@ -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];
 
index cf9a6df36743137a19ee6105ab9a4349954567e3..934ff5da4d5f89935e69374e66075e6f1fe4592d 100644 (file)
@@ -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;