#define MAX_IOVS 10
+#define MAX_HTTP_HDRS 32
+
+#define HTTP_HDR_REQ 0
+#define HTTP_HDR_URL 1
+#define HTTP_HDR_PROTO 2
+#define HTTP_HDR_STATUS 3
+#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;
http_callback_f *callback;
void *arg;
- char *s; /* start of buffer */
- char *t; /* start of trailing data */
- char *v; /* end of valid bytes */
- char *e; /* end of buffer */
-
- char *req;
- char *url;
- char *proto;
- char *status;
- char *response;
+ char *s; /* (S)tart of buffer */
+ char *t; /* start of (T)railing data */
+ char *v; /* end of (V)alid bytes */
+ char *f; /* first (F)ree byte */
+ char *e; /* (E)nd of buffer */
unsigned conds; /* If-* headers present */
-
- unsigned nhdr;
- char **hdr;
+
+ char *hd[MAX_HTTP_HDRS][HTTP_END + 1];
+ unsigned nhd;
};
/*--------------------------------------------------------------------*/
void HSH_Init(void);
/* cache_http.c */
-void http_Init(struct http *ht, void *space);
+void HTTP_Init(void);
+void http_Init(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);
int http_GetStatus(struct http *hp);
Build_Reply
};
void http_BuildSbuf(int fd, enum http_build mode, struct sbuf *sb, struct http *hp);
+#define HTTPH(a, b, c, d, e, f, g) extern char b[];
+#include "http_headers.h"
+#undef HTTPH
/* cache_pass.c */
void PassSession(struct worker *w, struct sess *sp);
#define VBC_MEM_MAGIC 0x2fd7af01
struct vbe_conn vbe;
struct http http;
- char *http_hdr;
};
/* A backend IP */
{
struct vbc_mem *vbcm;
- vbcm = calloc(
- sizeof *vbcm +
- heritage.mem_http_headers * sizeof vbcm->http_hdr +
- heritage.mem_http_headerspace +
- heritage.mem_workspace,
- 1);
+ vbcm = calloc(sizeof *vbcm + heritage.mem_workspace, 1);
if (vbcm == NULL)
return (NULL);
vbcm->magic = VBC_MEM_MAGIC;
vbcm->vbe.magic = VBE_CONN_MAGIC;
vbcm->vbe.vbcm = vbcm;
vbcm->vbe.http = &vbcm->http;
- http_Init(&vbcm->http, (void *)(vbcm + 1));
+ http_Init(&vbcm->http, (void *)(vbcm + 1), heritage.mem_workspace);
return (&vbcm->vbe);
}
assert(sp->obj == NULL);
if (sp->fd < 0) {
/* Allready closed */
- } else if (http_GetHdr(sp->http, "Connection", &b) &&
+ } else if (http_GetHdr(sp->http, H_Connection, &b) &&
!strcmp(b, "close")) {
vca_close_session(sp, "Connection header");
- } else if (strcmp(sp->http->proto, "HTTP/1.1")) {
+ } else if (strcmp(sp->http->hd[HTTP_HDR_PROTO][HTTP_START],
+ "HTTP/1.1")) {
vca_close_session(sp, "not HTTP/1.1");
}
VCL_Rel(sp->vcl);
vc = sp->vbc;
hp = sp->bkd_http;
- if (http_GetHdr(hp, "Last-Modified", &b))
+ if (http_GetHdr(hp, H_Last_Modified, &b))
sp->obj->last_modified = TIM_parse(b);
http_BuildSbuf(sp->fd, Build_Reply, w->sb, hp);
if (body) {
- if (http_GetHdr(hp, "Content-Length", &b))
+ if (http_GetHdr(hp, H_Content_Length, &b))
cls = fetch_straight(sp, vc->fd, hp, b);
- else if (http_HdrIs(hp, "Transfer-Encoding", "chunked"))
+ else if (http_HdrIs(hp, H_Transfer_Encoding, "chunked"))
cls = fetch_chunked(sp, vc->fd, hp);
else
cls = fetch_eof(sp, vc->fd, hp);
sp->obj->header = strdup(sbuf_data(w->sb));
VSL_stats->n_header++;
- if (http_GetHdr(hp, "Connection", &b) && !strcasecmp(b, "close"))
+ if (http_GetHdr(hp, H_Connection, &b) && !strcasecmp(b, "close"))
cls = 1;
if (cls)
struct http *h;
struct objhead *oh;
struct object *o;
- char *c;
+ char *url, *host;
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
} else
CHECK_OBJ_NOTNULL(w->nobj, OBJECT_MAGIC);
- if (!http_GetHdr(h, "Host", &c))
- c = h->url;
+ url = h->hd[HTTP_HDR_URL][HTTP_START];
+ if (!http_GetHdr(h, H_Host, &host))
+ host = url;
if (sp->obj != NULL) {
CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
o = sp->obj;
AZ(pthread_mutex_lock(&oh->mtx));
goto were_back;
}
- oh = hash->lookup(h->url, c, w->nobjhead);
+ oh = hash->lookup(url, host, w->nobjhead);
CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
if (oh == w->nobjhead)
w->nobjhead = NULL;
/* Object banned but not reaped yet */
} else if (o->ttl < sp->t_req) {
/* Object expired */
- } else if (BAN_CheckObject(o, h->url)) {
+ } else if (BAN_CheckObject(o, url)) {
o->ttl = 0;
VSL(SLT_ExpBan, 0, "%u was banned", o->xid);
EXP_TTLchange(o);
#include "heritage.h"
#include "cache.h"
+#define HTTPH(a, b, c, d, e, f, g) char b[] = "*" a ":";
+#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]);
+
/*--------------------------------------------------------------------*/
void
-http_Init(struct http *hp, void *space)
+http_Init(struct http *hp, void *space, unsigned len)
{
char *sp = space;
+ assert(len > 0);
memset(hp, 0, sizeof *hp);
hp->magic = HTTP_MAGIC;
- hp->hdr = (void *)sp;
- sp += heritage.mem_http_headers * sizeof hp->hdr;
hp->s = sp;
- hp->e = hp->s + heritage.mem_http_headerspace;
+ hp->t = sp;
+ hp->v = sp;
+ hp->f = sp;
+ hp->e = sp + len;
}
/*--------------------------------------------------------------------*/
unsigned u, l;
char *p;
- l = strlen(hdr);
- for (u = 0; u < hp->nhdr; u++) {
- if (strncasecmp(hdr, hp->hdr[u], l))
+ 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][HTTP_START] != NULL);
+ assert(hp->hd[u][HTTP_END] != NULL);
+ if (hp->hd[u][HTTP_END] < hp->hd[u][HTTP_START] + l)
continue;
- p = hp->hdr[u];
- if (p[l] != ':')
+ if (hp->hd[u][HTTP_START][l-1] != ':')
continue;
- p += l + 1;
- while (isspace(*p))
- p++;
- *ptr = p;
+ if (strncasecmp(hdr, hp->hd[u][HTTP_START], 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];
return (1);
}
+ *ptr = NULL;
return (0);
}
http_GetStatus(struct http *hp)
{
- return (strtoul(hp->status, NULL /* XXX */, 10));
+ assert(hp->hd[HTTP_HDR_STATUS][HTTP_START] != NULL);
+ return (strtoul(hp->hd[HTTP_HDR_STATUS][HTTP_START],
+ NULL /* XXX */, 10));
}
/*--------------------------------------------------------------------
if (*p == '\r')
p++;
- hp->nhdr = 0;
+ hp->nhd = HTTP_HDR_FIRST;
hp->conds = 0;
r = NULL; /* For FlexeLint */
assert(p < hp->v); /* http_header_complete() guarantees this */
for (; p < hp->v; p = r) {
+ /* XXX: handle continuation lines */
q = strchr(p, '\n');
assert(q != NULL);
r = q + 1;
p[2] == '-')
hp->conds = 1;
- if (hp->nhdr < heritage.mem_http_headers) {
- hp->hdr[hp->nhdr++] = p;
- VSLR(SLT_Header, fd, p, q);
+ if (hp->nhd < MAX_HTTP_HDRS) {
+ hp->hd[hp->nhd][HTTP_START] = p;
+ hp->hd[hp->nhd][HTTP_END] = q;
+ VSLH(SLT_Header, fd, hp, hp->nhd);
+ hp->nhd++;
} else {
VSL_stats->losthdr++;
VSLR(SLT_LostHeader, fd, p, q);
}
}
assert(hp->t <= hp->v);
- if (hp->t != r)
- printf("hp->t %p r %p\n", hp->t, r);
assert(hp->t == r);
return (0);
}
continue;
/* First, the request type (GET/HEAD etc) */
- hp->req = p;
+ hp->hd[HTTP_HDR_REQ][HTTP_START] = p;
for (; isalpha(*p); p++)
;
- VSLR(SLT_Request, fd, hp->req, p);
+ hp->hd[HTTP_HDR_REQ][HTTP_END] = p;
+ VSLH(SLT_Request, fd, hp, HTTP_HDR_REQ);
*p++ = '\0';
/* Next find the URI */
while (isspace(*p) && *p != '\n')
p++;
if (*p == '\n') {
- VSLR(SLT_Debug, fd, hp->s, hp->v);
+ VSLR(SLT_HttpGarbage, fd, hp->s, hp->v);
return (400);
}
- hp->url = p;
+ hp->hd[HTTP_HDR_URL][HTTP_START] = p;
while (!isspace(*p))
p++;
- VSLR(SLT_URL, fd, hp->url, p);
+ hp->hd[HTTP_HDR_URL][HTTP_END] = p;
+ VSLH(SLT_URL, fd, hp, HTTP_HDR_URL);
if (*p == '\n') {
- VSLR(SLT_Debug, fd, hp->s, hp->v);
+ VSLR(SLT_HttpGarbage, fd, hp->s, hp->v);
return (400);
}
*p++ = '\0';
while (isspace(*p) && *p != '\n')
p++;
if (*p == '\n') {
- VSLR(SLT_Debug, fd, hp->s, hp->v);
+ VSLR(SLT_HttpGarbage, fd, hp->s, hp->v);
return (400);
}
- hp->proto = p;
+ hp->hd[HTTP_HDR_PROTO][HTTP_START] = p;
while (!isspace(*p))
p++;
- VSLR(SLT_Protocol, fd, hp->proto, p);
+ hp->hd[HTTP_HDR_PROTO][HTTP_END] = p;
+ VSLH(SLT_Protocol, fd, hp, HTTP_HDR_PROTO);
if (*p != '\n')
*p++ = '\0';
while (isspace(*p) && *p != '\n')
p++;
if (*p != '\n') {
- VSLR(SLT_Debug, fd, hp->s, hp->v);
+ VSLR(SLT_HttpGarbage, fd, hp->s, hp->v);
return (400);
}
*p++ = '\0';
continue;
/* First, protocol */
- hp->proto = p;
+ hp->hd[HTTP_HDR_PROTO][HTTP_START] = p;
while (!isspace(*p))
p++;
- VSLR(SLT_Protocol, fd, hp->proto, p);
+ hp->hd[HTTP_HDR_PROTO][HTTP_END] = p;
+ VSLH(SLT_Protocol, fd, hp, HTTP_HDR_PROTO);
*p++ = '\0';
/* Next find the status */
while (isspace(*p))
p++;
- hp->status = p;
+ hp->hd[HTTP_HDR_STATUS][HTTP_START] = p;
while (!isspace(*p))
p++;
- VSLR(SLT_Status, fd, hp->status, p);
+ hp->hd[HTTP_HDR_STATUS][HTTP_END] = p;
+ VSLH(SLT_Status, fd, hp, HTTP_HDR_STATUS);
*p++ = '\0';
/* Next find the response */
while (isspace(*p))
p++;
- hp->response = p;
+ hp->hd[HTTP_HDR_RESPONSE][HTTP_START] = p;
while (*p != '\n')
p++;
- for (q = p; q > hp->response && isspace(q[-1]); q--)
+ for (q = p; q > hp->hd[HTTP_HDR_RESPONSE][HTTP_START] &&
+ isspace(q[-1]); q--)
continue;
*q = '\0';
- VSLR(SLT_Response, fd, hp->response, q);
+ hp->hd[HTTP_HDR_RESPONSE][HTTP_END] = q;
+ VSLH(SLT_Response, fd, hp, HTTP_HDR_RESPONSE);
p++;
return (http_dissect_hdrs(hp, fd, p));
l = hp->e - hp->v;
if (l <= 1) {
VSL(SLT_HttpError, fd, "Received too much");
- VSLR(SLT_Debug, fd, hp->s, hp->v);
+ VSLR(SLT_HttpGarbage, fd, hp->s, hp->v);
hp->t = NULL;
ret = 1;
} else {
void
http_BuildSbuf(int fd, enum http_build mode, struct sbuf *sb, struct http *hp)
{
- unsigned u, sup;
+ unsigned u, sup, rr;
sbuf_clear(sb);
assert(sb != NULL);
switch (mode) {
- case Build_Reply:
- sbuf_cat(sb, hp->proto);
- sbuf_cat(sb, " ");
- sbuf_cat(sb, hp->status);
- sbuf_cat(sb, " ");
- sbuf_cat(sb, hp->response);
- sup = 2;
- break;
- case Build_Pipe:
- sbuf_cat(sb, hp->req);
- sbuf_cat(sb, " ");
- sbuf_cat(sb, hp->url);
- sbuf_cat(sb, " ");
- sbuf_cat(sb, hp->proto);
- sup = 0;
- break;
- case Build_Pass:
- sbuf_cat(sb, hp->req);
- sbuf_cat(sb, " ");
- sbuf_cat(sb, hp->url);
- sbuf_cat(sb, " ");
- sbuf_cat(sb, hp->proto);
- sup = 2;
- break;
- case Build_Fetch:
- sbuf_cat(sb, "GET ");
- sbuf_cat(sb, hp->url);
- sbuf_cat(sb, " ");
- sbuf_cat(sb, hp->proto);
- sup = 1;
- break;
+ case Build_Reply: rr = 0; sup = 2; break;
+ case Build_Pipe: rr = 1; sup = 0; break;
+ case Build_Pass: rr = 1; sup = 2; break;
+ case Build_Fetch: rr = 2; sup = 1; break;
default:
sup = 0; /* for flexelint */
+ rr = 0; /* for flexelint */
printf("mode = %d\n", mode);
- assert(mode == 1 || mode == 2);
+ assert(__LINE__ == 0);
+ }
+ if (rr == 0) {
+ sbuf_cat(sb, hp->hd[HTTP_HDR_PROTO][HTTP_START]);
+ sbuf_cat(sb, " ");
+ sbuf_cat(sb, hp->hd[HTTP_HDR_STATUS][HTTP_START]);
+ sbuf_cat(sb, " ");
+ sbuf_cat(sb, hp->hd[HTTP_HDR_RESPONSE][HTTP_START]);
+ } else {
+ if (rr == 2) {
+ sbuf_cat(sb, "GET ");
+ } else {
+ sbuf_cat(sb, hp->hd[HTTP_HDR_REQ][HTTP_START]);
+ sbuf_cat(sb, " ");
+ }
+ sbuf_cat(sb, hp->hd[HTTP_HDR_URL][HTTP_START]);
+ sbuf_cat(sb, " ");
+ sbuf_cat(sb, hp->hd[HTTP_HDR_PROTO][HTTP_START]);
}
+
sbuf_cat(sb, "\r\n");
- for (u = 0; u < hp->nhdr; u++) {
- if (http_supress(hp->hdr[u], sup))
+ for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
+ if (http_supress(hp->hd[u][HTTP_START], sup))
continue;
if (1)
- VSL(SLT_BldHdr, fd, "%s", hp->hdr[u]);
- sbuf_cat(sb, hp->hdr[u]);
+ VSL(SLT_BldHdr, fd, "%s", hp->hd[u][HTTP_START]);
+ sbuf_cat(sb, hp->hd[u][HTTP_START]);
sbuf_cat(sb, "\r\n");
}
if (mode != Build_Reply) {
sbuf_finish(sb);
}
}
+
+void
+HTTP_Init(void)
+{
+#define HTTPH(a, b, c, d, e, f, g) b[0] = strlen(b + 1);
+#include "http_headers.h"
+#undef HTTPH
+}
VCL_Init();
VCL_Load(heritage.vcl_file, "boot", NULL);
+ HTTP_Init();
SES_Init();
VBE_Init();
sbuf_finish(w->sb);
RES_Write(sp, sbuf_data(w->sb), sbuf_len(w->sb));
- if (http_GetHdr(hp, "Content-Length", &b))
+ if (http_GetHdr(hp, H_Content_Length, &b))
cls = pass_straight(sp, vc->fd, hp, b);
- else if (http_HdrIs(hp, "Connection", "close"))
+ else if (http_HdrIs(hp, H_Connection, "close"))
cls = pass_straight(sp, vc->fd, hp, NULL);
- else if (http_HdrIs(hp, "Transfer-Encoding", "chunked"))
+ else if (http_HdrIs(hp, H_Transfer_Encoding, "chunked"))
cls = pass_chunked(sp, vc->fd, hp);
else {
cls = pass_straight(sp, vc->fd, hp, NULL);
}
RES_Flush(sp);
- if (http_GetHdr(hp, "Connection", &b) && !strcasecmp(b, "close"))
+ if (http_GetHdr(hp, H_Connection, &b) && !strcasecmp(b, "close"))
cls = 1;
if (cls)
RES_Write(sp, "Last-Modified: ", -1);
RES_Write(sp, p, -1);
RES_Write(sp, "\r\n", -1);
- if (strcmp(sp->http->proto, "HTTP/1.1"))
+ if (strcmp(sp->http->hd[HTTP_HDR_PROTO][HTTP_START], "HTTP/1.1"))
RES_Write(sp, "Connection: close\r\n", -1);
sbuf_printf(sb, "X-Varnish: xid %u\r\n", sp->obj->xid);
sbuf_printf(sb, "\r\n");
time_t ims;
if (sp->obj->last_modified > 0 &&
- http_GetHdr(sp->http, "If-Modified-Since", &p)) {
+ http_GetHdr(sp->http, H_If_Modified_Since, &p)) {
ims = TIM_parse(p);
if (ims > sp->t_req) /* [RFC2616 14.25] */
return (0);
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->proto, "HTTP/1.1"))
+ if (strcmp(sp->http->hd[HTTP_HDR_PROTO][HTTP_START], "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));
bytes += sbuf_len(sb);
/* XXX: conditional request handling */
- if (!strcmp(sp->http->req, "GET")) {
+ if (!strcmp(sp->http->hd[HTTP_HDR_REQ][HTTP_START], "GET")) {
TAILQ_FOREACH(st, &sp->obj->store, list) {
assert(st->stevedore != NULL);
u += st->len;
struct sess sess;
struct http http;
- char *http_hdr;
};
/*--------------------------------------------------------------------*/
(void)addr; /* XXX */
(void)len; /* XXX */
sm = calloc(
- sizeof *sm +
- heritage.mem_http_headers * sizeof sm->http_hdr +
- heritage.mem_http_headerspace +
- heritage.mem_workspace,
+ sizeof *sm + heritage.mem_workspace,
1);
if (sm == NULL)
return (NULL);
sm->sess.magic = SESS_MAGIC;
sm->sess.mem = sm;
sm->sess.http = &sm->http;
- http_Init(&sm->http, (void *)(sm + 1));
+ http_Init(&sm->http, (void *)(sm + 1), heritage.mem_workspace);
return (&sm->sess);
}
char *
VRT_GetReq(struct sess *sp)
{
+ char *p;
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
assert(sp != NULL);
assert(sp->http != NULL);
- return (sp->http->req);
+ return (sp->http->hd[HTTP_HDR_REQ][HTTP_START]);
}
/*--------------------------------------------------------------------*/
unsigned wthread_timeout;
/* Memory allocation hints */
- unsigned mem_http_headerspace;
- unsigned mem_http_headers;
unsigned mem_workspace;
};
retirement_age = INT_MAX;
u1 = u2 = 0;
- if (http_GetHdrField(hp, "Cache-Control", "max-age", &p)) {
+ if (http_GetHdrField(hp, H_Cache_Control, "max-age", &p)) {
u1 = strtoul(p, NULL, 0);
u2 = 0;
- if (http_GetHdr(hp, "Age", &p)) {
+ if (http_GetHdr(hp, H_Age, &p)) {
u2 = strtoul(p, NULL, 0);
obj->age = u2;
}
}
h_date = 0;
- if (http_GetHdr(hp, "Date", &p))
+ if (http_GetHdr(hp, H_Date, &p))
h_date = TIM_parse(p);
h_expires = 0;
- if (http_GetHdr(hp, "Expires", &p))
+ if (http_GetHdr(hp, H_Expires, &p))
h_expires = TIM_parse(p);
if (h_date < t_req && h_expires > t_req) {
heritage.wthread_min = 1;
heritage.wthread_max = UINT_MAX;
heritage.wthread_timeout = 10;
- heritage.mem_http_headerspace= 4096;
- heritage.mem_http_headers= 32;
- heritage.mem_workspace = 0;
+ heritage.mem_workspace = 4096;
while ((o = getopt(argc, argv, "b:df:h:p:s:t:w:")) != -1)
switch (o) {
SLTM(BackendReuse)
SLTM(BackendClose)
SLTM(HttpError)
+SLTM(HttpGarbage)
SLTM(ClientAddr)
SLTM(Backend)
SLTM(Request)
p[i] = '\0';
v->name = p;
v->fmt = STRING;
- asprintf(&p, "VRT_GetHdr(sp, \"%s\")", v->name + vh->len);
+ asprintf(&p, "VRT_GetHdr(sp, \"\\%03o%s:\")",
+ strlen(v->name + vh->len) + 1, v->name + vh->len);
assert(p != NULL);
v->rname = p;
return (v);