Commit 043d7cb6 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

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: http://www.varnish-cache.org/svn/trunk/varnish-cache@832 d4fa192b-c00b-0410-8231-f00ffab90ce4
parent fcf841c1
......@@ -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"
......
......@@ -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];
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment