Commit 5cea4e6d authored by Geoff Simmons's avatar Geoff Simmons

Add the .bool() method.

parent 43541478
......@@ -28,7 +28,7 @@ SYNOPSIS
new <obj> = selector.set([BOOL case_sensitive]
[, BOOL allow_overlaps])
VOID <obj>.add(STRING [, STRING string] [, STRING regex]
[, BACKEND backend] [, INT integer])
[, BACKEND backend] [, INT integer] [, BOOL bool])
VOID <obj>.create_stats()
# Matching
......@@ -43,8 +43,9 @@ SYNOPSIS
# Retrieving objects by index, by string, or after match
STRING <obj>.element([INT n] [, ENUM select])
STRING <obj>.string([INT n] [, STRING element] [, ENUM select])
INT <obj>.integer([INT n] [, STRING element] [, ENUM select])
BACKEND <obj>.backend([INT n] [, STRING element] [, ENUM select])
INT <obj>.integer([INT n] [, STRING element] [, ENUM select])
BOOL <obj>.bool([INT n] [, STRING element] [, ENUM select])
BOOL <obj>.re_match(STRING [, INT n] [, STRING element]
[, ENUM select])
STRING <obj>.sub(STRING text, STRING rewrite [, BOOL all] [, INT n]
......@@ -437,8 +438,8 @@ Examples::
.. _xset.add():
VOID xset.add(STRING, [STRING string], [STRING regex], [BACKEND backend], [INT integer])
----------------------------------------------------------------------------------------
VOID xset.add(STRING, [STRING string], [STRING regex], [BACKEND backend], [INT integer], [BOOL bool])
-----------------------------------------------------------------------------------------------------
::
......@@ -447,7 +448,8 @@ VOID xset.add(STRING, [STRING string], [STRING regex], [BACKEND backend], [INT i
[STRING string],
[STRING regex],
[BACKEND backend],
[INT integer]
[INT integer],
[BOOL bool]
)
Add the given string to the set. As indicated above, elements added to
......@@ -455,10 +457,10 @@ the set are implicitly numbered in the order in which they are added
with ``.add()``, starting with 1.
If values are set for the optional parameters ``string``, ``regex``,
``backend`` or ``integer``, then those values are associated with this
element, and can be retrieved with the ``.string()``, ``.backend()``,
``.integer()``, ``.re_match()`` or ``.sub()`` methods, as described
below.
``backend``, ``integer`` or ``bool``, then those values are associated
with this element, and can be retrieved with the ``.string()``,
``.backend()``, ``.integer()``, ``.bool()``, ``.re_match()`` or
``.sub()`` methods, as described below.
A regular expression in the ``regex`` parameter is compiled at VCL load
time. If the compile fails, then the VCL load fails with an error message.
......@@ -895,6 +897,49 @@ Example::
}
}
.. _xset.bool():
BOOL xset.bool(INT n, STRING element, ENUM select)
--------------------------------------------------
::
BOOL xset.bool(
INT n=0,
STRING element=0,
ENUM {UNIQUE, EXACT, FIRST, LAST, SHORTEST, LONGEST} select=UNIQUE
)
Returns the boolean value set by the ``bool`` parameter for the
element of the set indicated by ``n``, ``element`` and ``select``,
according to the rules given above.
``.bool()`` invokes VCL failure if:
* The rules for ``n``, ``element`` and ``select`` indicate failure.
* No boolean was set with the ``bool`` parameter in ``.add()``.
Example::
# Match domains to the Host header, and append "www." where
# necessary.
sub vcl_init {
new domains = selector.set();
domains.add("example.com", bool=true);
domains.add("www.example.net", bool=false);
domains.add("example.org", bool=true);
domains.add("www.example.edu", bool=false)
}
sub vcl_recv {
if (domains.match(req.http.Host)) {
if (domains.bool()) {
set req.http.Host = "www." + req.http.Host;
}
}
}
.. _xset.re_match():
BOOL xset.re_match(STRING subject, INT n, STRING element, ENUM select)
......
......@@ -255,3 +255,21 @@ vmod_set_sub(VRT_CTX, struct vmod_selector_set *set, VCL_STRING str,
return (NULL);
return (VRT_regsub(ctx, all, str, re, sub));
}
VCL_BOOL
vmod_set_bool(VRT_CTX, struct VPFX(selector_set) *set, VCL_INT n,
VCL_STRING element, VCL_ENUM selects)
{
unsigned idx;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, "bool", element, selects);
if (idx == UINT_MAX)
return (0);
if (!check_added(ctx, set, idx, BOOLEAN, "bool", "boolean"))
return (0);
return (set->table[idx]->bool);
}
# looks like -*- vcl -*-
varnishtest "bool() method"
varnish v1 -vcl {
import ${vmod_selector};
backend b None;
sub vcl_init {
new s = selector.set();
s.add("foo", bool=true);
s.add("bar", bool=false);
s.add("baz", bool=true);
s.add("quux", bool=false);
s.add("foobar", bool=true);
}
sub vcl_recv {
return (synth(200));
}
sub vcl_synth {
set resp.http.N-1 = s.bool(1);
set resp.http.N-2 = s.bool(2);
set resp.http.N-3 = s.bool(3);
set resp.http.N-4 = s.bool(4);
set resp.http.N-5 = s.bool(5);
if (s.match(req.http.Word)) {
set resp.http.Bool = s.bool();
set resp.http.Bool-Unique = s.bool(select=UNIQUE);
set resp.http.Bool-Exact = s.bool(select=EXACT);
set resp.http.Bool-First = s.bool(select=FIRST);
set resp.http.Bool-Last = s.bool(select=LAST);
set resp.http.Bool-Shortest = s.bool(select=SHORTEST);
set resp.http.Bool-Longest = s.bool(select=LONGEST);
}
set resp.http.Foo = s.bool(element="foo");
set resp.http.Bar = s.bool(element="bar");
set resp.http.Baz = s.bool(element="baz");
set resp.http.Quux = s.bool(element="quux");
set resp.http.Foobar = s.bool(element="foobar");
if (req.http.Element) {
set resp.http.Element
= s.bool(element=req.http.Element);
}
return (deliver);
}
} -start
client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.N-1 == true
expect resp.http.N-2 == false
expect resp.http.N-3 == true
expect resp.http.N-4 == false
expect resp.http.N-5 == true
expect resp.http.Foo == true
expect resp.http.Bar == false
expect resp.http.Baz == true
expect resp.http.Quux == false
expect resp.http.Foobar == true
txreq -hdr "Word: foo"
rxresp
expect resp.status == 200
expect resp.http.Bool == true
expect resp.http.Bool-Unique == resp.http.Bool
expect resp.http.Bool-Exact == resp.http.Bool
expect resp.http.Bool-First == true
expect resp.http.Bool-Last == true
expect resp.http.Bool-Shortest == true
expect resp.http.Bool-Longest == true
txreq -hdr "Word: bar"
rxresp
expect resp.status == 200
expect resp.http.Bool == false
expect resp.http.Bool-Unique == resp.http.Bool
expect resp.http.Bool-Exact == resp.http.Bool
expect resp.http.Bool-First == false
expect resp.http.Bool-Last == false
expect resp.http.Bool-Shortest == false
expect resp.http.Bool-Longest == false
txreq -hdr "Word: baz"
rxresp
expect resp.status == 200
expect resp.http.Bool == true
expect resp.http.Bool-Unique == resp.http.Bool
expect resp.http.Bool-Exact == resp.http.Bool
expect resp.http.Bool-First == true
expect resp.http.Bool-Last == true
expect resp.http.Bool-Shortest == true
expect resp.http.Bool-Longest == true
txreq -hdr "Word: quux"
rxresp
expect resp.status == 200
expect resp.http.Bool == false
expect resp.http.Bool-Unique == resp.http.Bool
expect resp.http.Bool-Exact == resp.http.Bool
expect resp.http.Bool-First == false
expect resp.http.Bool-Last == false
expect resp.http.Bool-Shortest == false
expect resp.http.Bool-Longest == false
txreq -hdr "Word: foobar"
rxresp
expect resp.status == 200
expect resp.http.Bool == true
expect resp.http.Bool-Unique == resp.http.Bool
expect resp.http.Bool-Exact == resp.http.Bool
expect resp.http.Bool-First == true
expect resp.http.Bool-Last == true
expect resp.http.Bool-Shortest == true
expect resp.http.Bool-Longest == true
} -run
client c1 {
txreq -hdr "Element: oof"
expect_close
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "Notice" {
expect 0 * Begin req
expect * = Notice {^vmod_selector: s\.match\(\): subject string is NULL$}
expect * = End
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error {^vmod selector failure: s\.bool\(element="oof"\): no such element$}
expect * = VCL_return fail
expect * = End
} -run
varnish v1 -vcl {
import ${vmod_selector};
import std;
backend b None;
sub vcl_init {
new s = selector.set();
s.add("foo", bool=false);
s.add("bar", bool=true);
s.add("baz", bool=false);
s.add("quux", bool=true);
s.add("foobar", bool=false);
}
sub vcl_recv {
set req.http.Bool = s.bool(std.integer(req.http.Int));
return (synth(200));
}
}
logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error {^vmod selector failure: s\.bool\(\) called without prior match$}
expect 0 = ReqHeader "Bool: false"
expect * = VCL_return fail
expect * = End
expect 0 * Begin req
expect * = VCL_Error {^vmod selector failure: s\.bool\(\) called without prior match$}
expect 0 = ReqHeader "Bool: false"
expect * = VCL_return fail
expect * = End
expect 0 * Begin req
expect * = VCL_Error {^vmod selector failure: s\.bool\(6\): set has 5 elements$}
expect 0 = ReqHeader "Bool: false"
expect * = VCL_return fail
expect * = End
} -start
client c1 {
txreq -hdr "Int: -1"
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect_close
} -run
client c1 {
txreq -hdr "Int: 0"
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect_close
} -run
client c1 {
txreq -hdr "Int: 6"
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect_close
} -run
logexpect l1 -wait
varnish v1 -vcl {
import ${vmod_selector};
backend b None;
sub vcl_init {
new s = selector.set();
s.add("foobarbazquux", bool=true);
s.add("foobarbaz", bool=false);
s.add("foobar", bool=true);
s.add("foo", bool=false);
}
sub vcl_recv {
return (synth(200));
}
sub vcl_synth {
if (s.hasprefix(req.http.Word)) {
set resp.http.Bool = s.bool();
set resp.http.Bool-Unique = s.bool(select=UNIQUE);
set resp.http.Bool-Exact = s.bool(select=EXACT);
set resp.http.Bool-First = s.bool(select=FIRST);
set resp.http.Bool-Last = s.bool(select=LAST);
set resp.http.Bool-Shortest
= s.bool(select=SHORTEST);
set resp.http.Bool-Longest
= s.bool(select=LONGEST);
}
if (req.http.Element) {
set resp.http.Element
= s.bool(element=req.http.Element);
set resp.http.Element-Unique = s.bool(select=UNIQUE);
set resp.http.Element-Exact = s.bool(select=EXACT);
set resp.http.Element-First = s.bool(select=FIRST);
set resp.http.Element-Last = s.bool(select=LAST);
set resp.http.Element-Shortest
= s.bool(select=SHORTEST);
set resp.http.Element-Longest = s.bool(select=LONGEST);
}
return (deliver);
}
}
client c1 {
txreq -hdr "Word: foo"
rxresp
expect resp.status == 200
expect resp.http.Bool == false
expect resp.http.Bool-Unique == false
expect resp.http.Bool-Exact == false
expect resp.http.Bool-First == false
expect resp.http.Bool-Last == false
expect resp.http.Bool-Shortest == false
expect resp.http.Bool-Longest == false
txreq -hdr "Element: foo"
rxresp
expect resp.status == 200
expect resp.http.Element == false
expect resp.http.Element-Unique == false
expect resp.http.Element-Exact == false
expect resp.http.Element-First == false
expect resp.http.Element-Last == false
expect resp.http.Element-Shortest == false
expect resp.http.Element-Longest == false
} -run
varnish v1 -vcl {
import ${vmod_selector};
backend b None;
sub vcl_init {
new s = selector.set();
s.add("foobarbazquux", bool=false);
s.add("foobarbaz", bool=true);
s.add("foobar", bool=false);
s.add("foo", bool=true);
}
sub vcl_recv {
return (synth(200));
}
sub vcl_synth {
if (s.hasprefix(req.http.Word)) {
set resp.http.Bool-Exact = s.bool(select=EXACT);
set resp.http.Bool-First = s.bool(select=FIRST);
set resp.http.Bool-Last = s.bool(select=LAST);
set resp.http.Bool-Shortest = s.bool(select=SHORTEST);
set resp.http.Bool-Longest = s.bool(select=LONGEST);
}
return (deliver);
}
}
client c1 {
txreq -hdr "Word: foobar"
rxresp
expect resp.status == 200
expect resp.http.Bool-Exact == false
expect resp.http.Bool-First == false
expect resp.http.Bool-Last == true
expect resp.http.Bool-Shortest == true
expect resp.http.Bool-Longest == false
txreq -hdr "Word: foobarbaz"
rxresp
expect resp.status == 200
expect resp.http.Bool-Exact == true
expect resp.http.Bool-First == true
expect resp.http.Bool-Last == true
expect resp.http.Bool-Shortest == true
expect resp.http.Bool-Longest == true
txreq -hdr "Word: foobarbazquux"
rxresp
expect resp.status == 200
expect resp.http.Bool-Exact == false
expect resp.http.Bool-First == false
expect resp.http.Bool-Last == true
expect resp.http.Bool-Shortest == true
expect resp.http.Bool-Longest == false
} -run
varnish v1 -vcl {
import ${vmod_selector};
backend b None;
sub vcl_init {
new s = selector.set();
s.add("foobarbazquux", bool=true);
s.add("foobarbaz", bool=false);
s.add("foobar", bool=true);
s.add("foo", bool=false);
}
sub vcl_recv {
if (s.hasprefix(req.http.Word)) {
set req.http.Bool-Exact = s.bool(select=EXACT);
set req.http.Bool-Unique = s.bool(select=UNIQUE);
}
return (synth(200));
}
}
logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect * * Begin req
expect * = ReqHeader "Bool-Exact: true"
expect * = VCL_Error {^vmod selector failure: s\.bool\(select=UNIQUE\): 2 elements were matched$}
expect 0 = ReqHeader "Bool-Unique: false"
expect * = VCL_return fail
expect * = End
expect 0 * Begin req
expect * = VCL_Error {^vmod selector failure: s\.bool\(select=EXACT\): no element matched exactly$}
expect 0 = ReqHeader "Bool-Exact: false"
expect * = VCL_return fail
expect * = End
} -start
client c1 {
txreq -hdr "Word: foobar"
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect_close
} -run
client c1 {
txreq -hdr "Word: foobarb"
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect_close
} -run
logexpect l1 -wait
varnish v1 -vcl {
import ${vmod_selector};
backend b None;
sub vcl_init {
new s = selector.set();
s.add("foo", bool=true);
s.add("bar");
}
sub vcl_recv {
if (s.match(req.http.Word)) {
set req.http.Bool = s.bool();
}
return (synth(200));
}
sub vcl_synth {
set resp.http.Bool = req.http.Bool;
return (deliver);
}
}
logexpect l1 -v v1 -d 0 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error {^vmod selector failure: s\.bool\(\): boolean not added for element 2$}
expect 0 = ReqHeader "Bool: false"
expect * = VCL_return fail
expect * = End
} -start
client c1 {
txreq -hdr "Word: foo"
rxresp
expect resp.status == 200
expect resp.http.Bool == true
txreq -hdr "Word: bar"
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
expect_close
} -run
logexpect l1 -wait
......@@ -506,7 +506,7 @@ vmod_set_add(VRT_CTX, struct vmod_selector_set *set,
}
if (!args->valid_string && re == NULL && !args->valid_backend
&& !args->valid_integer)
&& !args->valid_integer && !args->valid_bool)
return;
set->table = realloc(set->table, n * sizeof(struct entry *));
......@@ -530,6 +530,10 @@ vmod_set_add(VRT_CTX, struct vmod_selector_set *set,
entry->integer = args->integer;
set_added(set, n - 1, INTEGER);
}
if (args->valid_bool) {
entry->bool = args->bool;
set_added(set, n - 1, BOOLEAN);
}
set->table[n - 1] = entry;
}
......
......@@ -52,6 +52,7 @@ struct entry {
VCL_BACKEND backend;
vre_t *re;
VCL_INT integer;
VCL_BOOL bool;
};
enum bitmap_e {
......@@ -59,6 +60,7 @@ enum bitmap_e {
BACKEND,
REGEX,
INTEGER,
BOOLEAN,
__MAX_BITMAP,
};
......
......@@ -24,7 +24,7 @@ SYNOPSIS
new <obj> = selector.set([BOOL case_sensitive]
[, BOOL allow_overlaps])
VOID <obj>.add(STRING [, STRING string] [, STRING regex]
[, BACKEND backend] [, INT integer])
[, BACKEND backend] [, INT integer] [, BOOL bool])
VOID <obj>.create_stats()
# Matching
......@@ -39,8 +39,9 @@ SYNOPSIS
# Retrieving objects by index, by string, or after match
STRING <obj>.element([INT n] [, ENUM select])
STRING <obj>.string([INT n] [, STRING element] [, ENUM select])
INT <obj>.integer([INT n] [, STRING element] [, ENUM select])
BACKEND <obj>.backend([INT n] [, STRING element] [, ENUM select])
INT <obj>.integer([INT n] [, STRING element] [, ENUM select])
BOOL <obj>.bool([INT n] [, STRING element] [, ENUM select])
BOOL <obj>.re_match(STRING [, INT n] [, STRING element]
[, ENUM select])
STRING <obj>.sub(STRING text, STRING rewrite [, BOOL all] [, INT n]
......@@ -422,17 +423,17 @@ Examples::
}
$Method VOID .add(STRING, [STRING string], [STRING regex], [BACKEND backend],
[INT integer])
[INT integer], [BOOL bool])
Add the given string to the set. As indicated above, elements added to
the set are implicitly numbered in the order in which they are added
with ``.add()``, starting with 1.
If values are set for the optional parameters ``string``, ``regex``,
``backend`` or ``integer``, then those values are associated with this
element, and can be retrieved with the ``.string()``, ``.backend()``,
``.integer()``, ``.re_match()`` or ``.sub()`` methods, as described
below.
``backend``, ``integer`` or ``bool``, then those values are associated
with this element, and can be retrieved with the ``.string()``,
``.backend()``, ``.integer()``, ``.bool()``, ``.re_match()`` or
``.sub()`` methods, as described below.
A regular expression in the ``regex`` parameter is compiled at VCL load
time. If the compile fails, then the VCL load fails with an error message.
......@@ -801,6 +802,40 @@ Example::
}
}
$Method BOOL .bool(INT n=0, STRING element=0,
ENUM {UNIQUE, EXACT, FIRST, LAST, SHORTEST, LONGEST}
select=UNIQUE)
Returns the boolean value set by the ``bool`` parameter for the
element of the set indicated by ``n``, ``element`` and ``select``,
according to the rules given above.
``.bool()`` invokes VCL failure if:
* The rules for ``n``, ``element`` and ``select`` indicate failure.
* No boolean was set with the ``bool`` parameter in ``.add()``.
Example::
# Match domains to the Host header, and append "www." where
# necessary.
sub vcl_init {
new domains = selector.set();
domains.add("example.com", bool=true);
domains.add("www.example.net", bool=false);
domains.add("example.org", bool=true);
domains.add("www.example.edu", bool=false)
}
sub vcl_recv {
if (domains.match(req.http.Host)) {
if (domains.bool()) {
set req.http.Host = "www." + req.http.Host;
}
}
}
$Method BOOL .re_match(STRING subject, INT n=0, STRING element=0,
ENUM {UNIQUE, EXACT, FIRST, LAST, SHORTEST, LONGEST}
select=UNIQUE)
......
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