Commit b317d959 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Introduce VCL_STRANDS, and use it for string compare.

VCL_STRANDS is an alternative to VCL_STRING_LIST which uses a
struct instead of varargs.

This means that multiple VCL_STRANDS can be passed to a function,
and string-compare really needed that to not waste workspace.

Add <, >, <=, >= string comparisons while here anyway.

The struct and a const char *[N] array are built on the stack and
they are only valid for the duration of the function call.
parent 6f6242be
......@@ -156,6 +156,64 @@ VRT_GetHdr(VRT_CTX, const struct gethdr_s *hs)
return (p);
}
/*--------------------------------------------------------------------
* Build STRANDS from what is essentially a STRING_LIST
*/
VCL_STRANDS
VRT_BundleStrands(int n, struct strands *s, char const **d, const char *f, ...)
{
va_list ap;
s->n = n;
s->p = d;
*d++ = f;
va_start(ap, f);
while(--n)
*d++ = va_arg(ap, const char *);
assert(va_arg(ap, const char *) == vrt_magic_string_end);
va_end(ap);
return (s);
}
/*--------------------------------------------------------------------
* Compare two STRANDS
*/
int
VRT_CompareStrands(VCL_STRANDS a, VCL_STRANDS b)
{
const char *pa = NULL, *pb = NULL;
int na = 0, nb = 0;
while (1) {
if (pa != NULL && *pa == '\0')
pa = NULL;
if (pb != NULL && *pb == '\0')
pb = NULL;
if (pa == NULL && na < a->n)
pa = a->p[na++];
else if (pb == NULL && nb < b->n)
pb = b->p[nb++];
else if (pa == NULL && pb == NULL)
return (0);
else if (pa == NULL)
return (-1);
else if (pb == NULL)
return (1);
else if (*pa == '\0')
pa = NULL;
else if (*pb == '\0')
pb = NULL;
else if (*pa != *pb)
return (*pa - *pb);
else {
pa++;
pb++;
}
}
}
/*--------------------------------------------------------------------
* Collapse a STRING_LIST in the space provided, or return NULL
*/
......@@ -341,7 +399,7 @@ VRT_r_now(VRT_CTX)
/*--------------------------------------------------------------------*/
char *
VCL_STRING v_matchproto_()
VRT_IP_string(VRT_CTX, VCL_IP ip)
{
char *p;
......@@ -361,7 +419,7 @@ VRT_IP_string(VRT_CTX, VCL_IP ip)
return (p);
}
char *
VCL_STRING v_matchproto_()
VRT_INT_string(VRT_CTX, long num)
{
......@@ -369,7 +427,7 @@ VRT_INT_string(VRT_CTX, long num)
return (WS_Printf(ctx->ws, "%ld", num));
}
char *
VCL_STRING v_matchproto_()
VRT_REAL_string(VRT_CTX, double num)
{
......@@ -377,7 +435,7 @@ VRT_REAL_string(VRT_CTX, double num)
return (WS_Printf(ctx->ws, "%.3f", num));
}
char *
VCL_STRING v_matchproto_()
VRT_TIME_string(VRT_CTX, double t)
{
char *p;
......@@ -389,7 +447,7 @@ VRT_TIME_string(VRT_CTX, double t)
return (p);
}
const char * v_matchproto_()
VCL_STRING v_matchproto_()
VRT_BACKEND_string(VCL_BACKEND d)
{
if (d == NULL)
......@@ -398,7 +456,7 @@ VRT_BACKEND_string(VCL_BACKEND d)
return (d->vcl_name);
}
const char *
VCL_STRING v_matchproto_()
VRT_BOOL_string(unsigned val)
{
......
......@@ -12,7 +12,7 @@ server s1 {
txresp -hdr "Content-Type: text/plain" -body response
} -start
varnish v1 -vcl+backend {} -start
varnish v1 -vcl+backend {} -start -cliok "param.set debug +syncvsl"
client c1 {
txreq -req POST -hdr "Content-Type: text/plain" -body request
......
varnishtest "Test VCL STRINGS/STRANDS comparisons"
server s1 {
rxreq
txresp
} -start
varnish v1 -vcl+backend {
sub vcl_deliver {
set resp.http.test = req.http.test;
set resp.http.eq =
req.http.foo == req.http.bar;
set resp.http.neq =
req.http.foo != req.http.bar;
set resp.http.lt =
req.http.foo < req.http.bar;
set resp.http.le =
req.http.foo <= req.http.bar;
set resp.http.gt =
req.http.foo > req.http.bar;
set resp.http.ge =
req.http.foo >= req.http.bar;
}
} -start
client c1 {
txreq -hdr "foo: 1" -hdr "bar: 1" -hdr "test: 1"
rxresp
expect resp.http.eq == true
expect resp.http.neq == false
expect resp.http.lt == false
expect resp.http.le == true
expect resp.http.gt == false
expect resp.http.ge == true
txreq -hdr "foo: 1" -hdr "bar: 2" -hdr "test: 2"
rxresp
expect resp.http.eq == false
expect resp.http.neq == true
expect resp.http.lt == true
expect resp.http.le == true
expect resp.http.gt == false
expect resp.http.ge == false
txreq -hdr "foo: 2" -hdr "bar: 1" -hdr "test: 3"
rxresp
expect resp.http.eq == false
expect resp.http.neq == true
expect resp.http.lt == false
expect resp.http.le == false
expect resp.http.gt == true
expect resp.http.ge == true
txreq -hdr "foo: 1" -hdr "bar: 11" -hdr "test: 4"
rxresp
expect resp.http.eq == false
expect resp.http.neq == true
expect resp.http.lt == true
expect resp.http.le == true
expect resp.http.gt == false
expect resp.http.ge == false
txreq -hdr "foo: 11" -hdr "bar: 1" -hdr "test: 5"
rxresp
expect resp.http.eq == false
expect resp.http.neq == true
expect resp.http.lt == false
expect resp.http.le == false
expect resp.http.gt == true
expect resp.http.ge == true
txreq -hdr "foo:" -hdr "bar:" -hdr "test: 6"
rxresp
expect resp.http.eq == true
expect resp.http.neq == false
expect resp.http.lt == false
expect resp.http.le == true
expect resp.http.gt == false
expect resp.http.ge == true
txreq -hdr "foo:" -hdr "bar: 1" -hdr "test: 7"
rxresp
expect resp.http.eq == false
expect resp.http.neq == true
expect resp.http.lt == true
expect resp.http.le == true
expect resp.http.gt == false
expect resp.http.ge == false
} -run
varnish v1 -vsl_catchup -vcl+backend {
sub vcl_deliver {
set resp.http.test = req.http.test;
set resp.http.eq =
req.http.foo + " " == req.http.bar + " ";
set resp.http.neq =
req.http.foo + " " != req.http.bar + " ";
set resp.http.lt =
req.http.foo + " " < req.http.bar + " ";
set resp.http.le =
req.http.foo + " " <= req.http.bar + " ";
set resp.http.gt =
req.http.foo + " " > req.http.bar + " ";
set resp.http.ge =
req.http.foo + " " >= req.http.bar + " ";
}
}
client c1 -run
varnish v1 -vsl_catchup -vcl+backend {
sub vcl_deliver {
set resp.http.test = req.http.test;
set resp.http.eq =
req.http.foo == req.http.bar + req.http.not;
set resp.http.neq =
req.http.foo != req.http.bar + req.http.not;
set resp.http.lt =
req.http.foo < req.http.bar + req.http.not;
set resp.http.le =
req.http.foo <= req.http.bar + req.http.not;
set resp.http.gt =
req.http.foo > req.http.bar + req.http.not;
set resp.http.ge =
req.http.foo >= req.http.bar + req.http.not;
}
}
client c1 -run
varnish v1 -vsl_catchup -vcl+backend {
sub vcl_deliver {
set resp.http.test = req.http.test;
set resp.http.eq =
req.http.not + req.http.foo == req.http.bar + req.http.not;
set resp.http.neq =
req.http.not + req.http.foo != req.http.bar + req.http.not;
set resp.http.lt =
req.http.not + req.http.foo < req.http.bar + req.http.not;
set resp.http.le =
req.http.not + req.http.foo <= req.http.bar + req.http.not;
set resp.http.gt =
req.http.not + req.http.foo > req.http.bar + req.http.not;
set resp.http.ge =
req.http.not + req.http.foo >= req.http.bar + req.http.not;
}
}
client c1 -run
......@@ -61,6 +61,7 @@
* VRT_r_beresp_storage_hint() removed - under discussion #2509
* VRT_l_beresp_storage_hint() removed - under discussion #2509
* VRT_blob() added
* VCL_STRANDS added
* 6.1 (2017-09-15 aka 5.2)
* http_CollectHdrSep added
* VRT_purge modified (may fail a transaction, signature changed)
......@@ -114,6 +115,11 @@ struct vsb;
struct vsl_log;
struct ws;
struct strands {
int n;
const char **p;
};
/***********************************************************************
* This is the central definition of the mapping from VCL types to
* C-types. The python scripts read these from here.
......@@ -136,6 +142,7 @@ typedef const struct suckaddr * VCL_IP;
typedef const struct vrt_backend_probe * VCL_PROBE;
typedef double VCL_REAL;
typedef const struct stevedore * VCL_STEVEDORE;
typedef const struct strands * VCL_STRANDS;
typedef const char * VCL_STRING;
typedef double VCL_TIME;
typedef struct vcl * VCL_VCL;
......@@ -421,14 +428,19 @@ VCL_STEVEDORE VRT_stevedore(const char *nm);
/* Convert things to string */
char *VRT_IP_string(VRT_CTX, VCL_IP);
char *VRT_INT_string(VRT_CTX, VCL_INT);
char *VRT_REAL_string(VRT_CTX, VCL_REAL);
char *VRT_TIME_string(VRT_CTX, VCL_TIME);
const char *VRT_BOOL_string(VCL_BOOL);
const char *VRT_BACKEND_string(VCL_BACKEND);
const char *VRT_STEVEDORE_string(VCL_STEVEDORE);
const char *VRT_CollectString(VRT_CTX, const char *p, ...);
VCL_STRANDS VRT_BundleStrands(int, struct strands *, char const **,
const char *f, ...);
int VRT_CompareStrands(VCL_STRANDS a, VCL_STRANDS b);
VCL_STRING VRT_BACKEND_string(VCL_BACKEND);
VCL_STRING VRT_BOOL_string(VCL_BOOL);
VCL_STRING VRT_CollectString(VRT_CTX, const char *p, ...);
VCL_STRING VRT_INT_string(VRT_CTX, VCL_INT);
VCL_STRING VRT_IP_string(VRT_CTX, VCL_IP);
VCL_STRING VRT_REAL_string(VRT_CTX, VCL_REAL);
VCL_STRING VRT_STEVEDORE_string(VCL_STEVEDORE);
VCL_STRING VRT_STRANDS_string(VCL_STRANDS);
VCL_STRING VRT_TIME_string(VRT_CTX, VCL_TIME);
#ifdef va_start // XXX: hackish
void *VRT_VSC_Alloc(const char *, size_t, size_t, const unsigned char *, size_t,
......
This diff is collapsed.
......@@ -131,7 +131,11 @@ const struct type STEVEDORE[1] = {{
const struct type STRING[1] = {{
.magic = TYPE_MAGIC,
.name = "STRING",
.tostring = "",
}};
const struct type STRANDS[1] = {{
.magic = TYPE_MAGIC,
.name = "STRANDS",
}};
const struct type STRINGS[1] = {{
......
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