#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
#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;
typedef void http_callback_f(void *, int bad);
+struct http_hdr {
+ char *b;
+ char *e;
+};
+
struct http {
unsigned magic;
#define HTTP_MAGIC 0x6428b5c9
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];
};
/*--------------------------------------------------------------------*/
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;
/* 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);
#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 */
/* 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);
/* 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 */
} 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);
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);
}
HSH_Unbusy(sp->obj);
HSH_Deref(sp->obj);
sp->obj = 0;
- PassSession(sp->wrk, sp);
+ PassSession(sp);
sp->step = STP_PASSBODY;
return (0);
}
cnt_pass(struct sess *sp)
{
- PassSession(sp->wrk, sp);
+ PassSession(sp);
sp->step = STP_PASSBODY;
return (0);
}
} 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) {
*/
#include <stdio.h>
+#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#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);
/*--------------------------------------------------------------------*/
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));
}
/*--------------------------------------------------------------------*/
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)
{
return (0);
}
+/*--------------------------------------------------------------------*/
+
int
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)
{
return (1);
}
+/*--------------------------------------------------------------------*/
/* Read from fd, but soak up any tail first */
int
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));
}
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 {
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';
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);
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';
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++;
/*--------------------------------------------------------------------*/
-#include <errno.h>
-
static void
http_read_f(int fd, short event, void *arg)
{
/*--------------------------------------------------------------------*/
+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)
{
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) {
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);
if (u == 0)
break;
- RES_Write(sp, p, q - p);
+ WRK_Write(sp->wrk, p, q - p);
p = q;
}
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);
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)
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 */
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
" </BODY>\r\n"
"</HTML>\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
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);
}
/*--------------------------------------------------------------------*/
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,
assert(u == sp->obj->len);
}
SES_ChargeBytes(sp, bytes + u);
- RES_Flush(sp);
+ WRK_Flush(sp->wrk);
}
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);
}
/*--------------------------------------------------------------------*/
* 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
*
*--------------------------------------------------------------------
*/
-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 */
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 */