element:
Add two checkpoints for the sessions workspace.
The first checkpoint is after the session fixed data, and move the
client address and port to workspace to see that this works.
The second checkpoint is after the, as received unadultered by VCL
http request. Grab a copy of the http request matching this.
Implement rollback as an optional feature of restart in VCL.
Move various workspace initialization and resetting operations to more
suitable locations in the program flow.
I don't know if this is really usable, but now it's possible to do:
backend b1 {
set backend.host = "backend1";
set backend.port = "80";
}
backend b2 {
set backend.host = "backend2";
set backend.port = "80";
}
sub vcl_recv {
set req.backend = b1;
remove req.http.cookie;
if (req.restarts == 0) {
set req.url = "foobar.html";
} else {
set req.backend = b2;
}
}
sub vcl_fetch {
if (obj.status != 200) {
restart rollback;
}
}
And have it first look for "foobar.html" on one backend, and failing
that, try to give the user what they asked for from the other backend.
git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@2167
d4fa192b-c00b-0410-8231-
f00ffab90ce4
struct sockaddr *mysockaddr;
/* formatted ascii client address */
- char addr[TCP_ADDRBUFSIZE];
- char port[TCP_PORTBUFSIZE];
+ char *addr;
+ char *port;
struct srcaddr *srcaddr;
/* HTTP request */
const char *doclose;
struct http *http;
+ struct http *http0;
+
struct ws ws[1];
+ char *ws_ses; /* WS above session data */
+ char *ws_req; /* WS above request data */
struct http_conn htc[1];
void WS_Release(struct ws *ws, unsigned bytes);
void WS_ReleaseP(struct ws *ws, char *ptr);
void WS_Assert(const struct ws *ws);
-void WS_Reset(struct ws *ws);
+void WS_Reset(struct ws *ws, char *p);
char *WS_Alloc(struct ws *ws, unsigned bytes);
char *WS_Dup(struct ws *ws, const char *);
+char *WS_Snapshot(struct ws *ws);
/* rfc2616.c */
int RFC2616_cache_policy(const struct sess *sp, const struct http *hp);
void
VCA_Prep(struct sess *sp)
{
+ char addr[TCP_ADDRBUFSIZE];
+ char port[TCP_PORTBUFSIZE];
+
TCP_name(sp->sockaddr, sp->sockaddrlen,
- sp->addr, sizeof sp->addr, sp->port, sizeof sp->port);
+ addr, sizeof addr, port, sizeof port);
+ sp->addr = WS_Dup(sp->ws, addr);
+ sp->port = WS_Dup(sp->ws, port);
VSL(SLT_SessionOpen, sp->fd, "%s %s", sp->addr, sp->port);
sp->acct.first = sp->t_open;
if (need_test)
sp->id = i;
sp->t_open = now;
- HTC_Init(sp->htc, sp->ws, sp->fd);
sp->step = STP_FIRST;
WRK_QueueSession(sp);
}
return (1);
}
+ /* Reset the workspace to the session-watermark */
+ WS_Reset(sp->ws, sp->ws_ses);
+
i = HTC_Reinit(sp->htc);
if (i == 1) {
VSL_stats->sess_pipeline++;
assert(sp->xid == 0);
VCA_Prep(sp);
+
+ /* Record the session watermark */
+ sp->ws_ses = WS_Snapshot(sp->ws);
+
+ /* Receive a HTTP protocol request */
+ HTC_Init(sp->htc, sp->ws, sp->fd);
sp->wrk->used = sp->t_open;
sp->wrk->acct.sess++;
SES_RefSrcAddr(sp);
do
i = HTC_Rx(sp->htc);
while (i == 0);
+
switch (i) {
case 1:
sp->step = STP_RECV;
sp->vcl = sp->wrk->vcl;
sp->wrk->vcl = NULL;
+ http_Setup(sp->http, sp->ws);
done = http_DissectRequest(sp);
+
+ /* Catch request snapshot */
+ sp->ws_req = WS_Snapshot(sp->ws);
+
+ /* Catch original request, before modification */
+ *sp->http0 = *sp->http;
+
if (done != 0) {
RES_Error(sp, done, NULL); /* XXX: STP_ERROR ? */
sp->step = STP_DONE;
htc->magic = HTTP_CONN_MAGIC;
htc->ws = ws;
htc->fd = fd;
- WS_Reset(htc->ws);
WS_Reserve(htc->ws, (htc->ws->e - htc->ws->s) / 2);
htc->rxbuf.b = ws->f;
htc->rxbuf.e = ws->f;
int i;
CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
- WS_Reset(htc->ws);
WS_Reserve(htc->ws, (htc->ws->e - htc->ws->s) / 2);
htc->rxbuf.b = htc->ws->f;
htc->rxbuf.e = htc->ws->f;
#define SESSMEM_MAGIC 0x555859c5
struct sess sess;
- struct http http;
+ struct http http[2];
unsigned workspace;
VTAILQ_ENTRY(sessmem) list;
struct sockaddr_storage sockaddr[2];
}
WS_Init(sp->ws, (void *)(sm + 1), sm->workspace);
- sp->http = &sm->http;
- http_Setup(sp->http, sp->ws);
+ sp->http = &sm->http[0];
+ sp->http0 = &sm->http[1];
return (sp);
}
/*--------------------------------------------------------------------*/
+void
+VRT_Rollback(struct sess *sp)
+{
+
+ *sp->http = *sp->http0;
+ WS_Reset(sp->ws, sp->ws_req);
+}
+
+/*--------------------------------------------------------------------*/
+
void
VRT_purge(const char *regexp, int hash)
{
}
void
-WS_Reset(struct ws *ws)
+WS_Reset(struct ws *ws, char *p)
{
WS_Assert(ws);
assert(ws->r == NULL);
- ws->f = ws->s;
+ if (p == NULL)
+ ws->f = ws->s;
+ else {
+ assert(p >= ws->s);
+ assert(p < ws->e);
+ ws->f = p;
+ }
}
char *
return (p);
}
+char *
+WS_Snapshot(struct ws *ws)
+{
+
+ assert(ws->r == NULL);
+ return (ws->f);
+}
+
unsigned
WS_Reserve(struct ws *ws, unsigned bytes)
{
int VRT_strcmp(const char *s1, const char *s2);
void VRT_ESI(struct sess *sp);
-
+void VRT_Rollback(struct sess *sp);
/* Backend related */
void VRT_init_simple_backend(struct backend **, const struct vrt_simple_backend *);
/*--------------------------------------------------------------------*/
+static void
+parse_restart_real(struct tokenlist *tl)
+{
+ struct token *t1;
+
+ t1 = VTAILQ_NEXT(tl->t, list);
+ if (t1->tok == ID && vcc_IdIs(t1, "rollback")) {
+ Fb(tl, 1, "VRT_Rollback(sp);\n");
+ vcc_NextToken(tl);
+ } else if (t1->tok != ';') {
+ vsb_printf(tl->sb, "Expected \"rollback\" or semicolon.\n");
+ vcc_ErrWhere(tl, t1);
+ ERRCHK(tl);
+ }
+ parse_restart(tl);
+}
+
+/*--------------------------------------------------------------------*/
+
static void
parse_call(struct tokenlist *tl)
{
const char *name;
action_f *func;
} action_table[] = {
+ { "restart", parse_restart_real },
#define VCL_RET_MAC(l, u, b, i) { #l, parse_##l },
#define VCL_RET_MAC_E(l, u, b, i) VCL_RET_MAC(l, u, b, i)
#include "vcl_returns.h"
vsb_cat(sb, "int VRT_strcmp(const char *s1, const char *s2);\n");
vsb_cat(sb, "\n");
vsb_cat(sb, "void VRT_ESI(struct sess *sp);\n");
- vsb_cat(sb, "\n");
+ vsb_cat(sb, "void VRT_Rollback(struct sess *sp);\n");
vsb_cat(sb, "\n");
vsb_cat(sb, "/* Backend related */\n");
vsb_cat(sb, "void VRT_init_simple_backend(struct backend **, const struct vrt_simple_backend *);\n");