cache_http.c \
cache_main.c \
cache_pool.c \
- cache_pass.c \
cache_pipe.c \
cache_response.c \
cache_session.c \
TAILQ_ENTRY(sess) list;
- struct vbe_conn *vbc;
struct backend *backend;
struct object *obj;
struct VCL_conf *vcl;
void EXP_TTLchange(struct object *o);
/* cache_fetch.c */
-int FetchBody(struct sess *sp);
-int FetchHeaders(struct sess *sp);
+int Fetch(struct sess *sp);
/* cache_hash.c */
+void HSH_Prealloc(struct sess *sp);
struct object *HSH_Lookup(struct sess *sp);
void HSH_Unbusy(struct object *o);
void HSH_Ref(struct object *o);
#include "http_headers.h"
#undef HTTPH
-/* cache_pass.c */
-int PassSession(struct sess *sp);
-void PassBody(struct sess *sp);
-
/* cache_pipe.c */
void PipeSession(struct sess *sp);
/*
DOT digraph vcl_center {
-DOT page="8.2,11.7"
-DOT size="6.3,9.7"
-DOT margin="1.0"
+xDOT page="8.2,11.5"
+DOT size="7.2,10.5"
+DOT margin="0.5"
+DOT center="1"
DOT start [
DOT shape=hexagon
-DOT label="Start"
+DOT label="Request received"
DOT ]
-DOT start -> RECV
+DOT RECV [shape=plaintext]
+DOT PIPE [shape=plaintext]
+DOT LOOKUP [shape=plaintext]
+DOT HIT [shape=plaintext]
+DOT MISS [shape=plaintext]
+DOT PASS [shape=plaintext]
+DOT FETCH [shape=plaintext]
+DOT DELIVER [shape=plaintext]
+DOT ERROR [shape=plaintext]
+DOT start -> RECV [style=bold,color=green,weight=4]
*/
#include <stdio.h>
static unsigned xids;
/*--------------------------------------------------------------------
- * The very first request
+ * AGAIN
+ * We come here when we just completed a request and already have
+ * received (part of) the next one. Instead taking the detour
+ * around the acceptor and then back to a worker, just stay in this
+ * worker and do what it takes.
*/
+
static int
cnt_again(struct sess *sp)
{
/*--------------------------------------------------------------------
* We have a refcounted object on the session, now deliver it.
*
-DOT subgraph cluster_deliver {
+DOT subgraph xcluster_deliver {
DOT deliver [
DOT shape=ellipse
DOT label="Build & send header"
DOT ]
-DOT DELIVER -> deliver [style=bold]
+DOT DELIVER -> deliver [style=bold,color=green,weight=4]
DOT deliver2 [
DOT shape=ellipse
DOT label="Send object"
DOT ]
-DOT deliver -> deliver2 [style=bold]
+DOT deliver -> deliver2 [style=bold,color=green,weight=4]
DOT }
-DOT deliver2 -> DONE [style=bold]
+DOT deliver2 -> DONE [style=bold,color=green,weight=4]
*/
static int
double dh, dp, da;
AZ(sp->obj);
- AZ(sp->vbc);
sp->backend = NULL;
if (sp->vcl != NULL) {
if (sp->wrk->vcl != NULL)
/*--------------------------------------------------------------------
* Emit an error
*
-DOT subgraph cluster_error {
+DOT subgraph xcluster_error {
DOT error [
DOT shape=ellipse
DOT label="Issue HTTP error"
* We have fetched the headers from the backend, ask the VCL code what
* to do next, then head off in that direction.
*
-DOT subgraph cluster_fetch {
+DOT subgraph xcluster_fetch {
DOT fetch [
DOT shape=ellipse
-DOT label="find obj.ttl\nobj.cacheable"
+DOT label="fetch from backend\n(find obj.ttl)"
DOT ]
-DOT FETCH -> fetch [style=bold]
+DOT FETCH -> fetch [style=bold,color=blue,weight=2]
DOT vcl_fetch [
DOT shape=box
DOT label="vcl_fetch()"
DOT ]
-DOT fetch -> vcl_fetch [style=bold]
-DOT fetch_lookup [
-DOT shape=ellipse
-DOT label="obj.cacheable=false\nunbusy obj\ndiscard body\n"
-DOT ]
-DOT vcl_fetch -> fetch_lookup [label="lookup", style=dotted, weight=0]
+DOT fetch -> vcl_fetch [style=bold,color=blue,weight=2]
DOT fetch_pass [
DOT shape=ellipse
-DOT label="obj.cacheable=false\nunbusy obj"
+DOT label="obj.pass=true"
DOT ]
DOT vcl_fetch -> fetch_pass [label="pass"]
-DOT fetch_ipass [
-DOT shape=ellipse
-DOT label="obj.cacheable=true\nobj.pass=true\nunbusy obj"
-DOT ]
-DOT vcl_fetch -> fetch_ipass [label="insert_pass"]
-DOT fetch_insert [
-DOT shape=ellipse
-DOT label="rcv body\nobj.cacheable=true\nunbusy"
-DOT ]
-DOT vcl_fetch -> fetch_insert [label="insert", style=bold]
-DOT fetch_error [
-DOT shape=ellipse
-DOT label="disc body\nobj.cacheable=false\nunbusy"
-DOT ]
-DOT vcl_fetch -> fetch_error [label="error"]
DOT }
-DOT fetch_lookup -> LOOKUP [style=dotted, weight=0]
-DOT fetch_pass -> PASSBODY
-DOT fetch_ipass -> PASSBODY
-DOT fetch_insert -> DELIVER [style=bold]
-DOT fetch_error -> ERROR
+DOT fetch_pass -> DELIVER
+DOT vcl_fetch -> DELIVER [label="insert",style=bold,color=blue,weight=2]
+DOT vcl_fetch -> errfetch [label="error"]
+DOT errfetch [label="ERROR",shape=plaintext]
*/
static int
cnt_fetch(struct sess *sp)
{
- CHECK_OBJ_NOTNULL(sp->vbc, VBE_CONN_MAGIC);
- RFC2616_cache_policy(sp, sp->vbc->http);
-
- VCL_fetch_method(sp);
- if (sp->handling == VCL_RET_LOOKUP)
- INCOMPL();
- if (sp->handling == VCL_RET_PASS) {
+ if (Fetch(sp)) {
sp->obj->cacheable = 0;
HSH_Unbusy(sp->obj);
HSH_Deref(sp->obj);
sp->obj = NULL;
- sp->step = STP_PASSBODY;
- return (0);
- }
- if (sp->handling == VCL_RET_INSERT_PASS) {
- sp->obj->pass = 1;
- sp->obj->cacheable = 1;
- HSH_Unbusy(sp->obj);
- /* Don't HSH_Deref(sp->obj); we need the ref for storage */
- sp->obj = NULL;
- sp->step = STP_PASSBODY;
- return (0);
- }
- if (sp->handling == VCL_RET_INSERT) {
- if (FetchBody(sp)) {
- sp->obj->cacheable = 0;
- HSH_Unbusy(sp->obj);
- HSH_Deref(sp->obj);
- sp->obj = NULL;
- RES_Error(sp, 503, NULL);
- sp->step = STP_DONE;
- return (0);
- }
- sp->obj->cacheable = 1;
- AZ(sp->vbc);
- HSH_Ref(sp->obj); /* get another, STP_DELIVER will deref */
- HSH_Unbusy(sp->obj);
- sp->wrk->acct.fetch++;
- sp->step = STP_DELIVER;
+ sp->step = STP_DONE;
+ RES_Error(sp, 503, NULL);
return (0);
}
+
+ RFC2616_cache_policy(sp, &sp->obj->http); /* XXX -> VCL */
+
+ VCL_fetch_method(sp);
+
if (sp->handling == VCL_RET_ERROR)
INCOMPL();
- INCOMPL();
+
+ if (sp->handling == VCL_RET_PASS)
+ sp->obj->pass = 1;
+
+ sp->obj->cacheable = 1;
+ HSH_Ref(sp->obj); /* get another, STP_DELIVER will deref */
+ if (sp->obj->objhead != NULL)
+ HSH_Unbusy(sp->obj);
+ sp->wrk->acct.fetch++;
+ sp->step = STP_DELIVER;
+ return (0);
}
/*--------------------------------------------------------------------
}
/*--------------------------------------------------------------------
+ * HIT
* We had a cache hit. Ask VCL, then march off as instructed.
*
-DOT subgraph cluster_hit {
+DOT subgraph xcluster_hit {
DOT hit [
DOT shape=box
DOT label="vcl_hit()"
DOT ]
-DOT HIT -> hit [style=bold]
-DOT hit2 [
-DOT shape=diamond
-DOT label="obj.pass ?"
-DOT ]
-DOT hit -> hit2 [label=deliver, style=bold]
-DOT hit_lookup [
-DOT shape=ellipse
-DOT label="unbusy"
-DOT ]
-DOT hit -> hit_lookup [label="lookup", style=dotted, weight=0]
-DOT hit_error [
-DOT shape=ellipse
-DOT label="unbusy"
-DOT ]
-DOT hit -> hit_error [label="error", weight=0]
-DOT hit_pass [
-DOT shape=ellipse
-DOT label="unbusy"
-DOT ]
-DOT hit -> hit_pass [label=pass]
-DOT hit2 -> hit_pass
+DOT HIT -> hit [style=bold,color=green,weight=4]
DOT }
-DOT hit_error -> ERROR
-DOT hit_pass -> PASS
-DOT hit_lookup -> LOOKUP [style=dotted, weight=0]
-DOT hit2 -> DELIVER [style=bold]
+DOT hit -> err_hit [label="error"]
+DOT err_hit [label="ERROR",shape=plaintext]
+DOT hit -> PASS [label=pass]
+DOT hit -> DELIVER [label="deliver",style=bold,color=green,weight=4]
*/
static int
cnt_hit(struct sess *sp)
{
- VCL_hit_method(sp);
+ assert(!sp->obj->pass);
- if (sp->handling == VCL_RET_DELIVER && sp->obj->pass)
- sp->handling = VCL_RET_PASS;
+ VCL_hit_method(sp);
if (sp->handling == VCL_RET_DELIVER) {
sp->step = STP_DELIVER;
return (0);
}
+
+ /* Drop our object, we won't need it */
+ HSH_Deref(sp->obj);
+ sp->obj = NULL;
+
if (sp->handling == VCL_RET_PASS) {
- HSH_Deref(sp->obj);
- sp->obj = NULL;
sp->step = STP_PASS;
return (0);
}
if (sp->handling == VCL_RET_ERROR) {
- HSH_Deref(sp->obj);
- sp->obj = NULL;
sp->step = STP_ERROR;
return (0);
}
- if (sp->handling == VCL_RET_LOOKUP)
- INCOMPL();
INCOMPL();
}
/*--------------------------------------------------------------------
- * Look up request in hash table
+ * LOOKUP
+ * Hash things together and look object up in hash-table.
*
* LOOKUP consists of two substates so that we can reenter if we
* encounter a busy object.
*
-DOT subgraph cluster_lookup {
+DOT subgraph xcluster_lookup {
+DOT hash [
+DOT shape=box
+DOT label="vcl_hash()"
+DOT ]
DOT lookup [
DOT shape=ellipse
-DOT label="find obj in cache"
+DOT label="obj in cache ?"
DOT ]
-DOT LOOKUP -> lookup [style=bold]
-DOT lookup3 [
+DOT lookup2 [
DOT shape=ellipse
-DOT label="Insert new busy object"
+DOT label="obj.pass ?"
DOT ]
-DOT lookup -> lookup3 [style=bold]
+DOT LOOKUP -> hash [style=bold,color=green,weight=4]
+DOT hash -> lookup [label="hash",style=bold,color=green,weight=4]
+DOT lookup -> lookup2 [label="yes",style=bold,color=green,weight=4]
DOT }
-DOT lookup -> HIT [label="hit", style=bold]
-DOT lookup3 -> MISS [label="miss", style=bold]
+DOT lookup2 -> HIT [label="no", style=bold,color=green,weight=4]
+DOT lookup2 -> PASS [label="yes"]
+DOT lookup -> MISS [label="no",style=bold,color=blue,weight=2]
*/
static int
cnt_lookup(struct sess *sp)
-{
-
- AZ(sp->obj);
- sp->step = STP_LOOKUP2;
- return (0);
-}
-
-static int
-cnt_lookup2(struct sess *sp)
{
struct object *o;
- /*
- * We don't assign to sp->obj directly because it is used
- * to cache state when we encounter a busy object.
- */
- o = HSH_Lookup(sp);
+ VCL_hash_method(sp); /* XXX: no-op for now */
- /* If we encountered busy-object, disembark worker thread */
+ o = HSH_Lookup(sp);
if (o == NULL) {
+ /*
+ * We hit a busy object, disembark worker thread and expect
+ * hash code to restart us, still in STP_LOOKUP, later.
+ */
WSL(sp->wrk, SLT_Debug, sp->fd,
"on waiting list on obj %u", sp->obj->xid);
SES_Charge(sp);
return (0);
}
- /* Account separately for pass and cache objects */
if (sp->obj->pass) {
VSL_stats->cache_hitpass++;
WSL(sp->wrk, SLT_HitPass, sp->fd, "%u", sp->obj->xid);
- } else {
- VSL_stats->cache_hit++;
- WSL(sp->wrk, SLT_Hit, sp->fd, "%u", sp->obj->xid);
- }
+ HSH_Deref(sp->obj);
+ sp->obj = NULL;
+ sp->step = STP_PASS;
+ return (0);
+ }
+
+ VSL_stats->cache_hit++;
+ WSL(sp->wrk, SLT_Hit, sp->fd, "%u", sp->obj->xid);
sp->step = STP_HIT;
return (0);
}
/*--------------------------------------------------------------------
* We had a miss, ask VCL, proceed as instructed
*
-DOT subgraph cluster_miss {
+DOT subgraph xcluster_miss {
DOT miss [
DOT shape=box
DOT label="vcl_miss()"
DOT ]
-DOT MISS -> miss [style=bold]
-DOT miss_error [
-DOT shape=ellipse
-DOT label="obj.cacheable=false\nunbusy"
-DOT ]
-DOT miss -> miss_error [label="error"]
-DOT miss_pass [
-DOT shape=ellipse
-DOT label="obj.cacheable=false\nunbusy"
+DOT MISS -> miss [style=bold,color=blue,weight=2]
+DOT miss_ins [
+DOT label="insert new object"
DOT ]
-DOT miss -> miss_pass [label="pass"]
-DOT miss_lookup [
-DOT shape=ellipse
-DOT label="obj.cacheable=false\nunbusy"
-DOT ]
-DOT miss -> miss_lookup [label="lookup", style=dotted, weight=0]
-DOT miss_fetch [
-DOT shape=ellipse
-DOT label="fetch obj headers\nfrom backend"
-DOT ]
-DOT miss -> miss_fetch [label="fetch", style=bold]
+DOT miss -> miss_ins [label="fetch",style=bold,color=blue,weight=2]
DOT }
-DOT miss_error -> ERROR
-DOT miss_pass -> PASS
-DOT miss_fetch -> FETCH [style=bold]
-DOT miss_lookup -> LOOKUP [style=dotted, weight=0]
+DOT miss -> err_miss [label="error"]
+DOT err_miss [label="ERROR",shape=plaintext]
+DOT miss_ins -> FETCH [style=bold,color=blue,weight=2]
+DOT miss -> PASS [label="pass"]
DOT
*/
sp->step = STP_PASS;
return (0);
}
- if (sp->handling == VCL_RET_LOOKUP)
- INCOMPL();
if (sp->handling == VCL_RET_FETCH) {
- AZ(sp->vbc);
- if (FetchHeaders(sp)) {
- sp->obj->cacheable = 0;
- HSH_Unbusy(sp->obj);
- HSH_Deref(sp->obj);
- sp->obj = NULL;
- sp->step = STP_DONE;
- RES_Error(sp, 503, NULL);
- return (0);
- }
sp->step = STP_FETCH;
- AN(sp->vbc);
return (0);
}
INCOMPL();
* Start pass processing by getting headers from backend, then
* continue in passbody.
*
-DOT subgraph cluster_pass {
+DOT subgraph xcluster_pass {
DOT pass [
+DOT shape=box
+DOT label="vcl_pass()"
+DOT ]
+DOT pass_do [
DOT shape=ellipse
-DOT label="send to bke\nrx bkehdr"
+DOT label="create new object\n"
DOT ]
DOT PASS -> pass
+DOT pass -> pass_do [label="pass"]
DOT }
-DOT pass -> PASSBODY
+DOT pass_do -> FETCH
+DOT pass -> err_pass [label="error"]
+DOT err_pass [label="ERROR",shape=plaintext]
*/
static int
cnt_pass(struct sess *sp)
{
- AZ(sp->vbc);
- if (!PassSession(sp)) {
- AN(sp->vbc);
- sp->step = STP_PASSBODY;
- } else
- sp->step = STP_DONE;
- return (0);
-}
-
-
-/*--------------------------------------------------------------------
- * We get here when we have the backends headers, send them to client
- * and pass any body the backend may have on as well.
- *
-DOT subgraph cluster_passbody {
-DOT passbody [
-DOT shape=ellipse
-DOT label="send hdrs\npass body\n"
-DOT ]
-DOT PASSBODY -> passbody
-DOT }
-DOT passbody -> DONE
- */
-
-static int
-cnt_passbody(struct sess *sp)
-{
+ AZ(sp->obj);
- sp->wrk->acct.pass++;
- AN(sp->vbc);
- PassBody(sp);
- AZ(sp->vbc);
- sp->step = STP_DONE;
+ VCL_pass_method(sp);
+ if (sp->handling == VCL_RET_ERROR) {
+ sp->step = STP_ERROR;
+ return (0);
+ }
+ HSH_Prealloc(sp);
+ sp->obj = sp->wrk->nobj;
+ sp->wrk->nobj = NULL;
+ sp->obj->busy = 1;
+ sp->step = STP_FETCH;
return (0);
}
-
/*--------------------------------------------------------------------
* Ship the request header to the backend unchanged, then pipe
* until one of the ends close the connection.
*
-DOT subgraph cluster_pipe {
+DOT subgraph xcluster_pipe {
DOT pipe [
+DOT shape=box
+DOT label="vcl_pipe()"
+DOT ]
+DOT pipe_do [
DOT shape=ellipse
DOT label="build&send hdr\npipe until close"
DOT ]
DOT PIPE -> pipe
+DOT pipe -> pipe_do [label="pipe"]
DOT }
-DOT pipe -> DONE
+DOT pipe_do -> DONE
+DOT pipe -> err_pipe [label="error"]
+DOT err_pipe [label="ERROR",shape=plaintext]
*/
static int
/*--------------------------------------------------------------------
- * Dispatch the request as instructed by VCL
+ * RECV
+ * We have a complete request, get a VCL reference and dispatch it
+ * as instructed by vcl_recv{}
*
-DOT subgraph cluster_recv {
+DOT subgraph xcluster_recv {
DOT recv [
DOT shape=box
DOT label="vcl_recv()"
DOT ]
-DOT RECV -> recv
-DOT recv_lookup [
-DOT shape=ellipse
-DOT label="discard any body"
-DOT ]
-DOT recv -> recv_lookup [label="lookup"]
-DOT recv_error [
-DOT shape=ellipse
-DOT label="discard any body"
-DOT ]
-DOT recv -> recv_error [label="error"]
+DOT RECV -> recv [style=bold,color=green,weight=4]
DOT }
DOT recv -> PIPE [label="pipe"]
DOT recv -> PASS [label="pass"]
-DOT recv_lookup -> LOOKUP
-DOT recv_error -> ERROR
+DOT recv -> err_recv [label="error"]
+DOT err_recv [label="ERROR",shape=plaintext]
+DOT recv -> LOOKUP [label="lookup",style=bold,color=green,weight=4]
*/
static int
{
int done;
- VSL_stats->client_req++;
+ AZ(sp->vcl);
+ AZ(sp->obj);
+
+ /* Update stats of various sorts */
+ VSL_stats->client_req++; /* XXX not locked */
clock_gettime(CLOCK_REALTIME, &sp->t_req);
sp->wrk->idle = sp->t_req.tv_sec;
- sp->xid = ++xids;
+ sp->wrk->acct.req++;
+
+ /* Assign XID and log */
+ sp->xid = ++xids; /* XXX not locked */
WSL(sp->wrk, SLT_ReqStart, sp->fd,
"%s %s %u", sp->addr, sp->port, sp->xid);
- AZ(sp->vcl);
+ /* Borrow VCL reference from worker thread */
VCL_Refresh(&sp->wrk->vcl);
sp->vcl = sp->wrk->vcl;
sp->wrk->vcl = NULL;
- AZ(sp->obj);
- AZ(sp->vbc);
-
- sp->wrk->acct.req++;
done = http_DissectRequest(sp->wrk, sp->http, sp->fd);
if (done != 0) {
- RES_Error(sp, done, NULL);
+ RES_Error(sp, done, NULL); /* XXX: STP_ERROR ? */
sp->step = STP_DONE;
return (0);
}
http_DoConnection(sp);
+ /* By default we use the first backend */
sp->backend = sp->vcl->backend[0];
/* XXX: Handle TRACE & OPTIONS of Max-Forwards = 0 */
- /* XXX: determine if request comes with body */
-
VCL_recv_method(sp);
+ sp->wantbody = !strcmp(sp->http->hd[HTTP_HDR_REQ].b, "GET");
switch(sp->handling) {
case VCL_RET_LOOKUP:
/* XXX: discard req body, if any */
- sp->wantbody = !strcmp(sp->http->hd[HTTP_HDR_REQ].b, "GET");
sp->step = STP_LOOKUP;
return (0);
case VCL_RET_PIPE:
/*--------------------------------------------------------------------
* Central state engine dispatcher.
*
- * We grab a VCL reference, and keeps kicking the session around until
- * it has had enough.
+ * Kick the session around until it has had enough.
*
*/
CHECK_OBJ_NOTNULL(w, WORKER_MAGIC);
for (done = 0; !done; ) {
+ /*
+ * This is a good place to be paranoid about the various
+ * pointers still pointing to the things we expect.
+ */
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
if (sp->obj != NULL)
CHECK_OBJ(sp->obj, OBJECT_MAGIC);
CHECK_OBJ(w->nobj, OBJECT_MAGIC);
if (w->nobjhead != NULL)
CHECK_OBJ(w->nobjhead, OBJHEAD_MAGIC);
+
switch (sp->step) {
-#define STEP(l,u) \
- case STP_##u: \
- done = cnt_##l(sp); \
- break;
+#define STEP(l,u) case STP_##u: done = cnt_##l(sp); break;
#include "steps.h"
#undef STEP
default: INCOMPL();
/*--------------------------------------------------------------------*/
int
-FetchBody(struct sess *sp)
+Fetch(struct sess *sp)
{
- int cls;
struct vbe_conn *vc;
+ struct worker *w;
char *b;
+ int cls;
int body = 1; /* XXX */
struct http *hp;
struct storage *st;
CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
assert(sp->obj->busy != 0);
+ w = sp->wrk;
+
+ sp->obj->xid = sp->xid;
+
+ vc = VBE_GetFd(sp);
+ if (vc == NULL)
+ return (1);
+
+ http_ClrHeader(vc->http);
+ vc->http->logtag = HTTP_Tx;
+ http_GetReq(w, vc->fd, vc->http, sp->http);
+ http_FilterHeader(w, vc->fd, vc->http, sp->http, HTTPH_R_FETCH);
+ http_PrintfHeader(w, vc->fd, vc->http, "X-Varnish: %u", sp->xid);
+ http_PrintfHeader(w, vc->fd, vc->http,
+ "X-Forwarded-for: %s", sp->addr);
+ if (!http_GetHdr(vc->http, H_Host, &b)) {
+ http_PrintfHeader(w, vc->fd, vc->http, "Host: %s",
+ sp->backend->hostname);
+ }
- vc = sp->vbc;
- sp->vbc = NULL;
+ WRK_Reset(w, &vc->fd);
+ http_Write(w, vc->http, 0);
+ if (WRK_Flush(w)) {
+ /* XXX: cleanup */
+ return (1);
+ }
+
+ CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+ CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
+ CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
+
+ if (http_RecvHead(vc->http, vc->fd)) {
+ /* XXX: cleanup */
+ return (1);
+ }
+ if (http_DissectResponse(sp->wrk, vc->http, vc->fd)) {
+ /* XXX: cleanup */
+ return (1);
+ }
+ CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+ CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
+ CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
+
+ sp->obj->entered = time(NULL);
+
+
+ assert(sp->obj->busy != 0);
if (http_GetHdr(vc->http, H_Last_Modified, &b))
sp->obj->last_modified = TIM_parse(b);
return (0);
}
-
-/*--------------------------------------------------------------------*/
-
-int
-FetchHeaders(struct sess *sp)
-{
- struct vbe_conn *vc;
- struct worker *w;
- char *b;
-
- CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
- CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
- CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
- assert(sp->obj->busy != 0);
- w = sp->wrk;
-
- sp->obj->xid = sp->xid;
-
- vc = VBE_GetFd(sp);
- if (vc == NULL)
- return (1);
-
- http_ClrHeader(vc->http);
- vc->http->logtag = HTTP_Tx;
- http_GetReq(w, vc->fd, vc->http, sp->http);
- http_FilterHeader(w, vc->fd, vc->http, sp->http, HTTPH_R_FETCH);
- http_PrintfHeader(w, vc->fd, vc->http, "X-Varnish: %u", sp->xid);
- http_PrintfHeader(w, vc->fd, vc->http,
- "X-Forwarded-for: %s", sp->addr);
- if (!http_GetHdr(vc->http, H_Host, &b)) {
- http_PrintfHeader(w, vc->fd, vc->http, "Host: %s",
- sp->backend->hostname);
- }
-
- WRK_Reset(w, &vc->fd);
- http_Write(w, vc->http, 0);
- if (WRK_Flush(w)) {
- /* XXX: cleanup */
- return (1);
- }
-
- CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
- CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
- CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
-
- if (http_RecvHead(vc->http, vc->fd)) {
- /* XXX: cleanup */
- return (1);
- }
- if (http_DissectResponse(sp->wrk, vc->http, vc->fd)) {
- /* XXX: cleanup */
- return (1);
- }
- CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
- CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
- CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
- AZ(sp->vbc);
- sp->vbc = vc;
-
- sp->obj->entered = time(NULL);
-
- return (0);
-}
static struct hash_slinger *hash;
-struct object *
-HSH_Lookup(struct sess *sp)
+/* Precreate an objhead and object for later use */
+void
+HSH_Prealloc(struct sess *sp)
{
struct worker *w;
- struct http *h;
- struct objhead *oh;
- struct object *o;
- char *url, *host;
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
- CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
- CHECK_OBJ_NOTNULL(sp->http, HTTP_MAGIC);
- AN(hash);
w = sp->wrk;
- h = sp->http;
- /* Precreate an objhead and object in case we need them */
if (w->nobjhead == NULL) {
w->nobjhead = calloc(sizeof *w->nobjhead, 1);
XXXAN(w->nobjhead);
VSL_stats->n_object++;
} else
CHECK_OBJ_NOTNULL(w->nobj, OBJECT_MAGIC);
+}
+
+struct object *
+HSH_Lookup(struct sess *sp)
+{
+ struct worker *w;
+ struct http *h;
+ struct objhead *oh;
+ struct object *o;
+ char *url, *host;
+
+ CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+ CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
+ CHECK_OBJ_NOTNULL(sp->http, HTTP_MAGIC);
+ AN(hash);
+ w = sp->wrk;
+ h = sp->http;
+ HSH_Prealloc(sp);
url = h->hd[HTTP_HDR_URL].b;
if (!http_GetHdr(h, H_Host, &host))
host = url;
CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
oh = o->objhead;
- CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
- LOCK(&oh->mtx);
+ if (oh != NULL) {
+ CHECK_OBJ(oh, OBJHEAD_MAGIC);
+ LOCK(&oh->mtx);
+ }
assert(o->refcnt > 0);
o->refcnt++;
- UNLOCK(&oh->mtx);
+ if (oh != NULL)
+ UNLOCK(&oh->mtx);
}
void
CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
oh = o->objhead;
- CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
+ if (oh == NULL) {
+ /* Pass object, not referenced anywhere */
+ free(o);
+ return;
+ }
+
+ CHECK_OBJ(oh, OBJHEAD_MAGIC);
/* drop ref on object */
LOCK(&oh->mtx);
+++ /dev/null
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006 Linpro AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Id$
- *
- * XXX: charge bytes to srcaddr
- * XXX: buffer to relieve backed ASAP.
- * XXX: Check if response has any body
- * XXX: Don't pass chunked to HTTP/1.0 client
- */
-
-#include <stdio.h>
-#include <inttypes.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-
-#ifndef HAVE_CLOCK_GETTIME
-#include "compat/clock_gettime.h"
-#endif
-
-#include "shmlog.h"
-#include "cache.h"
-
-#define PASS_BUFSIZ 8192
-
-/*--------------------------------------------------------------------*/
-
-static int
-pass_straight(struct sess *sp, int fd, struct http *hp, char *bi)
-{
- int i;
- off_t cl;
- unsigned c;
- char buf[PASS_BUFSIZ];
-
- if (bi != NULL)
- cl = strtoumax(bi, NULL, 0);
- else
- cl = (1 << 30);
-
- i = fcntl(fd, F_GETFL); /* XXX ? */
- i &= ~O_NONBLOCK;
- i = fcntl(fd, F_SETFL, i);
-
- while (cl != 0) {
- c = cl;
- if (c > sizeof buf)
- c = sizeof buf;
- i = http_Read(hp, fd, buf, c);
- if (i == 0 && bi == NULL)
- return (1);
- if (i <= 0) {
- vca_close_session(sp, "backend closed");
- return (1);
- }
- sp->wrk->acct.bodybytes += WRK_Write(sp->wrk, buf, i);
- if (WRK_Flush(sp->wrk))
- vca_close_session(sp, "remote closed");
- cl -= i;
- }
- return (0);
-}
-
-
-/*--------------------------------------------------------------------*/
-
-static int
-pass_chunked(struct sess *sp, int fd, struct http *hp)
-{
- int i, j;
- char *p, *q;
- unsigned u;
- char buf[PASS_BUFSIZ];
- char *bp, *be;
-
- i = fcntl(fd, F_GETFL); /* XXX ? */
- i &= ~O_NONBLOCK;
- i = fcntl(fd, F_SETFL, i);
-
- bp = buf;
- be = buf + sizeof buf;
- p = buf;
- while (1) {
- i = http_Read(hp, fd, bp, be - bp);
- xxxassert(i >= 0);
- if (i == 0 && p == bp)
- break;
- bp += i;
- /* buffer valid from p to bp */
- assert(bp >= p);
-
- /* chunk starts with f("%x\r\n", len) */
- u = strtoul(p, &q, 16);
- while (q && q < bp && *q == ' ')
- /* shouldn't happen - but sometimes it does */
- q++;
- if (q == NULL || q > bp - 2 /* want \r\n in same buffer */) {
- /* short - move to start of buffer and extend */
- memmove(buf, p, bp - p);
- bp -= p - buf;
- p = buf;
- continue;
- }
- assert(*q == '\r');
- q++;
- assert(*q == '\n');
- q++;
-
- /* we just received the final zero-length chunk */
- if (u == 0) {
- sp->wrk->acct.bodybytes += WRK_Write(sp->wrk, p, q - p);
- break;
- }
-
- /* include chunk header */
- u += q - p;
-
- /* include trailing \r\n with chunk */
- u += 2;
-
- for (;;) {
- j = u;
- if (bp - p < j)
- j = bp - p;
- sp->wrk->acct.bodybytes += WRK_Write(sp->wrk, p, j);
- WRK_Flush(sp->wrk);
- p += j;
- assert(u >= j);
- u -= j;
- if (u == 0)
- break;
- p = bp = buf;
- j = u;
- if (j > be - bp)
- j = be - bp;
- i = http_Read(hp, fd, bp, j);
- xxxassert(i > 0);
- bp += i;
- }
- }
- if (WRK_Flush(sp->wrk))
- vca_close_session(sp, "remote closed");
- return (0);
-}
-
-
-/*--------------------------------------------------------------------*/
-
-void
-PassBody(struct sess *sp)
-{
- struct vbe_conn *vc;
- char *b;
- int cls;
-
- CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
- CHECK_OBJ_NOTNULL(sp->vbc, VBE_CONN_MAGIC);
- vc = sp->vbc;
- sp->vbc = NULL;
-
- clock_gettime(CLOCK_REALTIME, &sp->t_resp);
-
- http_ClrHeader(sp->http);
- http_CopyResp(sp->wrk, sp->fd, sp->http, vc->http);
- http_FilterHeader(sp->wrk, sp->fd, sp->http, vc->http, HTTPH_A_PASS);
- http_PrintfHeader(sp->wrk, sp->fd, sp->http, "X-Varnish: %u", sp->xid);
- http_PrintfHeader(sp->wrk, sp->fd, sp->http,
- "X-Forwarded-for: %s", sp->addr);
- /* XXX */
- if (http_HdrIs(vc->http, H_Transfer_Encoding, "chunked"))
- http_PrintfHeader(sp->wrk, sp->fd, sp->http, "Transfer-Encoding: chunked");
- WRK_Reset(sp->wrk, &sp->fd);
- sp->wrk->acct.hdrbytes += http_Write(sp->wrk, 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 if (http_IsBodyless(vc->http))
- cls = 0;
- else {
- cls = pass_straight(sp, vc->fd, vc->http, NULL);
- }
-
- if (WRK_Flush(sp->wrk))
- vca_close_session(sp, "remote closed");
-
- if (http_GetHdr(vc->http, H_Connection, &b) && !strcasecmp(b, "close"))
- cls = 1;
-
- if (cls)
- VBE_ClosedFd(sp->wrk, vc, 0);
- else
- VBE_RecycleFd(sp->wrk, vc);
-}
-
-
-/*--------------------------------------------------------------------*/
-
-int
-PassSession(struct sess *sp)
-{
- int i;
- struct vbe_conn *vc;
- struct worker *w;
- char *b;
-
- CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
- CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
- w = sp->wrk;
-
- vc = VBE_GetFd(sp);
- if (vc == NULL)
- return (1);
-
- http_CopyReq(w, vc->fd, vc->http, sp->http);
- http_FilterHeader(w, vc->fd, vc->http, sp->http, HTTPH_R_PASS);
- http_PrintfHeader(w, vc->fd, vc->http, "X-Varnish: %u", sp->xid);
- if (!http_GetHdr(vc->http, H_Host, &b)) {
- http_PrintfHeader(w, vc->fd, vc->http, "Host: %s",
- sp->backend->hostname);
- }
- WRK_Reset(w, &vc->fd);
- http_Write(w, vc->http, 0);
- i = WRK_Flush(w);
- xxxassert(i == 0);
-
- /* XXX: copy any contents */
-
- i = http_RecvHead(vc->http, vc->fd);
- xxxassert(i == 0);
- http_DissectResponse(w, vc->http, vc->fd);
-
- assert(sp->vbc == NULL);
- sp->vbc = vc;
- return (0);
-}
hp = sp->http;
break;
case 2:
- hp = sp->vbc->http;
+ hp = &sp->obj->http;
break;
default:
INCOMPL();
" lookup;\n"
"}\n"
"\n"
+ "sub default_vcl_pipe {\n"
+ " pipe;\n"
+ "}\n"
+ "\n"
+ "sub default_vcl_pass {\n"
+ " pass;\n"
+ "}\n"
+ "\n"
+ "sub default_vcl_hash {\n"
+ " hash;\n"
+ "}\n"
+ "\n"
"sub default_vcl_hit {\n"
" if (!obj.cacheable) {\n"
" pass;\n"
" error;\n"
" }\n"
" if (!obj.cacheable) {\n"
- " insert_pass;\n"
+ " pass;\n"
" }\n"
" if (resp.http.Set-Cookie) {\n"
- " insert_pass;\n"
+ " pass;\n"
" }\n"
" insert;\n"
"}\n"
STEP(recv, RECV)
STEP(pipe, PIPE)
STEP(pass, PASS)
-STEP(passbody, PASSBODY)
STEP(lookup, LOOKUP)
-STEP(lookup2, LOOKUP2)
STEP(miss, MISS)
STEP(hit, HIT)
STEP(fetch, FETCH)
vcl_fini_f *fini_func;
vcl_func_f *recv_func;
+ vcl_func_f *pipe_func;
+ vcl_func_f *pass_func;
+ vcl_func_f *hash_func;
vcl_func_f *miss_func;
vcl_func_f *hit_func;
vcl_func_f *fetch_func;
VCL_RET_MAC_E(error, ERROR, (1 << 0), 0)
#endif
VCL_RET_MAC(lookup, LOOKUP, (1 << 1), 1)
-VCL_RET_MAC(pipe, PIPE, (1 << 2), 2)
-VCL_RET_MAC(pass, PASS, (1 << 3), 3)
-VCL_RET_MAC(insert_pass, INSERT_PASS, (1 << 4), 4)
+VCL_RET_MAC(hash, HASH, (1 << 2), 2)
+VCL_RET_MAC(pipe, PIPE, (1 << 3), 3)
+VCL_RET_MAC(pass, PASS, (1 << 4), 4)
VCL_RET_MAC(fetch, FETCH, (1 << 5), 5)
VCL_RET_MAC(insert, INSERT, (1 << 6), 6)
VCL_RET_MAC(deliver, DELIVER, (1 << 7), 7)
#else
#define VCL_RET_ERROR (1 << 0)
#define VCL_RET_LOOKUP (1 << 1)
-#define VCL_RET_PIPE (1 << 2)
-#define VCL_RET_PASS (1 << 3)
-#define VCL_RET_INSERT_PASS (1 << 4)
+#define VCL_RET_HASH (1 << 2)
+#define VCL_RET_PIPE (1 << 3)
+#define VCL_RET_PASS (1 << 4)
#define VCL_RET_FETCH (1 << 5)
#define VCL_RET_INSERT (1 << 6)
#define VCL_RET_DELIVER (1 << 7)
#ifdef VCL_MET_MAC
VCL_MET_MAC(recv,RECV,(VCL_RET_ERROR|VCL_RET_PASS|VCL_RET_PIPE|VCL_RET_LOOKUP))
-VCL_MET_MAC(miss,MISS,(VCL_RET_ERROR|VCL_RET_PASS|VCL_RET_PIPE|VCL_RET_FETCH))
-VCL_MET_MAC(hit,HIT,(VCL_RET_ERROR|VCL_RET_PASS|VCL_RET_PIPE|VCL_RET_DELIVER))
-VCL_MET_MAC(fetch,FETCH,(VCL_RET_ERROR|VCL_RET_PASS|VCL_RET_PIPE|VCL_RET_INSERT|VCL_RET_INSERT_PASS))
+VCL_MET_MAC(pipe,PIPE,(VCL_RET_ERROR|VCL_RET_PIPE))
+VCL_MET_MAC(pass,PASS,(VCL_RET_ERROR|VCL_RET_PASS))
+VCL_MET_MAC(hash,HASH,(VCL_RET_HASH))
+VCL_MET_MAC(miss,MISS,(VCL_RET_ERROR|VCL_RET_PASS|VCL_RET_FETCH))
+VCL_MET_MAC(hit,HIT,(VCL_RET_ERROR|VCL_RET_PASS|VCL_RET_DELIVER))
+VCL_MET_MAC(fetch,FETCH,(VCL_RET_ERROR|VCL_RET_PASS|VCL_RET_INSERT))
VCL_MET_MAC(timeout,TIMEOUT,(VCL_RET_FETCH|VCL_RET_DISCARD))
#endif
return (T_FETCH);
}
return (0);
- case 'i':
- if (p[0] == 'i' && p[1] == 'n' && p[2] == 's' &&
- p[3] == 'e' && p[4] == 'r' && p[5] == 't' &&
- p[6] == '_' && p[7] == 'p' && p[8] == 'a' &&
- p[9] == 's' && p[10] == 's' && !isvar(p[11])) {
- *q = p + 11;
- return (T_INSERT_PASS);
+ case 'h':
+ if (p[0] == 'h' && p[1] == 'a' && p[2] == 's' &&
+ p[3] == 'h' && !isvar(p[4])) {
+ *q = p + 4;
+ return (T_HASH);
}
+ return (0);
+ case 'i':
if (p[0] == 'i' && p[1] == 'n' && p[2] == 's' &&
p[3] == 'e' && p[4] == 'r' && p[5] == 't'
&& !isvar(p[6])) {
vcl_tnames[T_FETCH] = "fetch";
vcl_tnames[T_FUNC] = "func";
vcl_tnames[T_GEQ] = ">=";
+ vcl_tnames[T_HASH] = "hash";
vcl_tnames[T_IF] = "if";
vcl_tnames[T_INC] = "++";
vcl_tnames[T_INCR] = "+=";
vcl_tnames[T_INSERT] = "insert";
- vcl_tnames[T_INSERT_PASS] = "insert_pass";
vcl_tnames[T_LEQ] = "<=";
vcl_tnames[T_LOOKUP] = "lookup";
vcl_tnames[T_MUL] = "*=";
{
fputs("#define VCL_RET_ERROR (1 << 0)\n", f);
fputs("#define VCL_RET_LOOKUP (1 << 1)\n", f);
- fputs("#define VCL_RET_PIPE (1 << 2)\n", f);
- fputs("#define VCL_RET_PASS (1 << 3)\n", f);
- fputs("#define VCL_RET_INSERT_PASS (1 << 4)\n", f);
+ fputs("#define VCL_RET_HASH (1 << 2)\n", f);
+ fputs("#define VCL_RET_PIPE (1 << 3)\n", f);
+ fputs("#define VCL_RET_PASS (1 << 4)\n", f);
fputs("#define VCL_RET_FETCH (1 << 5)\n", f);
fputs("#define VCL_RET_INSERT (1 << 6)\n", f);
fputs("#define VCL_RET_DELIVER (1 << 7)\n", f);
fputs(" vcl_fini_f *fini_func;\n", f);
fputs("\n", f);
fputs(" vcl_func_f *recv_func;\n", f);
+ fputs(" vcl_func_f *pipe_func;\n", f);
+ fputs(" vcl_func_f *pass_func;\n", f);
+ fputs(" vcl_func_f *hash_func;\n", f);
fputs(" vcl_func_f *miss_func;\n", f);
fputs(" vcl_func_f *hit_func;\n", f);
fputs(" vcl_func_f *fetch_func;\n", f);
#
set methods {
{recv {error pass pipe lookup}}
- {miss {error pass pipe fetch}}
- {hit {error pass pipe deliver}}
- {fetch {error pass pipe insert insert_pass}}
+ {pipe {error pipe}}
+ {pass {error pass}}
+ {hash {hash}}
+ {miss {error pass fetch}}
+ {hit {error pass deliver}}
+ {fetch {error pass insert}}
{timeout {fetch discard}}
}
set returns {
error
lookup
+ hash
pipe
pass
- insert_pass
fetch
insert
deliver
#define T_SWITCH_CONFIG 142
#define T_ERROR 143
#define T_LOOKUP 144
-#define T_PIPE 145
-#define T_PASS 146
-#define T_INSERT_PASS 147
+#define T_HASH 145
+#define T_PIPE 146
+#define T_PASS 147
#define T_FETCH 148
#define T_INSERT 149
#define T_DELIVER 150