From: phk Date: Fri, 21 Jul 2006 09:32:09 +0000 (+0000) Subject: HTTP header munging part (N of M) X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=80d11547f23a9643a07e25a68a8d8dcad46dbd42;p=varnish HTTP header munging part (N of M) NB: Only pass mode (lightly) tested right now. Give up on the three element array per header and use a two element struct instead, it reduces obfuscation and removes risk of pointer fandango. Introduce #defined filtercontrol in http_headers.h, use them in a new field. Only Pass is there for now. Use the http-workspace for building headers instead of sbuf. Move uiovec handling to cache_pool.c where it more naturally belongs and so we can use it on both backends and sessions. Add http header munging functiosn for copying, printf'ing, filtering and writing headers. git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@533 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- diff --git a/varnish-cache/bin/varnishd/cache.h b/varnish-cache/bin/varnishd/cache.h index a1bc5fa3..f743a654 100644 --- a/varnish-cache/bin/varnishd/cache.h +++ b/varnish-cache/bin/varnishd/cache.h @@ -15,10 +15,10 @@ #include "common.h" #include "miniobj.h" -#define MAX_IOVS 10 - #define MAX_HTTP_HDRS 32 +#define MAX_IOVS (MAX_HTTP_HDRS * 2) + #define HTTP_HDR_REQ 0 #define HTTP_HDR_URL 1 #define HTTP_HDR_PROTO 2 @@ -26,10 +26,6 @@ #define HTTP_HDR_RESPONSE 4 #define HTTP_HDR_FIRST 5 -#define HTTP_START 0 -#define HTTP_DATA 1 -#define HTTP_END 2 - struct event_base; struct cli; struct sbuf; @@ -52,6 +48,11 @@ enum step { typedef void http_callback_f(void *, int bad); +struct http_hdr { + char *b; + char *e; +}; + struct http { unsigned magic; #define HTTP_MAGIC 0x6428b5c9 @@ -67,8 +68,9 @@ struct http { unsigned conds; /* If-* headers present */ - char *hd[MAX_HTTP_HDRS][HTTP_END + 1]; + struct http_hdr hd[MAX_HTTP_HDRS]; unsigned nhd; + unsigned char hdf[MAX_HTTP_HDRS]; }; /*--------------------------------------------------------------------*/ @@ -85,6 +87,8 @@ struct worker { pthread_cond_t cv; TAILQ_ENTRY(worker) list; + int *wfd; + unsigned werr; /* valid after WRK_Flush() */ struct iovec iov[MAX_IOVS]; unsigned niov; size_t liov; @@ -296,6 +300,13 @@ void HSH_Init(void); /* cache_http.c */ void HTTP_Init(void); +void http_Write(struct worker *w, struct http *hp, int resp); +void http_CopyReq(int fd, struct http *to, struct http *fm); +void http_CopyResp(int fd, struct http *to, struct http *fm); +void http_FilterHeader(int fd, struct http *to, struct http *fm, unsigned how); +void http_CopyHeader(int fd, struct http *to, struct http *fm, unsigned n); +void http_PrintfHeader(int fd, struct http *to, const char *fmt, ...); +int http_IsHdr(struct http_hdr *hh, char *hdr); void http_Setup(struct http *ht, void *space, unsigned len); int http_GetHdr(struct http *hp, const char *hdr, char **ptr); int http_GetHdrField(struct http *hp, const char *hdr, const char *field, char **ptr); @@ -318,7 +329,7 @@ void http_BuildSbuf(int fd, enum http_build mode, struct sbuf *sb, struct http * #undef HTTPH /* cache_pass.c */ -void PassSession(struct worker *w, struct sess *sp); +void PassSession(struct sess *sp); void PassBody(struct worker *w, struct sess *sp); /* cache_pipe.c */ @@ -327,6 +338,10 @@ void PipeSession(struct worker *w, struct sess *sp); /* cache_pool.c */ void WRK_Init(void); void WRK_QueueSession(struct sess *sp); +void WRK_Reset(struct worker *w, int *fd); +int WRK_Flush(struct worker *w); +void WRK_Write(struct worker *w, const void *ptr, size_t len); +void WRK_WriteH(struct worker *w, struct http_hdr *hh, const char *suf); /* cache_session.c [SES] */ void SES_Init(void); @@ -352,8 +367,6 @@ void VSL(enum shmlogtag tag, unsigned id, const char *fmt, ...); /* cache_response.c */ void RES_Error(struct sess *sp, int error, const char *msg); -void RES_Flush(struct sess *sp); -void RES_Write(struct sess *sp, const void *ptr, size_t len); void RES_WriteObj(struct sess *sp); /* cache_vcl.c */ diff --git a/varnish-cache/bin/varnishd/cache_center.c b/varnish-cache/bin/varnishd/cache_center.c index 374801ad..9ef84388 100644 --- a/varnish-cache/bin/varnishd/cache_center.c +++ b/varnish-cache/bin/varnishd/cache_center.c @@ -90,8 +90,7 @@ cnt_done(struct sess *sp) } else if (http_GetHdr(sp->http, H_Connection, &b) && !strcmp(b, "close")) { vca_close_session(sp, "Connection header"); - } else if (strcmp(sp->http->hd[HTTP_HDR_PROTO][HTTP_START], - "HTTP/1.1")) { + } else if (strcmp(sp->http->hd[HTTP_HDR_PROTO].b, "HTTP/1.1")) { vca_close_session(sp, "not HTTP/1.1"); } VCL_Rel(sp->vcl); @@ -263,7 +262,7 @@ cnt_hit(struct sess *sp) if (sp->handling == VCL_RET_PASS) { HSH_Deref(sp->obj); sp->obj = NULL; - PassSession(sp->wrk, sp); + PassSession(sp); sp->step = STP_PASSBODY; return (0); } @@ -398,7 +397,7 @@ cnt_miss(struct sess *sp) HSH_Unbusy(sp->obj); HSH_Deref(sp->obj); sp->obj = 0; - PassSession(sp->wrk, sp); + PassSession(sp); sp->step = STP_PASSBODY; return (0); } @@ -431,7 +430,7 @@ static int cnt_pass(struct sess *sp) { - PassSession(sp->wrk, sp); + PassSession(sp); sp->step = STP_PASSBODY; return (0); } diff --git a/varnish-cache/bin/varnishd/cache_hash.c b/varnish-cache/bin/varnishd/cache_hash.c index fb11aa7e..f18b87b3 100644 --- a/varnish-cache/bin/varnishd/cache_hash.c +++ b/varnish-cache/bin/varnishd/cache_hash.c @@ -77,7 +77,7 @@ HSH_Lookup(struct sess *sp) } else CHECK_OBJ_NOTNULL(w->nobj, OBJECT_MAGIC); - url = h->hd[HTTP_HDR_URL][HTTP_START]; + url = h->hd[HTTP_HDR_URL].b; if (!http_GetHdr(h, H_Host, &host)) host = url; if (sp->obj != NULL) { diff --git a/varnish-cache/bin/varnishd/cache_http.c b/varnish-cache/bin/varnishd/cache_http.c index 731dccc5..c6d7b929 100644 --- a/varnish-cache/bin/varnishd/cache_http.c +++ b/varnish-cache/bin/varnishd/cache_http.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -19,8 +20,8 @@ #include "http_headers.h" #undef HTTPH -#define VSLH(a, b, c, d) \ - VSLR((a), (b), (c)->hd[d][HTTP_START], (c)->hd[d][HTTP_END]); +#define VSLH(ax, bx, cx, dx) \ + VSLR((ax), (bx), (cx)->hd[(dx)].b, (cx)->hd[(dx)].e); /*--------------------------------------------------------------------*/ @@ -37,6 +38,25 @@ http_Setup(struct http *hp, void *space, unsigned len) hp->v = sp; hp->f = sp; hp->e = sp + len; + hp->nhd = HTTP_HDR_FIRST; +} + +/*--------------------------------------------------------------------*/ + + +int +http_IsHdr(struct http_hdr *hh, char *hdr) +{ + unsigned l; + + assert(hh->b != NULL); + assert(hh->e != NULL); + assert(hdr != NULL); + l = hdr[0]; + assert(l == strlen(hdr + 1)); + assert(hdr[l] == ':'); + hdr++; + return (!strncasecmp(hdr, hh->b, l)); } /*--------------------------------------------------------------------*/ @@ -52,27 +72,26 @@ http_GetHdr(struct http *hp, const char *hdr, char **ptr) assert(hdr[l] == ':'); hdr++; for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) { - assert(hp->hd[u][HTTP_START] != NULL); - assert(hp->hd[u][HTTP_END] != NULL); - if (hp->hd[u][HTTP_END] < hp->hd[u][HTTP_START] + l) + assert(hp->hd[u].b != NULL); + assert(hp->hd[u].e != NULL); + if (hp->hd[u].e < hp->hd[u].b + l) continue; - if (hp->hd[u][HTTP_START][l-1] != ':') + if (hp->hd[u].b[l-1] != ':') continue; - if (strncasecmp(hdr, hp->hd[u][HTTP_START], l)) + if (strncasecmp(hdr, hp->hd[u].b, l)) continue; - if (hp->hd[u][HTTP_DATA] == NULL) { - p = hp->hd[u][HTTP_START] + l; - while (isspace(*p)) - p++; - hp->hd[u][HTTP_DATA] = p; - } - *ptr = hp->hd[u][HTTP_DATA]; + p = hp->hd[u].b + l; + while (isspace(*p)) + p++; + *ptr = p; return (1); } *ptr = NULL; return (0); } +/*--------------------------------------------------------------------*/ + int http_GetHdrField(struct http *hp, const char *hdr, const char *field, char **ptr) { @@ -106,6 +125,8 @@ http_GetHdrField(struct http *hp, const char *hdr, const char *field, char **ptr return (0); } +/*--------------------------------------------------------------------*/ + int http_HdrIs(struct http *hp, const char *hdr, const char *val) { @@ -119,6 +140,8 @@ http_HdrIs(struct http *hp, const char *hdr, const char *val) return (0); } +/*--------------------------------------------------------------------*/ + int http_GetTail(struct http *hp, unsigned len, char **b, char **e) { @@ -140,6 +163,7 @@ http_GetTail(struct http *hp, unsigned len, char **b, char **e) return (1); } +/*--------------------------------------------------------------------*/ /* Read from fd, but soak up any tail first */ int @@ -168,12 +192,14 @@ http_Read(struct http *hp, int fd, void *p, unsigned len) return (u); } +/*--------------------------------------------------------------------*/ + int http_GetStatus(struct http *hp) { - assert(hp->hd[HTTP_HDR_STATUS][HTTP_START] != NULL); - return (strtoul(hp->hd[HTTP_HDR_STATUS][HTTP_START], + assert(hp->hd[HTTP_HDR_STATUS].b != NULL); + return (strtoul(hp->hd[HTTP_HDR_STATUS].b, NULL /* XXX */, 10)); } @@ -211,8 +237,8 @@ http_dissect_hdrs(struct http *hp, int fd, char *p) hp->conds = 1; if (hp->nhd < MAX_HTTP_HDRS) { - hp->hd[hp->nhd][HTTP_START] = p; - hp->hd[hp->nhd][HTTP_END] = q; + hp->hd[hp->nhd].b = p; + hp->hd[hp->nhd].e = q; VSLH(SLT_RxHeader, fd, hp, hp->nhd); hp->nhd++; } else { @@ -239,10 +265,10 @@ http_DissectRequest(struct http *hp, int fd) continue; /* First, the request type (GET/HEAD etc) */ - hp->hd[HTTP_HDR_REQ][HTTP_START] = p; + hp->hd[HTTP_HDR_REQ].b = p; for (; isalpha(*p); p++) ; - hp->hd[HTTP_HDR_REQ][HTTP_END] = p; + hp->hd[HTTP_HDR_REQ].e = p; VSLH(SLT_Request, fd, hp, HTTP_HDR_REQ); *p++ = '\0'; @@ -253,10 +279,10 @@ http_DissectRequest(struct http *hp, int fd) VSLR(SLT_HttpGarbage, fd, hp->s, hp->v); return (400); } - hp->hd[HTTP_HDR_URL][HTTP_START] = p; + hp->hd[HTTP_HDR_URL].b = p; while (!isspace(*p)) p++; - hp->hd[HTTP_HDR_URL][HTTP_END] = p; + hp->hd[HTTP_HDR_URL].e = p; VSLH(SLT_URL, fd, hp, HTTP_HDR_URL); if (*p == '\n') { VSLR(SLT_HttpGarbage, fd, hp->s, hp->v); @@ -271,10 +297,10 @@ http_DissectRequest(struct http *hp, int fd) VSLR(SLT_HttpGarbage, fd, hp->s, hp->v); return (400); } - hp->hd[HTTP_HDR_PROTO][HTTP_START] = p; + hp->hd[HTTP_HDR_PROTO].b = p; while (!isspace(*p)) p++; - hp->hd[HTTP_HDR_PROTO][HTTP_END] = p; + hp->hd[HTTP_HDR_PROTO].e = p; VSLH(SLT_Protocol, fd, hp, HTTP_HDR_PROTO); if (*p != '\n') *p++ = '\0'; @@ -303,34 +329,34 @@ http_DissectResponse(struct http *hp, int fd) continue; /* First, protocol */ - hp->hd[HTTP_HDR_PROTO][HTTP_START] = p; + hp->hd[HTTP_HDR_PROTO].b = p; while (!isspace(*p)) p++; - hp->hd[HTTP_HDR_PROTO][HTTP_END] = p; + hp->hd[HTTP_HDR_PROTO].e = p; VSLH(SLT_Protocol, fd, hp, HTTP_HDR_PROTO); *p++ = '\0'; /* Next find the status */ while (isspace(*p)) p++; - hp->hd[HTTP_HDR_STATUS][HTTP_START] = p; + hp->hd[HTTP_HDR_STATUS].b = p; while (!isspace(*p)) p++; - hp->hd[HTTP_HDR_STATUS][HTTP_END] = p; + hp->hd[HTTP_HDR_STATUS].e = p; VSLH(SLT_Status, fd, hp, HTTP_HDR_STATUS); *p++ = '\0'; /* Next find the response */ while (isspace(*p)) p++; - hp->hd[HTTP_HDR_RESPONSE][HTTP_START] = p; + hp->hd[HTTP_HDR_RESPONSE].b = p; while (*p != '\n') p++; - for (q = p; q > hp->hd[HTTP_HDR_RESPONSE][HTTP_START] && + for (q = p; q > hp->hd[HTTP_HDR_RESPONSE].b && isspace(q[-1]); q--) continue; *q = '\0'; - hp->hd[HTTP_HDR_RESPONSE][HTTP_END] = q; + hp->hd[HTTP_HDR_RESPONSE].e = q; VSLH(SLT_Response, fd, hp, HTTP_HDR_RESPONSE); p++; @@ -375,8 +401,6 @@ http_header_complete(struct http *hp) /*--------------------------------------------------------------------*/ -#include - static void http_read_f(int fd, short event, void *arg) { @@ -484,6 +508,130 @@ http_supress(const char *hdr, int flag) /*--------------------------------------------------------------------*/ +static void +http_copyh(int fd, struct http *to, struct http *fm, unsigned n, enum shmlogtag tag) +{ + + assert(n < MAX_HTTP_HDRS); + assert(fm->hd[n].b != NULL); + to->hd[n].b = fm->hd[n].b; + to->hd[n].e = fm->hd[n].e; + VSLH(tag, fd, to, n); +} + +void +http_CopyReq(int fd, struct http *to, struct http *fm) +{ + + CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC); + CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); + http_copyh(fd, to, fm, HTTP_HDR_REQ, SLT_Request); + http_copyh(fd, to, fm, HTTP_HDR_URL, SLT_URL); + http_copyh(fd, to, fm, HTTP_HDR_PROTO, SLT_Protocol); +} + + +void +http_CopyResp(int fd, struct http *to, struct http *fm) +{ + + CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC); + CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); + http_copyh(fd, to, fm, HTTP_HDR_PROTO, SLT_Protocol); + http_copyh(fd, to, fm, HTTP_HDR_STATUS, SLT_Status); + http_copyh(fd, to, fm, HTTP_HDR_RESPONSE, SLT_Response); +} + +void +http_CopyHeader(int fd, struct http *to, struct http *fm, unsigned n) +{ + + CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC); + CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); + assert(n < MAX_HTTP_HDRS); + assert(fm->hd[n].b != NULL); + if (to->nhd < MAX_HTTP_HDRS) { + to->hd[to->nhd].b = fm->hd[n].b; + to->hd[to->nhd].e = fm->hd[n].e; + VSLH(SLT_TxHeader, fd, to, to->nhd); + to->nhd++; + } else { + VSL_stats->losthdr++; + VSLH(SLT_LostHeader, fd, fm, n); + } +} + +/*--------------------------------------------------------------------*/ + +void +http_FilterHeader(int fd, struct http *to, struct http *fm, unsigned how) +{ + unsigned u; + + to->nhd = HTTP_HDR_FIRST; + for (u = HTTP_HDR_FIRST; u < fm->nhd; u++) { +#define HTTPH(a, b, c, d, e, f, g) \ + if (((e) & how) && http_IsHdr(&fm->hd[u], (b))) \ + continue; +#include "http_headers.h" +#undef HTTPH + http_CopyHeader(fd, to, fm, u); + } +} + +/*--------------------------------------------------------------------*/ + +void +http_PrintfHeader(int fd, struct http *to, const char *fmt, ...) +{ + va_list ap; + unsigned l, n; + + va_start(ap, fmt); + l = to->e - to->f; + n = vsnprintf(to->f, l, fmt, ap); + if (n + 1 > l || to->nhd >= MAX_HTTP_HDRS) { + VSL_stats->losthdr++; + VSL(SLT_LostHeader, fd, "%s", to->f); + } else { + assert(to->f < to->e); + to->hd[to->nhd].b = to->f; + to->hd[to->nhd].e = to->f + n; + to->f += n + 1; + VSLH(SLT_TxHeader, fd, to, to->nhd); + to->nhd++; + } + va_end(ap); +} + +/*--------------------------------------------------------------------*/ + +void +http_Write(struct worker *w, struct http *hp, int resp) +{ + unsigned u; + + if (resp) { + assert(hp->hd[HTTP_HDR_STATUS].b != NULL); + WRK_WriteH(w, &hp->hd[HTTP_HDR_PROTO], "\r\n"); + WRK_WriteH(w, &hp->hd[HTTP_HDR_STATUS], " "); + WRK_WriteH(w, &hp->hd[HTTP_HDR_RESPONSE], " "); + } else { + assert(hp->hd[HTTP_HDR_URL].b != NULL); + WRK_WriteH(w, &hp->hd[HTTP_HDR_REQ], " "); + WRK_WriteH(w, &hp->hd[HTTP_HDR_URL], " "); + WRK_WriteH(w, &hp->hd[HTTP_HDR_PROTO], "\r\n"); + } + for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) { + assert(hp->hd[u].b != NULL); + assert(hp->hd[u].e != NULL); + WRK_WriteH(w, &hp->hd[u], "\r\n"); + } + WRK_Write(w, "\r\n", -1); +} + +/*--------------------------------------------------------------------*/ + void http_BuildSbuf(int fd, enum http_build mode, struct sbuf *sb, struct http *hp) { @@ -503,31 +651,29 @@ http_BuildSbuf(int fd, enum http_build mode, struct sbuf *sb, struct http *hp) assert(__LINE__ == 0); } if (rr == 0) { - sbuf_cat(sb, hp->hd[HTTP_HDR_PROTO][HTTP_START]); + sbuf_cat(sb, hp->hd[HTTP_HDR_PROTO].b); sbuf_cat(sb, " "); - sbuf_cat(sb, hp->hd[HTTP_HDR_STATUS][HTTP_START]); + sbuf_cat(sb, hp->hd[HTTP_HDR_STATUS].b); sbuf_cat(sb, " "); - sbuf_cat(sb, hp->hd[HTTP_HDR_RESPONSE][HTTP_START]); + sbuf_cat(sb, hp->hd[HTTP_HDR_RESPONSE].b); } else { if (rr == 2) { sbuf_cat(sb, "GET "); } else { - sbuf_cat(sb, hp->hd[HTTP_HDR_REQ][HTTP_START]); + sbuf_cat(sb, hp->hd[HTTP_HDR_REQ].b); sbuf_cat(sb, " "); } - sbuf_cat(sb, hp->hd[HTTP_HDR_URL][HTTP_START]); + sbuf_cat(sb, hp->hd[HTTP_HDR_URL].b); sbuf_cat(sb, " "); - sbuf_cat(sb, hp->hd[HTTP_HDR_PROTO][HTTP_START]); + sbuf_cat(sb, hp->hd[HTTP_HDR_PROTO].b); } sbuf_cat(sb, "\r\n"); for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) { - if (http_supress(hp->hd[u][HTTP_START], sup)) + if (http_supress(hp->hd[u].b, sup)) continue; - if (1) - VSL(SLT_TxHeader, fd, "%s", hp->hd[u][HTTP_START]); - sbuf_cat(sb, hp->hd[u][HTTP_START]); + sbuf_cat(sb, hp->hd[u].b); sbuf_cat(sb, "\r\n"); } if (mode != Build_Reply) { diff --git a/varnish-cache/bin/varnishd/cache_pass.c b/varnish-cache/bin/varnishd/cache_pass.c index 14c33e9b..fbb46350 100644 --- a/varnish-cache/bin/varnishd/cache_pass.c +++ b/varnish-cache/bin/varnishd/cache_pass.c @@ -46,8 +46,9 @@ pass_straight(struct sess *sp, int fd, struct http *hp, char *bi) if (i == 0 && bi == NULL) return (1); assert(i > 0); - RES_Write(sp, buf, i); - RES_Flush(sp); + WRK_Write(sp->wrk, buf, i); + if (WRK_Flush(sp->wrk)) + vca_close_session(sp, "remote closed"); cl -= i; } return (0); @@ -92,7 +93,7 @@ pass_chunked(struct sess *sp, int fd, struct http *hp) if (u == 0) break; - RES_Write(sp, p, q - p); + WRK_Write(sp->wrk, p, q - p); p = q; @@ -104,28 +105,30 @@ pass_chunked(struct sess *sp, int fd, struct http *hp) } if (bp - p < j) j = bp - p; - RES_Write(sp, p, j); + WRK_Write(sp->wrk, p, j); p += j; u -= j; } while (u > 0) { if (http_GetTail(hp, u, &b, &e)) { j = e - b; - RES_Write(sp, q, j); + WRK_Write(sp->wrk, q, j); u -= j; } else break; } - RES_Flush(sp); + if (WRK_Flush(sp->wrk)) + vca_close_session(sp, "remote closed"); while (u > 0) { j = u; if (j > sizeof buf) j = sizeof buf; i = read(fd, buf, j); assert(i > 0); - RES_Write(sp, buf, i); + WRK_Write(sp->wrk, buf, i); u -= i; - RES_Flush(sp); + if (WRK_Flush(sp->wrk)) + vca_close_session(sp, "remote closed"); } } return (0); @@ -138,32 +141,34 @@ void PassBody(struct worker *w, struct sess *sp) { struct vbe_conn *vc; - struct http *hp; char *b; int cls; - hp = sp->bkd_http; - assert(hp != NULL); vc = sp->vbc; assert(vc != NULL); - http_BuildSbuf(sp->fd, Build_Reply, w->sb, hp); - sbuf_cat(w->sb, "\r\n"); - sbuf_finish(w->sb); - RES_Write(sp, sbuf_data(w->sb), sbuf_len(w->sb)); - - if (http_GetHdr(hp, H_Content_Length, &b)) - cls = pass_straight(sp, vc->fd, hp, b); - else if (http_HdrIs(hp, H_Connection, "close")) - cls = pass_straight(sp, vc->fd, hp, NULL); - else if (http_HdrIs(hp, H_Transfer_Encoding, "chunked")) - cls = pass_chunked(sp, vc->fd, hp); + sp->http->f = sp->http->v; + sp->http->nhd = HTTP_HDR_FIRST; + http_CopyResp(sp->fd, sp->http, vc->http); + http_FilterHeader(sp->fd, sp->http, vc->http, HTTPH_A_PASS); + http_PrintfHeader(sp->fd, sp->http, "X-Varnish: %u", sp->xid); + WRK_Reset(w, &sp->fd); + http_Write(w, sp->http, 1); + + if (http_GetHdr(vc->http, H_Content_Length, &b)) + cls = pass_straight(sp, vc->fd, vc->http, b); + else if (http_HdrIs(vc->http, H_Connection, "close")) + cls = pass_straight(sp, vc->fd, vc->http, NULL); + else if (http_HdrIs(vc->http, H_Transfer_Encoding, "chunked")) + cls = pass_chunked(sp, vc->fd, vc->http); else { - cls = pass_straight(sp, vc->fd, hp, NULL); + cls = pass_straight(sp, vc->fd, vc->http, NULL); } - RES_Flush(sp); - if (http_GetHdr(hp, H_Connection, &b) && !strcasecmp(b, "close")) + if (WRK_Flush(w)) + vca_close_session(sp, "remote closed"); + + if (http_GetHdr(vc->http, H_Connection, &b) && !strcasecmp(b, "close")) cls = 1; if (cls) @@ -172,21 +177,31 @@ PassBody(struct worker *w, struct sess *sp) VBE_RecycleFd(vc); } + /*--------------------------------------------------------------------*/ + void -PassSession(struct worker *w, struct sess *sp) +PassSession(struct sess *sp) { int i; struct vbe_conn *vc; struct http *hp; + struct worker *w; + CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); + CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC); + w = sp->wrk; vc = VBE_GetFd(sp->backend, sp->xid); assert(vc != NULL); VSL(SLT_Backend, sp->fd, "%d %s", vc->fd, sp->backend->vcl_name); - http_BuildSbuf(vc->fd, Build_Pass, w->sb, sp->http); - i = write(vc->fd, sbuf_data(w->sb), sbuf_len(w->sb)); - assert(i == sbuf_len(w->sb)); + http_CopyReq(vc->fd, vc->http, sp->http); + http_FilterHeader(vc->fd, vc->http, sp->http, HTTPH_R_PASS); + http_PrintfHeader(vc->fd, vc->http, "X-Varnish: %u", sp->xid); + WRK_Reset(w, &vc->fd); + http_Write(w, vc->http, 0); + i = WRK_Flush(w); + assert(i == 0); /* XXX: copy any contents */ diff --git a/varnish-cache/bin/varnishd/cache_pool.c b/varnish-cache/bin/varnishd/cache_pool.c index 4bed37bc..31b730e0 100644 --- a/varnish-cache/bin/varnishd/cache_pool.c +++ b/varnish-cache/bin/varnishd/cache_pool.c @@ -24,6 +24,73 @@ static unsigned wrk_overflow; static TAILQ_HEAD(, worker) wrk_head = TAILQ_HEAD_INITIALIZER(wrk_head); static TAILQ_HEAD(, workreq) wrk_reqhead = TAILQ_HEAD_INITIALIZER(wrk_reqhead); +/*-------------------------------------------------------------------- + * Write data to fd + * We try to use writev() if possible in order to minimize number of + * syscalls made and packets sent. It also just might allow the worker + * thread to complete the request without holding stuff locked. + */ + +void +WRK_Reset(struct worker *w, int *fd) +{ + + CHECK_OBJ_NOTNULL(w, WORKER_MAGIC); + w->werr = 0; + w->liov = 0; + w->niov = 0; + w->wfd = fd; +} + +int +WRK_Flush(struct worker *w) +{ + int i; + + CHECK_OBJ_NOTNULL(w, WORKER_MAGIC); + if (*w->wfd < 0 || w->niov == 0 || w->werr) + return (w->werr); +VSL(SLT_Debug, 0, "%s %d", __func__, *w->wfd); + i = writev(*w->wfd, w->iov, w->niov); + if (i != w->liov) + w->werr++; + else { + w->liov = 0; + w->niov = 0; + } + return (w->werr); +} + +void +WRK_WriteH(struct worker *w, struct http_hdr *hh, const char *suf) +{ + + CHECK_OBJ_NOTNULL(w, WORKER_MAGIC); + assert(w != NULL); + assert(hh != NULL); + assert(hh->b != NULL); + assert(hh->e != NULL); + WRK_Write(w, hh->b, hh->e - hh->b); + if (suf != NULL) + WRK_Write(w, suf, -1); +} + +void +WRK_Write(struct worker *w, const void *ptr, size_t len) +{ + + CHECK_OBJ_NOTNULL(w, WORKER_MAGIC); + if (len == 0 || *w->wfd < 0) + return; + if (len == -1) + len = strlen(ptr); + if (w->niov == MAX_IOVS) + WRK_Flush(w); + w->iov[w->niov].iov_base = (void*)(uintptr_t)ptr; + w->iov[w->niov++].iov_len = len; + w->liov += len; +} + /*--------------------------------------------------------------------*/ static void diff --git a/varnish-cache/bin/varnishd/cache_response.c b/varnish-cache/bin/varnishd/cache_response.c index 38bd09ac..594a75d7 100644 --- a/varnish-cache/bin/varnishd/cache_response.c +++ b/varnish-cache/bin/varnishd/cache_response.c @@ -65,50 +65,12 @@ RES_Error(struct sess *sp, int error, const char *msg) " \r\n" "\r\n"); sbuf_finish(sb); - RES_Write(sp, sbuf_data(sb), sbuf_len(sb)); - RES_Flush(sp); + WRK_Write(sp->wrk, sbuf_data(sb), sbuf_len(sb)); + WRK_Flush(sp->wrk); vca_close_session(sp, msg); } -/*-------------------------------------------------------------------- - * Write data to client - * We try to use writev() if possible in order to minimize number of - * syscalls made and packets sent. It also just might allow the worker - * thread to complete the request without holding stuff locked. - */ - -void -RES_Flush(struct sess *sp) -{ - int i; - - if (sp->fd < 0 || sp->wrk->niov == 0) - return; - i = writev(sp->fd, sp->wrk->iov, sp->wrk->niov); - if (i != sp->wrk->liov) - vca_close_session(sp, "remote closed"); - sp->wrk->liov = 0; - sp->wrk->niov = 0; -} - -void -RES_Write(struct sess *sp, const void *ptr, size_t len) -{ - - if (sp->fd < 0 || len == 0) - return; - if (len == -1) - len = strlen(ptr); - if (sp->wrk->niov == MAX_IOVS) - RES_Flush(sp); - if (sp->fd < 0) - return; - sp->wrk->iov[sp->wrk->niov].iov_base = (void*)(uintptr_t)ptr; - sp->wrk->iov[sp->wrk->niov++].iov_len = len; - sp->wrk->liov += len; -} - /*--------------------------------------------------------------------*/ static void @@ -121,18 +83,18 @@ res_do_304(struct sess *sp, char *p) VSL(SLT_Status, sp->fd, "%u", 304); VSL(SLT_Length, sp->fd, "%u", 0); - RES_Write(sp, "HTTP/1.1 304 Not Modified\r\n", -1); - RES_Write(sp, "Via: 1.1 varnish\r\n", -1); - RES_Write(sp, "Last-Modified: ", -1); - RES_Write(sp, p, -1); - RES_Write(sp, "\r\n", -1); - if (strcmp(sp->http->hd[HTTP_HDR_PROTO][HTTP_START], "HTTP/1.1")) - RES_Write(sp, "Connection: close\r\n", -1); + WRK_Write(sp->wrk, "HTTP/1.1 304 Not Modified\r\n", -1); + WRK_Write(sp->wrk, "Via: 1.1 varnish\r\n", -1); + WRK_Write(sp->wrk, "Last-Modified: ", -1); + WRK_Write(sp->wrk, p, -1); + WRK_Write(sp->wrk, "\r\n", -1); + if (strcmp(sp->http->hd[HTTP_HDR_PROTO].b, "HTTP/1.1")) + WRK_Write(sp->wrk, "Connection: close\r\n", -1); sbuf_printf(sb, "X-Varnish: xid %u\r\n", sp->obj->xid); sbuf_printf(sb, "\r\n"); sbuf_finish(sb); - RES_Write(sp, sbuf_data(sb), sbuf_len(sb)); - RES_Flush(sp); + WRK_Write(sp->wrk, sbuf_data(sb), sbuf_len(sb)); + WRK_Flush(sp->wrk); } /*--------------------------------------------------------------------*/ @@ -180,26 +142,26 @@ RES_WriteObj(struct sess *sp) VSL(SLT_Status, sp->fd, "%u", sp->obj->response); VSL(SLT_Length, sp->fd, "%u", sp->obj->len); - RES_Write(sp, sp->obj->header, strlen(sp->obj->header)); + WRK_Write(sp->wrk, sp->obj->header, strlen(sp->obj->header)); sbuf_clear(sb); sbuf_printf(sb, "Age: %u\r\n", sp->obj->age + sp->t_req - sp->obj->entered); sbuf_printf(sb, "Via: 1.1 varnish\r\n"); sbuf_printf(sb, "X-Varnish: xid %u\r\n", sp->obj->xid); - if (strcmp(sp->http->hd[HTTP_HDR_PROTO][HTTP_START], "HTTP/1.1")) + if (strcmp(sp->http->hd[HTTP_HDR_PROTO].b, "HTTP/1.1")) sbuf_printf(sb, "Connection: close\r\n"); sbuf_printf(sb, "\r\n"); sbuf_finish(sb); - RES_Write(sp, sbuf_data(sb), sbuf_len(sb)); + WRK_Write(sp->wrk, sbuf_data(sb), sbuf_len(sb)); bytes += sbuf_len(sb); /* XXX: conditional request handling */ - if (!strcmp(sp->http->hd[HTTP_HDR_REQ][HTTP_START], "GET")) { + if (!strcmp(sp->http->hd[HTTP_HDR_REQ].b, "GET")) { TAILQ_FOREACH(st, &sp->obj->store, list) { assert(st->stevedore != NULL); u += st->len; if (st->stevedore->send == NULL) { - RES_Write(sp, st->ptr, st->len); + WRK_Write(sp->wrk, st->ptr, st->len); continue; } st->stevedore->send(st, sp, @@ -210,5 +172,5 @@ RES_WriteObj(struct sess *sp) assert(u == sp->obj->len); } SES_ChargeBytes(sp, bytes + u); - RES_Flush(sp); + WRK_Flush(sp->wrk); } diff --git a/varnish-cache/bin/varnishd/cache_vrt.c b/varnish-cache/bin/varnishd/cache_vrt.c index 9aa02eb1..d913c589 100644 --- a/varnish-cache/bin/varnishd/cache_vrt.c +++ b/varnish-cache/bin/varnishd/cache_vrt.c @@ -60,7 +60,7 @@ VRT_GetReq(struct sess *sp) CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); assert(sp != NULL); assert(sp->http != NULL); - return (sp->http->hd[HTTP_HDR_REQ][HTTP_START]); + return (sp->http->hd[HTTP_HDR_REQ].b); } /*--------------------------------------------------------------------*/ diff --git a/varnish-cache/include/http_headers.h b/varnish-cache/include/http_headers.h index 10e0415d..2c9ad8c1 100644 --- a/varnish-cache/include/http_headers.h +++ b/varnish-cache/include/http_headers.h @@ -5,7 +5,7 @@ * b session field name * c Request(1)/Response(2) bitfield * d Supress header to backend (1) / Supress header to client (2) - * e unused + * e Supress header in pass from client to backend * f unused * g unused * @@ -15,24 +15,29 @@ *-------------------------------------------------------------------- */ -HTTPH("Keep-Alive", H_Keep_Alive, 3, 3, 0, 0, 0) /* RFC2068 */ +#ifndef HTTPH_R_PASS +#define HTTPH_R_PASS (1 << 0) +#define HTTPH_A_PASS (1 << 1) +#endif + +HTTPH("Keep-Alive", H_Keep_Alive, 3, 3, HTTPH_R_PASS|HTTPH_A_PASS, 0, 0) /* RFC2068 */ HTTPH("Accept", H_Accept, 1, 0, 0, 0, 0) /* RFC2616 14.1 */ HTTPH("Accept-Charset", H_Accept_Charset, 1, 0, 0, 0, 0) /* RFC2616 14.2 */ HTTPH("Accept-Encoding", H_Accept_Encoding, 1, 0, 0, 0, 0) /* RFC2616 14.3 */ HTTPH("Accept-Language", H_Accept_Language, 1, 0, 0, 0, 0) /* RFC2616 14.4 */ -HTTPH("Accept-Ranges", H_Accept_Ranges, 2, 3, 0, 0, 0) /* RFC2616 14.5 */ +HTTPH("Accept-Ranges", H_Accept_Ranges, 2, 3, HTTPH_R_PASS|HTTPH_A_PASS, 0, 0) /* RFC2616 14.5 */ HTTPH("Age", H_Age, 2, 0, 0, 0, 0) /* RFC2616 14.6 */ HTTPH("Allow", H_Allow, 2, 0, 0, 0, 0) /* RFC2616 14.7 */ HTTPH("Authorization", H_Authorization, 1, 0, 0, 0, 0) /* RFC2616 14.8 */ -HTTPH("Cache-Control", H_Cache_Control, 3, 3, 0, 0, 0) /* RFC2616 14.9 */ -HTTPH("Connection", H_Connection, 3, 3, 0, 0, 0) /* RFC2616 14.10 */ +HTTPH("Cache-Control", H_Cache_Control, 3, 3, HTTPH_R_PASS|HTTPH_A_PASS, 0, 0) /* RFC2616 14.9 */ +HTTPH("Connection", H_Connection, 3, 3, HTTPH_R_PASS|HTTPH_A_PASS, 0, 0) /* RFC2616 14.10 */ HTTPH("Content-Encoding", H_Content_Encoding, 2, 0, 0, 0, 0) /* RFC2616 14.11 */ HTTPH("Content-Langugae", H_Content_Language, 2, 0, 0, 0, 0) /* RFC2616 14.12 */ HTTPH("Content-Length", H_Content_Length, 2, 2, 0, 0, 0) /* RFC2616 14.13 */ HTTPH("Content-Location", H_Content_Location, 2, 0, 0, 0, 0) /* RFC2616 14.14 */ HTTPH("Content-MD5", H_Content_MD5, 2, 0, 0, 0, 0) /* RFC2616 14.15 */ -HTTPH("Content-Range", H_Content_Range, 2, 3, 0, 0, 0) /* RFC2616 14.16 */ +HTTPH("Content-Range", H_Content_Range, 2, 3, HTTPH_R_PASS|HTTPH_A_PASS, 0, 0) /* RFC2616 14.16 */ HTTPH("Content-Type", H_Content_Type, 2, 0, 0, 0, 0) /* RFC2616 14.17 */ HTTPH("Date", H_Date, 2, 0, 0, 0, 0) /* RFC2616 14.18 */ HTTPH("ETag", H_ETag, 2, 0, 0, 0, 0) /* RFC2616 14.19 */ @@ -55,10 +60,10 @@ HTTPH("Range", H_Range, 1, 0, 0, 0, 0) /* RFC2616 14.35 */ HTTPH("Referer", H_Referer, 1, 0, 0, 0, 0) /* RFC2616 14.36 */ HTTPH("Retry-After", H_Retry_After, 2, 0, 0, 0, 0) /* RFC2616 14.37 */ HTTPH("Server", H_Server, 2, 0, 0, 0, 0) /* RFC2616 14.38 */ -HTTPH("TE", H_TE, 1, 3, 0, 0, 0) /* RFC2616 14.39 */ -HTTPH("Trailer", H_Trailer, 1, 3, 0, 0, 0) /* RFC2616 14.40 */ -HTTPH("Transfer-Encoding", H_Transfer_Encoding, 2, 3, 0, 0, 0) /* RFC2616 14.41 */ -HTTPH("Upgrade", H_Upgrade, 2, 3, 0, 0, 0) /* RFC2616 14.42 */ +HTTPH("TE", H_TE, 1, 3, HTTPH_R_PASS|HTTPH_A_PASS, 0, 0) /* RFC2616 14.39 */ +HTTPH("Trailer", H_Trailer, 1, 3, HTTPH_R_PASS|HTTPH_A_PASS, 0, 0) /* RFC2616 14.40 */ +HTTPH("Transfer-Encoding", H_Transfer_Encoding, 2, 3, HTTPH_R_PASS|HTTPH_A_PASS, 0, 0) /* RFC2616 14.41 */ +HTTPH("Upgrade", H_Upgrade, 2, 3, HTTPH_R_PASS|HTTPH_A_PASS, 0, 0) /* RFC2616 14.42 */ HTTPH("User-Agent", H_User_Agent, 1, 0, 0, 0, 0) /* RFC2616 14.43 */ HTTPH("Vary", H_Vary, 2, 0, 0, 0, 0) /* RFC2616 14.44 */ HTTPH("Via", H_Via, 2, 0, 0, 0, 0) /* RFC2616 14.45 */