Commit eaa2d571 authored by Geoff Simmons's avatar Geoff Simmons

bump to version 0.3, the first version compatible with Varnish 4.

This is a complete re-implementation, not just for Varnish 4, but also
because, for the state maintained to access the ov structure in backref,
it does not use a session table. Instead, regex objects have a pthread key
for thread-local access to the ov in the ctx workspace.
parent 76e1a4d4
Copyright (c) 2013 UPLEX Nils Goroll Systemoptimierung
Copyright (c) 2013-2014 UPLEX Nils Goroll Systemoptimierung
...
See LICENSE for details.
......
Copyright (c) 2013 UPLEX Nils Goroll Systemoptimierung
Copyright (c) 2013-2014 UPLEX Nils Goroll Systemoptimierung
All rights reserved.
Redistribution and use in source and binary forms, with or without
......
......@@ -2,16 +2,5 @@ ACLOCAL_AMFLAGS = -I m4
SUBDIRS = src
dist_man_MANS = vmod_re.3
dist_man_MANS = src/vmod_re.3
MAINTAINERCLEANFILES = $(dist_man_MANS)
EXTRA_DIST = README.rst
vmod_re.3: README.rst
if HAVE_RST2MAN
${RST2MAN} README.rst $@
else
@echo "========================================"
@echo "You need rst2man installed to make dist"
@echo "========================================"
@false
endif
See src/vmod_re.vcc for the VMOD documentation, including installation
instructions. The 'make' command converts this file into the manpage
'vmod_re'.
See LICENSE for license and copyright notices.
\ No newline at end of file
=======
vmod_re
=======
-------------------------------------------------------------------------
Varnish Module for Regular Expression Matching with Subexpression Capture
-------------------------------------------------------------------------
:Manual section: 3
:Author: Geoffrey Simmons
:Date: 2013-09-28
:Version: 0.2
SYNOPSIS
========
::
import re;
re.match(<string>, <regular expresssion>)
re.match_dyn(<string>, <regular expresssion>)
re.backref(<integer>, <fallback>)
re.version()
DESCRIPTION
===========
Varnish Module (vmod) for matching strings against regular expressions,
and for extracting captured substrings after matches.
FUNCTIONS
=========
Example VCL::
import re;
sub vcl_recv {
if (re.match(req.http.Cookie, "\bfoo=(.+)\b")) {
set req.http.Foo = re.backref(1, "");
}
}
sub vcl_fetch {
if (re.match_dyn(req.http.Cookie, beresp.http.X-Regex)) {
set resp.http.Foo = re.backref(2, "");
}
}
match
-----
Prototype
re.match(<string>, <regular expression>)
Returns
boolean
Description
Determines whether a string matches the given regular
expression, which never changes for the lifetime of the VCL;
functionally equivalent to VCL's infix operator ``~`` for
fixed regex patterns.
``re.match`` only matches against the pattern provided the
first time it's called, and does not detect whether the
pattern is changed after that.
Example
``re.match(beresp.http.Surrogate-Control, "max-age=(\d+);mysite")``
match_dyn
---------
Prototype
re.match_dyn(<string>, <regular expression>)
Returns
boolean
Description
Determines whether a string matches the given regular
expression, which may change during the lifetime of the VCL;
equivalent to VCL's infix operator ``~`` for arbitrary regex
patterns.
``re.match_dyn`` is less efficient than ``re.match``, so if you
are matching against a fixed regex, you should use ``re.match``.
Example
``re.match_dyn(req.http.Cookie, beresp.http.X-Regex)``
backref
-------
Prototype
re.backref(<integer>, <fallback>)
Returns
String
Description
Extracts the `nth` subexpression of the most recent successful
call to ``re.match`` or ``re.match_dyn`` in the same VCL
subroutine in the current session, or a fallback string in
case the extraction fails. Backref 0 indicates the entire
matched string. Thus this function behaves like the ``\n``
symbols in ``regsub`` and ``regsuball``, and the ``$1``,
``$2`` ... variables in Perl.
After unsuccessful matches, the ``fallback`` string is returned
for any call to ``re.backref``.
The VCL infix operators ``~`` and ``!~`` do not affect this
function, nor do the functions ``regsub`` or ``regsuball``.
``re.backref`` can extract up to 10 subexpressions, in
addition to the full expression indicated by backref 0.
If ``re.backref`` is called without any prior call to
``re.match`` or ``re.match_dyn`` in the same VCL subroutine
call, then the result is undefined.
Example
``set beresp.ttl = std.duration(re.backref(1, "120"), 120s);``
version
-------
Prototype
re.version()
Returns
string
Description
Returns the version string for this vmod.
Example
``set resp.http.X-re-version = re.version();``
INSTALLATION
============
Installation requires the Varnish source tree, whose version must
match the version of the binary installation.
Quick start
-----------
1. ``./autogen.sh`` (for git-installation)
2. ``./configure VARNISHSRC=/path/to/your/varnish/source/varnish-cache``
3. ``make``
4. ``make check`` (regression tests)
5. ``make install`` (may require root: sudo make install)
``VARNISHSRC`` is the directory of the Varnish source tree against
which to compile the vmod.
Optionally, you can also set the vmod install dir by adding
``VMODDIR=DIR`` in the ``configure`` step (defaults to the pkg-config
discovered directory from your Varnish installation).
For developers
--------------
As with Varnish itself, you can set additional flags and macros in the
``configure`` step, and you can use any of these options:
* ``--enable-developer-warnings``
* ``--enable-extra-developer-warnings`` (for GCC 4)
* ``--enable-werror``
The vmod must always build successfully with these options enabled.
Also as with Varnish, you can add ``--enable-debugging-symbols``, so
that the vmod's symbols are available to debuggers, in core dumps and
so forth.
ACKNOWLEDGEMENTS
================
Author: Geoffrey Simmons <geoff@uplex.de>, UPLEX Nils Goroll Systemoptimierung.
The implementation was inspired by ideas from Nils Goroll's esicookies
VMOD and pmatch patch for Varnish 2, and by Kristian Lyngstøl's header
VMOD.
HISTORY
=======
Version 0.1: Initial version
Version 0.2: various fixes, last version compatible with Varnish 3
LIMITATIONS
===========
The regular expressions in ``re.match`` and ``re.match_dyn`` are
compiled at run-time, so there are no errors at VCL compile-time for
invalid expressions. If an expression is invalid, then an error
message is emitted to Varnish's shared memory log using the
``VCL_error`` tag, and the match always fails.
To maintain per-session state about the most recent regex matches, the
vmod creates a table at initialization, sized to the maximum file
descriptor number (``ulimit -n``) defined for Varnish's process owner
(since Varnish 3 uses file descriptor numbers as session
IDs). Moreover, it fails an assertion (aborting Varnish) if the
process owner is able to increase its own max file descriptor.
The vmod only allocates the state data for session IDs that are
actually used; nevertheless, this may lead to an unecessarily large
memory footprint if the ``ulimit -n`` value for the Varnish user is
excessively high.
If you cannot configure the Varnish user so that it is unable to
increase its own max file descriptor, you can disable the assertion
that fails in that case by compiling the vmod with
``-DDISABLE_MAXFD_TEST``. But be warned that Varnish running the vmod
will crash if it ever uses a file descriptor for a session ID that is
larger than the value of ``ulimit -n`` at vmod initialization.
For best results, configure the Varnish user so that its max file
descriptor is just a bit larger than ``thread_pools *
thread_pool_max``, and cannot be increased by the user.
The vmod allocates space for captured subexpressions from session
workspaces. For typical usage, the default workspace size is almost
certainly enough; but if you are capturing many, long subexpressions
in each session, you might need to increase the Varnish parameter
``sess_workspace``.
Regular expression matching is subject to the same limitations that
hold for standard regexen in VCL, for example as set by the runtime
parameters ``pcre_match_limit`` and ``pcre_match_limit_recursion``.
SEE ALSO
========
* varnishd(1)
* vcl(7)
* pcre(3)
COPYRIGHT
=========
This document is licensed under the same license as the libvmod-re
project. See LICENSE for details.
* Copyright (c) 2013 UPLEX Nils Goroll Systemoptimierung
AC_PREREQ(2.59)
AC_COPYRIGHT([Copyright (c) 2013 UPLEX Nils Goroll Systemoptimierung])
AC_INIT([libvmod-re], [0.2])
AC_COPYRIGHT([Copyright (c) 2013-2014 UPLEX Nils Goroll Systemoptimierung])
AC_INIT([libvmod-re], [0.3])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR(src/vmod_re.vcc)
AM_CONFIG_HEADER(config.h)
......@@ -36,7 +36,6 @@ PKG_PROG_PKG_CONFIG
AC_HEADER_STDC
AC_CHECK_HEADERS([stdlib.h])
AC_CHECK_HEADERS([pthread.h])
AC_CHECK_HEADERS([sys/resource.h])
if test -n $PKG_CONFIG; then
PKG_CHECK_MODULES([PCRE], [libpcre])
else
......@@ -69,33 +68,24 @@ AC_SUBST(PCRE_LIBS)
# Check for python
AC_CHECK_PROGS(PYTHON, [python3 python3.1 python3.2 python2.7 python2.6 python2.5 python2 python], [AC_MSG_ERROR([Python is needed to build this vmod, please install python.])])
# Varnish source tree
AC_ARG_VAR([VARNISHSRC], [path to Varnish source tree (mandatory)])
if test "x$VARNISHSRC" = x; then
AC_MSG_ERROR([No Varnish source tree specified])
# Varnish include files tree
VARNISH_VMOD_INCLUDES
VARNISH_VMOD_DIR
VARNISH_VMODTOOL
# Check paths to varnishd and varnishtest
AC_ARG_VAR([VARNISHTEST], [path to varnishtest (mandatory for make check)])
AC_ARG_VAR([VARNISHD], [path to varnishd (mandatory for make check)])
AC_PATH_PROG([VARNISHTEST], [varnishtest])
AC_PATH_PROG([VARNISHD], [varnishd], [/bin/false],
[${PATH}${PATH_SEPARATOR}/usr/local/sbin${PATH_SEPARATOR}/usr/sbin])
if test "x$VARNISHD" = x; then
AC_MSG_FAILURE([Can't locate varnishd])
fi
VARNISHSRC=`cd $VARNISHSRC && pwd`
AC_CHECK_FILE([$VARNISHSRC/include/varnishapi.h],
[],
[AC_MSG_FAILURE(["$VARNISHSRC" is not a Varnish source directory])]
)
# Check that varnishtest is built in the varnish source directory
AC_CHECK_FILE([$VARNISHSRC/bin/varnishtest/varnishtest],
[],
[AC_MSG_FAILURE([Can't find "$VARNISHSRC/bin/varnishtest/varnishtest". Please build your varnish source directory])]
)
# vmod installation dir
AC_ARG_VAR([VMODDIR], [vmod installation directory @<:@LIBDIR/varnish/vmods@:>@])
if test "x$VMODDIR" = x; then
VMODDIR=`pkg-config --variable=vmoddir varnishapi`
if test "x$VMODDIR" = x; then
AC_MSG_FAILURE([Can't determine vmod installation directory])
fi
if test "x$VARNISHTEST" = x; then
AC_MSG_FAILURE([Can't locate varnishtest])
fi
# This corresponds to FreeBSD's WARNS level 6
DEVELOPER_CFLAGS="-Wall -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Wreturn-type -Wcast-qual -Wwrite-strings -Wswitch -Wshadow -Wcast-align -Wchar-subscripts -Winline -Wnested-externs -Wredundant-decls -Wformat"
......
AM_CPPFLAGS = -I$(VARNISHSRC)/include -I$(VARNISHSRC) @PCRE_CFLAGS@
AM_CPPFLAGS = @VMOD_INCLUDES@ @PCRE_CFLAGS@
vmoddir = $(VMODDIR)
vmoddir = @VMOD_DIR@
vmod_LTLIBRARIES = libvmod_re.la
libvmod_re_la_LDFLAGS = -module -export-dynamic -avoid-version
......@@ -10,19 +10,34 @@ libvmod_re_la_SOURCES = \
vcc_if.h \
vmod_re.c
vcc_if.c vcc_if.h: $(VARNISHSRC)/lib/libvmod_std/vmod.py $(top_srcdir)/src/vmod_re.vcc
@PYTHON@ $(VARNISHSRC)/lib/libvmod_std/vmod.py $(top_srcdir)/src/vmod_re.vcc
man3_MANS = vmod_re.3
dist_man_MANS =
vcc_if.c vcc_if.h: @VMODTOOL@ $(top_srcdir)/src/vmod_re.vcc
@VMODTOOL@ $(top_srcdir)/src/vmod_re.vcc
VMOD_TESTS = tests/*.vtc
.PHONY: $(VMOD_TESTS)
tests/*.vtc:
$(VARNISHSRC)/bin/varnishtest/varnishtest -Dvarnishd=$(VARNISHSRC)/bin/varnishd/varnishd -Dvmod_topbuild=$(abs_top_builddir) $@
@VARNISHTEST@ -Dvarnishd=@VARNISHD@ -Dvmod_topbuild=$(abs_top_builddir) $@
check: $(VMOD_TESTS)
vmod_re.3: vmod_re.man.rst
if HAVE_RST2MAN
${RST2MAN} vmod_re.man.rst $@
else
@echo "========================================"
@echo "You need rst2man installed to make dist"
@echo "========================================"
@false
endif
EXTRA_DIST = \
vmod_re.vcc \
$(VMOD_TESTS)
CLEANFILES = $(builddir)/vcc_if.c $(builddir)/vcc_if.h
CLEANFILES = $(builddir)/vcc_if.c $(builddir)/vcc_if.h \
$(builddir)/vmod_re.man.rst \
$(builddir)/vmod_re.rst
......@@ -13,7 +13,7 @@ server s1 {
varnish v1 -vcl+backend {
import re from "${vmod_topbuild}/src/.libs/libvmod_re.so";
sub vcl_fetch {
sub vcl_backend_response {
set beresp.http.x-version = re.version();
if (!beresp.http.x-version) {
set beresp.status = 500;
......
......@@ -8,43 +8,33 @@ server s1 {
varnish v1 -vcl+backend {
import re from "${vmod_topbuild}/src/.libs/libvmod_re.so";
sub vcl_init {
new foobar = re.regex("foobar");
new snafu = re.regex("snafu");
new bar = re.regex("bar");
}
sub vcl_recv {
if ((re.match(req.url, "foobar"))) {
if (foobar.match(req.url)) {
return(pass);
} else if (re.match(req.url, "snafu")) {
return(pipe);
} else if ((re.match_dyn(req.url, "foobar"))) {
return(pass);
} else if (re.match_dyn(req.url, "snafu")) {
} else if (snafu.match(req.url)) {
return(pipe);
} else {
return(pass);
}
}
sub vcl_fetch {
if (re.match(beresp.http.foo, "bar")) {
sub vcl_backend_response {
if (bar.match(beresp.http.foo)) {
set beresp.http.foo1 = "1";
} else {
error 999;
set beresp.status = 999;
}
if (!re.match(beresp.http.bar, "bar")) {
if (!bar.match(beresp.http.bar)) {
set beresp.http.bar1 = "2";
} else {
error 999;
}
if (re.match_dyn(beresp.http.foo, "bar")) {
set beresp.http.foo1d = "1";
} else {
error 999;
}
if (!re.match_dyn(beresp.http.bar, "bar")) {
set beresp.http.bar1d = "2";
} else {
error 999;
set beresp.status = 999;
}
}
......@@ -53,8 +43,7 @@ varnish v1 -vcl+backend {
client c1 {
txreq
rxresp
expect resp.status == "200"
expect resp.http.foo1 == "1"
expect resp.http.bar1 == "2"
expect resp.http.foo1d == "1"
expect resp.http.bar1d == "2"
} -run
......@@ -11,19 +11,16 @@ server s1 {
varnish v1 -vcl+backend {
import re from "${vmod_topbuild}/src/.libs/libvmod_re.so";
sub vcl_fetch {
if (re.match(beresp.http.foo, "(bar)(baz)")) {
set beresp.http.foo1 = re.backref(1, "error1");
set beresp.http.foo2 = re.backref(2, "error2");
} else {
error 999;
}
sub vcl_init {
new barbaz = re.regex("(bar)(baz)");
}
if (re.match_dyn(beresp.http.foo, "(bar)(baz)")) {
set beresp.http.foo1d = re.backref(1, "error1");
set beresp.http.foo2d = re.backref(2, "error2");
sub vcl_backend_response {
if (barbaz.match(beresp.http.foo)) {
set beresp.http.foo1 = barbaz.backref(1, "error1");
set beresp.http.foo2 = barbaz.backref(2, "error2");
} else {
error 999;
set beresp.status = 999;
}
}
......@@ -34,8 +31,6 @@ client c1 {
rxresp
expect resp.http.foo1 == "bar"
expect resp.http.foo2 == "baz"
expect resp.http.foo1d == "bar"
expect resp.http.foo2d == "baz"
}
client c2 {
......@@ -43,8 +38,6 @@ client c2 {
rxresp
expect resp.http.foo1 == "bar"
expect resp.http.foo2 == "baz"
expect resp.http.foo1d == "bar"
expect resp.http.foo2d == "baz"
}
client c1 -run
......
......@@ -8,13 +8,13 @@ server s1 {
varnish v1 -vcl+backend {
import re from "${vmod_topbuild}/src/.libs/libvmod_re.so";
sub vcl_recv {
if (re.match(req.http.host, "^(abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij)")) {
error 500 "not ok";
}
sub vcl_init {
new longregex = re.regex("^(abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij)");
}
if (re.match_dyn(req.http.host, "^(abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij|abcdefghij)")) {
error 500 "not ok";
sub vcl_recv {
if (longregex.match(req.http.host)) {
return(synth(500, "not ok"));
}
}
} -start
......
......@@ -8,19 +8,18 @@ server s1 {
varnish v1 -vcl+backend {
import re from "${vmod_topbuild}/src/.libs/libvmod_re.so";
sub vcl_fetch {
if (re.match(beresp.http.bar, "$")) {
sub vcl_init {
new end = re.regex("$");
new empty = re.regex("");
}
sub vcl_backend_response {
if (end.match(beresp.http.bar)) {
set beresp.http.foo = "XXX";
}
if (re.match(beresp.http.foo, "")) {
if (empty.match(beresp.http.foo)) {
set beresp.http.bar = "YYY";
}
if (re.match_dyn(beresp.http.bar, "$")) {
set beresp.http.food = "XXX";
}
if (re.match_dyn(beresp.http.foo, "")) {
set beresp.http.bard = "YYY";
}
}
} -start
......@@ -30,6 +29,4 @@ client c1 {
expect resp.http.content-length == 6
expect resp.http.foo == "XXX"
expect resp.http.bar == "YYY"
expect resp.http.food == "XXX"
expect resp.http.bard == "YYY"
} -run
......@@ -8,13 +8,14 @@ server s1 {
varnish v1 -vcl+backend {
import re from "${vmod_topbuild}/src/.libs/libvmod_re.so";
sub vcl_fetch {
if (re.match(beresp.http.foo, "(")) {
sub vcl_init {
new paren = re.regex("(");
}
sub vcl_backend_response {
if (paren.match(beresp.http.foo)) {
set beresp.http.foo = "baz";
}
if (re.match_dyn(beresp.http.baz, "(")) {
set beresp.http.baz = "waldo";
}
}
} -start
......
......@@ -9,48 +9,58 @@ server s1 {
varnish v1 -vcl+backend {
import re from "${vmod_topbuild}/src/.libs/libvmod_re.so";
sub vcl_fetch {
if (re.match(beresp.http.foo, "(bar)(baz)")) {
set beresp.http.foo0 = re.backref(0, "error0");
set beresp.http.foo1 = re.backref(1, "error1");
set beresp.http.foo2 = re.backref(2, "error2");
set beresp.http.foo3 = re.backref(3, "foofallback");
sub vcl_init {
new barbaz = re.regex("(bar)(baz)");
new bazplus = re.regex("(baz)(.+)");
new fourdots = re.regex("(.)(.)(.)(.)");
new frobnitz = re.regex("(frob)(nitz)");
}
sub vcl_backend_response {
if (barbaz.match(beresp.http.foo)) {
set beresp.http.foo0 = barbaz.backref(0, "error0");
set beresp.http.foo1 = barbaz.backref(1, "error1");
set beresp.http.foo2 = barbaz.backref(2, "error2");
set beresp.http.foo3 = barbaz.backref(3, "foofallback");
} else {
error 999;
set beresp.status = 999;
}
if (re.match(beresp.http.bar, "(baz)(.+)")) {
set beresp.http.bar0 = re.backref(0, "error0");
set beresp.http.bar1 = re.backref(1, "error1");
set beresp.http.bar2 = re.backref(2, "error2");
set beresp.http.bar3 = re.backref(3, "barfallback");
if (bazplus.match(beresp.http.bar)) {
set beresp.http.bar0 = bazplus.backref(0, "error0");
set beresp.http.bar1 = bazplus.backref(1, "error1");
set beresp.http.bar2 = bazplus.backref(2, "error2");
set beresp.http.bar3 = bazplus.backref(3, "barfallback");
} else {
error 999;
set beresp.status = 999;
}
if (re.match(beresp.http.barf, "(.)(.)(.)(.)")) {
set beresp.http.frap
= "_" + re.backref(0, "error0") + "_"
+ re.backref(5, "")
+ re.backref(4, "error4")
+ re.backref(3, "error3")
+ re.backref(2, "error2") + "p_";
if (barbaz.match(beresp.http.foo)
&& bazplus.match(beresp.http.bar)) {
set beresp.http.foo20 = barbaz.backref(0, "error0");
set beresp.http.foo21 = barbaz.backref(1, "error1");
set beresp.http.foo22 = barbaz.backref(2, "error2");
set beresp.http.foo23 = barbaz.backref(3, "foofallback");
set beresp.http.bar20 = bazplus.backref(0, "error0");
set beresp.http.bar21 = bazplus.backref(1, "error1");
set beresp.http.bar22 = bazplus.backref(2, "error2");
set beresp.http.bar23 = bazplus.backref(3, "barfallback");
} else {
error 999;
set beresp.status = 999;
}
/* does not match */
if (re.match(beresp.http.foo, "(frob)(nitz)")) {
set beresp.http.frob = "nitz";
if (fourdots.match(beresp.http.barf)) {
set beresp.http.frap
= "_" + fourdots.backref(0, "error0") + "_"
+ fourdots.backref(5, "")
+ fourdots.backref(4, "error4")
+ fourdots.backref(3, "error3")
+ fourdots.backref(2, "error2") + "p_";
} else {
set beresp.status = 999;
}
/* ... so 0..4 contain contain the previous values */
set beresp.http.frob0 = re.backref(0, "fallback0");
set beresp.http.frob1 = re.backref(1, "fallback1");
set beresp.http.frob2 = re.backref(2, "fallback2");
set beresp.http.frob3 = re.backref(3, "fallback3");
set beresp.http.frob4 = re.backref(4, "fallback4");
set beresp.http.frob5 = re.backref(5, "fallback5");
set beresp.http.frob6 = re.backref(5, "fallback6");
}
} -start
......@@ -66,13 +76,13 @@ client c1 {
expect resp.http.bar1 == "baz"
expect resp.http.bar2 == "quux"
expect resp.http.bar3 == "barfallback"
expect resp.http.foo20 == "barbaz"
expect resp.http.foo21 == "bar"
expect resp.http.foo22 == "baz"
expect resp.http.foo23 == "foofallback"
expect resp.http.bar20 == "bazquux"
expect resp.http.bar21 == "baz"
expect resp.http.bar22 == "quux"
expect resp.http.bar23 == "barfallback"
expect resp.http.frap == "_barf_frap_"
expect resp.http.frob != "nitz"
expect resp.http.frob0 == "barf"
expect resp.http.frob1 == "b"
expect resp.http.frob2 == "a"
expect resp.http.frob3 == "r"
expect resp.http.frob4 == "f"
expect resp.http.frob5 == "fallback5"
expect resp.http.frob6 == "fallback6"
} -run
varnishtest "non-capturing parentheses"
varnishtest "backref failure"
server s1 {
rxreq
txresp -hdr "Foo: barbaz" -body "1111\n"
txresp -hdr "Foo: barbaz" -hdr "Bar: bazquux" -hdr "Barf: barf" \
-body "1111\n"
} -start
varnish v1 -vcl+backend {
import re from "${vmod_topbuild}/src/.libs/libvmod_re.so";
sub vcl_fetch {
if (re.match(beresp.http.foo, "(?:bar)(baz)")) {
set beresp.http.foo0 = re.backref(0, "error0");
set beresp.http.foo1 = re.backref(1, "error1");
set beresp.http.foo2 = re.backref(2, "fallback");
} else {
error 999;
sub vcl_init {
new frobnitz = re.regex("(frob)(nitz)");
new barbaz = re.regex("(bar)(baz)");
}
sub vcl_deliver {
# Call to backref() before match()
set resp.http.nomatch = barbaz.backref(0, "fallback");
/* does not match */
if (frobnitz.match(resp.http.foo)) {
set resp.http.frob = "nitz";
}
/* ... so all backrefs fail */
set resp.http.frob0 = frobnitz.backref(0, "fallback0");
set resp.http.frob1 = frobnitz.backref(1, "fallback1");
set resp.http.frob2 = frobnitz.backref(2, "fallback2");
set resp.http.frob3 = frobnitz.backref(3, "fallback3");
set resp.http.frob4 = frobnitz.backref(4, "fallback4");
set resp.http.frob5 = frobnitz.backref(5, "fallback5");
set resp.http.frob6 = frobnitz.backref(6, "fallback6");
set resp.http.frob7 = frobnitz.backref(7, "fallback7");
set resp.http.frob8 = frobnitz.backref(8, "fallback8");
set resp.http.frob9 = frobnitz.backref(9, "fallback9");
set resp.http.frob10 = frobnitz.backref(10, "fallback10");
/* matches with backrefs, as above */
if (barbaz.match(resp.http.foo)) {
set resp.http.foo0 = barbaz.backref(0, "error0");
set resp.http.foo1 = barbaz.backref(1, "error1");
set resp.http.foo2 = barbaz.backref(2, "error2");
set resp.http.foo3 = barbaz.backref(3, "foofallback");
}
/* does not match */
if (barbaz.match(resp.http.barf)) {
set resp.http.puke = "match";
}
/* ... so all backrefs fail, including the backrefs
* from the previous match
*/
set resp.http.barf0 = barbaz.backref(0, "fallback0");
set resp.http.barf1 = barbaz.backref(1, "fallback1");
set resp.http.barf2 = barbaz.backref(2, "fallback2");
set resp.http.barf3 = barbaz.backref(3, "fallback3");
set resp.http.barf4 = barbaz.backref(4, "fallback4");
set resp.http.barf5 = barbaz.backref(5, "fallback5");
set resp.http.barf6 = barbaz.backref(6, "fallback6");
set resp.http.barf7 = barbaz.backref(7, "fallback7");
set resp.http.barf8 = barbaz.backref(8, "fallback8");
set resp.http.barf9 = barbaz.backref(9, "fallback9");
set resp.http.barf10 = barbaz.backref(10, "fallback10");
}
} -start
......@@ -23,7 +67,41 @@ varnish v1 -vcl+backend {
client c1 {