Commit 3b589fda authored by Joshua Bussdieker's avatar Joshua Bussdieker

Got Vary tests working against Key

parent dcb05230
......@@ -307,6 +307,16 @@ vbf_stp_fetch(struct worker *wrk, struct busyobj *bo)
AN(key);
assert(keyl == VSB_len(key));
l += keyl;
} else if (keyl < 0) {
/*
* Key parse error
* Complain about it, and make this a pass.
*/
VSLb(bo->vsl, SLT_Error,
"Illegal 'Key' header from backend, "
"making this a pass.");
bo->uncacheable = 1;
AZ(key);
} else {
#endif
varyl = VRY_Create(bo, &vary);
......
#include <stdio.h>
//#include "config.h"
#include "cache.h"
......@@ -12,7 +13,9 @@
#define M_CASE 5
#define M_NOT 6
void hexDump (char *desc, void *addr, int len) {
#define DEBUG 1
int hexDump (char *desc, void *addr, int len) {
int i;
unsigned char buff[17];
unsigned char *pc = addr;
......@@ -53,12 +56,13 @@ void hexDump (char *desc, void *addr, int len) {
// And print the final ASCII bit.
printf (" %s\n", buff);
return 0;
}
int
key_ParseMatcher(const char *s, struct vsb **sb) {
char *p = s;
char *e;
const char *p = s;
const char *e;
while (*p == ';') {
if (*p != ';')
return -1;
......@@ -105,14 +109,26 @@ key_ParseMatcher(const char *s, struct vsb **sb) {
return p - s;
}
/*
* Find length of a key entry
*/
static unsigned
key_len(const uint8_t *p)
{
unsigned l = vbe16dec(p);
return (3 + p[3] + 2 + (l == 0xffff ? 0 : l));
}
int
KEY_Create(struct busyobj *bo, struct vsb **psb)
{
printf("KEY_Create(bo: %p, psb: %p)\n", bo, *psb);
DEBUG && printf("KEY_Create(bo: %p, psb: %p)\n", bo, *psb);
char *v, *h, *e, *p, *q, *m, *mm, *me;
struct vsb *sb, *sbh, *sbm;
unsigned l;
int matcher = 0;
int error = 0;
CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
CHECK_OBJ_NOTNULL(bo->bereq, HTTP_MAGIC);
......@@ -141,13 +157,20 @@ KEY_Create(struct busyobj *bo, struct vsb **psb)
for (q = p; *q && !vct_issp(*q) && *q != ',' && *q != ';'; q++)
continue;
if (q - p > INT8_MAX) {
VSLb(bo->vsl, SLT_Error,
"Key header name length exceeded");
error = 1;
break;
}
/* Build header matching string */
VSB_clear(sbh);
VSB_printf(sbh, "%c%.*s:%c",
(char)(1 + (q - p)), (int)(q - p), p, 0);
AZ(VSB_finish(sbh));
printf(" - Entry: %.*s\n", (int)(q - p), p);
DEBUG && printf(" - Entry: %.*s\n", (int)(q - p), p);
// Using matchers
if (*q == ';') {
......@@ -158,6 +181,7 @@ KEY_Create(struct busyobj *bo, struct vsb **psb)
else {
// TODO: Cleanup allocations
printf("ERROR\n");
error = 1;
return 0;
}
AZ(VSB_finish(sbm));
......@@ -200,143 +224,117 @@ KEY_Create(struct busyobj *bo, struct vsb **psb)
if (*q == '\0')
break;
if (*q != ',') {
VSLb(bo->vsl, SLT_Error, "Malformed Key header");
error = 1;
break;
}
p = q;
}
if (error) {
VSB_delete(sbh);
VSB_delete(sb);
return (-1);
}
/* Terminate key matching string */
VSB_printf(sb, "%c%c%c", 0xff, 0xff, 0);
VSB_printf(sb, "%c%c%c%c", 0xff, 0xff, 0, 0);
VSB_delete(sbh);
AZ(VSB_finish(sb));
*psb = sb;
printf("KEY_Create(bo: %p, psb: %p) = %d\n", bo, *psb, VSB_len(sb));
hexDump("key", VSB_data(sb), VSB_len(sb));
DEBUG && printf("KEY_Create(bo: %p, psb: %p) = %zu\n", bo, *psb, VSB_len(sb));
DEBUG && hexDump("key", VSB_data(sb), VSB_len(sb));
return (VSB_len(sb));
}
void
KEY_Prep(struct req *req)
{
req->key_b = req->vary_b;
req->key_l = req->vary_l;
req->key_e = req->vary_e;
}
void
KEY_Finish(struct req *req, struct busyobj *bo)
{
if (bo != NULL) {
CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
KEY_Validate(req->key_b);
if (req->key_l != NULL) {
bo->key = WS_Copy(bo->ws,
req->key_b, req->key_l - req->key_b);
AN(bo->key);
KEY_Validate(bo->key);
} else
bo->key = NULL;
}
//WS_Release(req->ws, 0);
req->key_b = NULL;
req->key_l = NULL;
req->key_e = NULL;
}
/*
* Find length of a key entry
*/
static unsigned
key_len(const uint8_t *p)
{
unsigned l = vbe16dec(p);
return (3 + p[3] + 2 + (l == 0xffff ? 0 : l));
}
/*
* Compare two key entries
*/
static int
key_cmp(const uint8_t *v1, const uint8_t *v2)
KEY_Validate(const uint8_t *key)
{
unsigned retval = 0;
//hexDump("key_cmp(v1)", v1, key_len(v1));
//hexDump("key_cmp(v2)", v2, key_len(v2));
if (!memcmp(v1, v2, key_len(v1))) {
printf(" same same\n");
/* Same same */
retval = 0;
} else if (memcmp(v1 + 2, v2 + 2, v1[3] + 2)) {
printf(" diff header\n");
/* Different header */
retval = 1;
} else if (cache_param->http_gzip_support &&
!strcasecmp(H_Accept_Encoding, (const char*) v1 + 2)) {
printf(" accept enc\n");
/*
* If we do gzip processing, we do not key on Accept-Encoding,
* because we want everybody to get the gzip'ed object, and
* varnish will gunzip as necessary. We implement the skip at
* check time, rather than create time, so that object in
* persistent storage can be used with either setting of
* http_gzip_support.
*/
retval = 0;
} else {
printf(" same header diff content\n");
/* Same header, different content */
retval = 2;
DEBUG && hexDump("key", key, 32);
while (key[3] != 0) {
assert(strlen((const char*)key+4) == key[3]);
key += key_len(key);
}
return retval;
}
int
KEY_Match(struct req *req, const uint8_t *key)
{
printf("KEY_Match(req: %p, key: %p)\n", req, key);
DEBUG && printf("KEY_Match(req: %p, key: %p)\n", req, key);
uint8_t *vsp = req->key_b;
char *h;
int i;
AN(vsp);
while (key[3]) {
// Exception for gzip
if (cache_param->http_gzip_support &&
!strcasecmp(H_Accept_Encoding, (const char*) key + 3)) {
// Exact match
if (key[2] == 0) {
printf(" - Exact: %s\n", key+4);
i = key_cmp(key, vsp);
if (i == 1) {
/*
* Different header, build a new entry,
* then compare again with that new entry.
*/
//ln = 2 + key[3] + 2;
i = http_GetHdr(req->http, (const char*)(key+3), &h);
printf(" - Got %d bytes of %s\n", i, h);
} else if (key[2] == 0) {
char *e;
unsigned l = vbe16dec(key);
DEBUG && printf(" Header (Exact): %s\n", key + 4);
i = http_GetHdr(req->http, (const char*)(key+3), &h);
if (l == 0xFFFF) {
// Expect missing
if (i == 0) {
// Expected missing, is missing
DEBUG && printf(" * Expected missing, is missing\n");
} else {
// Expected missing, is present
DEBUG && printf(" * Expected missing, is present\n");
return 0;
}
} else {
// Expect present
const char *value = key + 4 + key[3] + 1;
DEBUG && printf(" - Value: %.*s\n", l, value);
if (i == 0) {
// Expected present, is missing
DEBUG && printf(" * Expected present, is missing\n");
return 0;
} else {
// Expected present, is present
DEBUG && printf(" * Expected present, is present\n");
AZ(vct_issp(*h));
/* Trim trailing space */
e = strchr(h, '\0');
while (e > h && vct_issp(e[-1]))
e--;
if (l != (int)(e - h)) {
// Different lengths, no match
DEBUG && printf(" * Different lengths, no match\n");
return 0;
} else {
if (memcmp(h, value, l) == 0) {
// Same length, match
DEBUG && printf(" * Same length, match\n");
} else {
// Same length, no match
DEBUG && printf(" * Same length, no match\n");
return 0;
}
}
}
}
// Matcher match
} else if (key[2] == 1) {
printf(" - Matcher: %s\n", key+4);
DEBUG && printf(" - Matcher: %s\n", key+4);
}
key += key_len(key);
}
printf("KEY_Match(req: %p, key: %p) = 0\n", req, key);
return 0;
}
void
KEY_Validate(const uint8_t *key)
{
while (key[3] != 0) {
assert(strlen((const char*)key+4) == key[3]);
key += key_len(key);
}
DEBUG && printf("KEY_Match(req: %p, key: %p) = 0\n", req, key);
return 1;
}
......@@ -418,9 +418,6 @@ cnt_lookup(struct worker *wrk, struct req *req)
AZ(req->busyobj);
VRY_Prep(req);
#ifdef KEY_HEADER
KEY_Prep(req);
#endif
AZ(req->objcore);
lr = HSH_Lookup(req, &oc, &boc,
......@@ -495,9 +492,6 @@ cnt_lookup(struct worker *wrk, struct req *req)
CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
req->obj = o;
#ifdef KEY_HEADER
KEY_Finish(req, NULL);
#endif
VRY_Finish(req, NULL);
if (oc->flags & OC_F_PASS)
......@@ -580,9 +574,6 @@ cnt_miss(struct worker *wrk, struct req *req)
bo = VBO_GetBusyObj(wrk, req);
CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
req->busyobj = bo;
#ifdef KEY_HEADER
KEY_Finish(req, bo);
#endif
VRY_Finish(req, bo);
VCL_miss_method(req->vcl, wrk, req, NULL, req->http->ws);
......@@ -896,18 +887,12 @@ cnt_purge(struct worker *wrk, struct req *req)
AZ(req->busyobj);
VRY_Prep(req);
#ifdef KEY_HEADER
KEY_Prep(req);
#endif
AZ(req->objcore);
lr = HSH_Lookup(req, &oc, &boc, 1, 1);
assert (lr == HSH_MISS);
AZ(oc);
CHECK_OBJ_NOTNULL(boc, OBJCORE_MAGIC);
#ifdef KEY_HEADER
KEY_Finish(req, NULL);
#endif
VRY_Finish(req, NULL);
HSH_Purge(wrk, boc->objhead, 0, 0);
......
varnishtest "Test Key functionality"
server s1 {
rxreq
expect req.http.foobar == "1"
txresp -hdr "Key: Foobar" -hdr "Snafu: 1" -body "1111\n"
rxreq
expect req.http.foobar == "2"
txresp -hdr "Key: Foobar" -hdr "Snafu: 2" -body "2222\n"
rxreq
expect req.http.foobar == "3"
txresp -hdr "Key: Foobar" -hdr "Snafu: 3" -body "3333\n"
rxreq
txresp -hdr "Key: Foobar" -hdr "Snafu: 4" -body "4444\n"
} -start
varnish v1 -vcl+backend {} -start
client c1 {
txreq -hdr "Foobar: 1"
rxresp
expect resp.status == 200
expect resp.http.X-Varnish == "1001"
expect resp.http.snafu == "1"
txreq -hdr "Foobar: 2"
rxresp
expect resp.status == 200
expect resp.http.X-Varnish == "1003"
expect resp.http.snafu == "2"
txreq -hdr "Foobar: 3"
rxresp
expect resp.status == 200
expect resp.http.X-Varnish == "1005"
expect resp.http.snafu == "3"
txreq
rxresp
expect resp.status == 200
expect resp.http.X-Varnish == "1007"
expect resp.http.snafu == "4"
txreq -hdr "Foobar: 1 "
rxresp
expect resp.status == 200
expect resp.http.X-Varnish == "1009 1002"
expect resp.http.snafu == "1"
} -run
varnishtest "test purging from vcl"
server s1 {
rxreq
expect req.url == "/1"
expect req.http.foo == "foo1"
txresp -hdr "Key: foo" -bodylen 1
rxreq
expect req.url == "/1"
expect req.http.foo == "foo2"
txresp -hdr "Key: foo" -bodylen 2
rxreq
expect req.url == "/1"
expect req.http.foo == "foo2"
txresp -hdr "Key: foo" -bodylen 12
rxreq
expect req.url == "/1"
expect req.http.foo == "foo1"
txresp -hdr "Key: foo" -bodylen 11
rxreq
expect req.url == "/1"
expect req.http.foo == "foo3"
txresp -hdr "Key: foo" -bodylen 23
rxreq
expect req.url == "/1"
expect req.http.foo == "foo1"
txresp -hdr "Key: foo" -bodylen 21
rxreq
expect req.url == "/1"
expect req.http.foo == "foo2"
txresp -hdr "Key: foo" -bodylen 22
} -start
varnish v1 -vcl+backend {
sub vcl_miss { if (req.http.purge == "yes") { purge; } }
sub vcl_lookup { if (req.http.purge == "yes") { purge; return(restart);} }
} -start
client c1 {
txreq -url "/1" -hdr "foo: foo1"
rxresp
expect resp.status == 200
expect resp.bodylen == 1
txreq -url "/1" -hdr "Foo: foo2"
rxresp
expect resp.status == 200
expect resp.bodylen == 2
txreq -url "/1" -hdr "foo: foo1"
rxresp
expect resp.status == 200
expect resp.bodylen == 1
txreq -url "/1" -hdr "Foo: foo2"
rxresp
expect resp.status == 200
expect resp.bodylen == 2
# Purge on hit
txreq -url "/1" -hdr "Foo: foo2" -hdr "purge: yes"
rxresp
expect resp.status == 200
expect resp.bodylen == 12
txreq -url "/1" -hdr "foo: foo1"
rxresp
expect resp.status == 200
expect resp.bodylen == 11
# Purge on miss
txreq -url "/1" -hdr "Foo: foo3" -hdr "purge: yes"
rxresp
expect resp.status == 200
expect resp.bodylen == 23
txreq -url "/1" -hdr "foo: foo1"
rxresp
expect resp.status == 200
expect resp.bodylen == 21
txreq -url "/1" -hdr "Foo: foo2"
rxresp
expect resp.status == 200
expect resp.bodylen == 22
} -run
varnish v1 -errvcl {'purge': not a valid action in method 'vcl_recv'.} {
backend s1 { .host = "${s1_addr}"; }
sub vcl_recv { if (req.http.purge == "yes") { purge; } }
}
varnishtest "Test that esi+gzip correctly bypasses Key: accept-encoding"
server s1 {
rxreq
expect req.http.accept-encoding == gzip
txresp -hdr "Key: Accept-encoding" -gzipbody {FOO}
} -start
varnish v1 -vcl+backend { } -start
client c1 {
txreq -hdr "Accept-encoding: gzip"
rxresp
expect resp.http.content-encoding == gzip
expect resp.status == 200
gunzip
expect resp.bodylen == 3
txreq
rxresp
expect resp.http.content-encoding == <undef>
expect resp.status == 200
expect resp.bodylen == 3
} -run
varnishtest "Check that Key headers are stored"
shell "rm -f ${tmpdir}/_.per"
server s1 {
rxreq
txresp -hdr "Foo: foo1" -hdr "Key: foo, bar"
rxreq
txresp -hdr "Foo: foo2" -hdr "Key: foo, bar"
} -start
varnish v1 \
-storage "-spersistent,${tmpdir}/_.per,10m" \
-arg "-pban_lurker_sleep=0" \
-vcl+backend { } -start
client c1 {
txreq -url "/foo" -hdr "foo: 1" -hdr "bar: 2"
rxresp
expect resp.status == 200
expect resp.http.X-Varnish == "1001"
expect resp.http.foo == "foo1"
txreq -url "/foo" -hdr "foo: 2" -hdr "bar: 1"
rxresp
expect resp.status == 200
expect resp.http.X-Varnish == "1003"
expect resp.http.foo == "foo2"
} -run
varnish v1 -expect n_object == 2
server s1 -wait
varnish v1 -stop
varnish v1 -start
varnish v1 -cliok "debug.xid 1999"
varnish v1 -expect n_vampireobject == 2
client c1 {
txreq -url "/foo" -hdr "foo: 1" -hdr "bar: 2"
rxresp
expect resp.status == 200
expect resp.http.X-Varnish == "2001 1002"
expect resp.http.foo == "foo1"
txreq -url "/foo" -hdr "foo: 2" -hdr "bar: 1"
rxresp
expect resp.status == 200
expect resp.http.X-Varnish == "2002 1004"
expect resp.http.foo == "foo2"
} -run
varnishtest "Key header with extra colon"
server s1 {
rxreq
txresp -hdr "Key:: foo" -hdr "Foo: bar" -bodylen 9
rxreq
txresp -hdr "Key:: foo" -hdr "Foo: bar" -bodylen 8
} -start
varnish v1 -vcl+backend {} -start
client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.bodylen == 9
txreq
rxresp
expect resp.status == 200
expect resp.bodylen == 8
} -run
varnishtest "insanely long key string"
server s1 {
rxreq
txresp -hdr "Key: Foo" -body "xxxx"
rxreq
txresp -hdr "Key: Foo" -body "yyyyy"
} -start
varnish v1 \
-cliok "param.set workspace_client 8k" \
-cliok "param.set workspace_backend 200k" \
-vcl+backend {
} -start
client c1 {
txreq -hdr "Foo: blabla"
rxresp
expect resp.bodylen == 4
#txreq -hdr "Foo: blablaA"
txreq -hdr "Foo: blablaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaaaaaaaaaaaaaaaaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
rxresp
expect resp.bodylen == 5
} -run
varnishtest "#1274 - panic when Key field-name is too large to fit in a signed char"
server s1 {
rxreq
# Key header more than 127 characters long
txresp -hdr "Key: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -bodylen 9
rxreq
# Key header more than 127 characters long
txresp -hdr "Key: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -bodylen 8
} -start
varnish v1 -vcl+backend { } -start
client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.bodylen == 9
txreq
rxresp
expect resp.status == 200
expect resp.bodylen == 8
} -run
varnishtest "#1275 - panic with malformed Key header"
server s1 {
rxreq
txresp -hdr "Key: foo bar"
} -start
varnish v1 -vcl+backend { } -start
client c1 {
txreq
rxresp
expect resp.status == 200
} -run
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment