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 {
txreq
rxresp
expect resp.status == 200
expect resp.http.nomatch == "fallback"
expect resp.http.frob == <undef>
expect resp.http.frob0 == "fallback0"
expect resp.http.frob1 == "fallback1"
expect resp.http.frob2 == "fallback2"
expect resp.http.frob3 == "fallback3"
expect resp.http.frob4 == "fallback4"
expect resp.http.frob5 == "fallback5"
expect resp.http.frob6 == "fallback6"
expect resp.http.frob7 == "fallback7"
expect resp.http.frob8 == "fallback8"
expect resp.http.frob9 == "fallback9"
expect resp.http.frob10 == "fallback10"
expect resp.http.foo0 == "barbaz"
expect resp.http.foo1 == "baz"
expect resp.http.foo2 == "fallback"
expect resp.http.foo1 == "bar"
expect resp.http.foo2 == "baz"
expect resp.http.foo3 == "foofallback"
expect resp.http.puke == <undef>
expect resp.http.barf0 == "fallback0"
expect resp.http.barf1 == "fallback1"
expect resp.http.barf2 == "fallback2"
expect resp.http.barf3 == "fallback3"
expect resp.http.barf4 == "fallback4"
expect resp.http.barf5 == "fallback5"
expect resp.http.barf6 == "fallback6"
expect resp.http.barf7 == "fallback7"
expect resp.http.barf8 == "fallback8"
expect resp.http.barf9 == "fallback9"
expect resp.http.barf10 == "fallback10"
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
# due to calling barbaz.backref() before .match()
expect * = VCL_Error "vmod re: backref called without prior match"
expect * = End
} -run
varnishtest "limit to backrefs 0 to 10"
varnishtest "non-capturing parentheses"
server s1 {
rxreq
txresp -hdr "Foo: 12345678901" -hdr "Bar: 123456789012" -body "1111\n"
txresp -hdr "Foo: barbaz" -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, "(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)")
) {
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, "error3");
set beresp.http.foo4 = re.backref(4, "error4");
set beresp.http.foo5 = re.backref(5, "error5");
set beresp.http.foo6 = re.backref(6, "error6");
set beresp.http.foo7 = re.backref(7, "error7");
set beresp.http.foo8 = re.backref(8, "error8");
set beresp.http.foo9 = re.backref(9, "error9");
set beresp.http.foo10 = re.backref(10, "error10");
set beresp.http.foo11 = re.backref(11, "fallback");
} else {
error 999;
}
if (re.match(beresp.http.bar,
"(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)")
) {
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, "error3");
set beresp.http.bar4 = re.backref(4, "error4");
set beresp.http.bar5 = re.backref(5, "error5");
set beresp.http.bar6 = re.backref(6, "error6");
set beresp.http.bar7 = re.backref(7, "error7");
set beresp.http.bar8 = re.backref(8, "error8");
set beresp.http.bar9 = re.backref(9, "error9");
set beresp.http.bar10 = re.backref(10, "error10");
set beresp.http.bar11 = re.backref(11, "error11");
sub vcl_init {
new barbaz = re.regex("(?:bar)(baz)");
}
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, "fallback");
} else {
error 999;
set beresp.status = 999;
}
}
......@@ -51,28 +27,7 @@ varnish v1 -vcl+backend {
client c1 {
txreq
rxresp
expect resp.http.foo0 == "1234567890"
expect resp.http.foo1 == "1"
expect resp.http.foo2 == "2"
expect resp.http.foo3 == "3"
expect resp.http.foo4 == "4"
expect resp.http.foo5 == "5"
expect resp.http.foo6 == "6"
expect resp.http.foo7 == "7"
expect resp.http.foo8 == "8"
expect resp.http.foo9 == "9"
expect resp.http.foo10 == "0"
expect resp.http.foo11 == "fallback"
expect resp.http.bar0 == "error0"
expect resp.http.bar1 == "error1"
expect resp.http.bar2 == "error2"
expect resp.http.bar3 == "error3"
expect resp.http.bar4 == "error4"
expect resp.http.bar5 == "error5"
expect resp.http.bar6 == "error6"
expect resp.http.bar7 == "error7"
expect resp.http.bar8 == "error8"
expect resp.http.bar9 == "error9"
expect resp.http.bar10 == "error10"
expect resp.http.bar11 == "error11"
expect resp.http.foo0 == "barbaz"
expect resp.http.foo1 == "baz"
expect resp.http.foo2 == "fallback"
} -run
varnishtest "re.backref not affected by standard VCL regex code"
varnishtest "limit to backrefs 0 to 10"
server s1 {
rxreq
txresp -hdr "Foo: barbaz" -body "1111\n"
txresp -hdr "Foo: 12345678901" -hdr "Bar: 123456789012" -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")) {
error 503;
}
sub vcl_init {
new tendots = re.regex("(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)");
new moredots = re.regex("(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)");
}
if (beresp.http.foo ~ "bar(baz)") {
set beresp.http.tilde0 = re.backref(0, "tilde0");
set beresp.http.tilde1 = re.backref(1, "tilde1");
sub vcl_backend_response {
if (tendots.match(beresp.http.foo)) {
set beresp.http.foo0 = tendots.backref(0, "error0");
set beresp.http.foo1 = tendots.backref(1, "error1");
set beresp.http.foo2 = tendots.backref(2, "error2");
set beresp.http.foo3 = tendots.backref(3, "error3");
set beresp.http.foo4 = tendots.backref(4, "error4");
set beresp.http.foo5 = tendots.backref(5, "error5");
set beresp.http.foo6 = tendots.backref(6, "error6");
set beresp.http.foo7 = tendots.backref(7, "error7");
set beresp.http.foo8 = tendots.backref(8, "error8");
set beresp.http.foo9 = tendots.backref(9, "error9");
set beresp.http.foo10 = tendots.backref(10, "error10");
set beresp.http.foo11 = tendots.backref(11, "fallback");
} else {
error 999;
set beresp.status = 999;
}
if (beresp.http.foo !~ "bar(quux)") {
set beresp.http.neg0 = re.backref(0, "neg0");
set beresp.http.neg1 = re.backref(1, "neg1");
if (moredots.match(beresp.http.bar)) {
set beresp.http.bar0 = moredots.backref(0, "error0");
set beresp.http.bar1 = moredots.backref(1, "error1");
set beresp.http.bar2 = moredots.backref(2, "error2");
set beresp.http.bar3 = moredots.backref(3, "error3");
set beresp.http.bar4 = moredots.backref(4, "error4");
set beresp.http.bar5 = moredots.backref(5, "error5");
set beresp.http.bar6 = moredots.backref(6, "error6");
set beresp.http.bar7 = moredots.backref(7, "error7");
set beresp.http.bar8 = moredots.backref(8, "error8");
set beresp.http.bar9 = moredots.backref(9, "error9");
set beresp.http.bar10 = moredots.backref(10, "error10");
set beresp.http.bar11 = moredots.backref(11, "fallback");
} else {
error 999;
set beresp.status = 999;
}
set beresp.http.bar = regsub(beresp.http.foo, "bar(baz)", "\1");
set beresp.http.regsub0 = re.backref(0, "regsub0");
set beresp.http.regsub1 = re.backref(1, "regsub1");
set beresp.http.bar = regsuball(beresp.http.foo, "(.)", "x");
set beresp.http.regsuball0 = re.backref(0, "regsuball0");
set beresp.http.regsuball1 = re.backref(1, "regsuball1");
}
} -start
......@@ -42,12 +54,36 @@ client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.tilde0 == "barbaz"
expect resp.http.tilde1 == "bar"
expect resp.http.neg0 == "barbaz"
expect resp.http.neg1 == "bar"
expect resp.http.regsub0 == "barbaz"
expect resp.http.regsub1 == "bar"
expect resp.http.regsuball0 == "barbaz"
expect resp.http.regsuball1 == "bar"
expect resp.http.foo0 == "1234567890"
expect resp.http.foo1 == "1"
expect resp.http.foo2 == "2"
expect resp.http.foo3 == "3"
expect resp.http.foo4 == "4"
expect resp.http.foo5 == "5"
expect resp.http.foo6 == "6"
expect resp.http.foo7 == "7"
expect resp.http.foo8 == "8"
expect resp.http.foo9 == "9"
expect resp.http.foo10 == "0"
expect resp.http.foo11 == "fallback"
expect resp.http.bar0 == "12345678901"
expect resp.http.bar1 == "1"
expect resp.http.bar2 == "2"
expect resp.http.bar3 == "3"
expect resp.http.bar4 == "4"
expect resp.http.bar5 == "5"
expect resp.http.bar6 == "6"
expect resp.http.bar7 == "7"
expect resp.http.bar8 == "8"
expect resp.http.bar9 == "9"
expect resp.http.bar10 == "0"
expect resp.http.bar11 == "fallback"
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod re: backref \d+ out of range$"
expect * = VCL_Error "^vmod re: capturing substrings exceed max \d+"
expect * = VCL_Error "^vmod re: backref \d+ out of range$"
expect * = End
} -run
varnishtest "re.backref not affected by standard VCL regex code"
server s1 {
rxreq
txresp -hdr "Foo: barbaz" -body "1111\n"
} -start
varnish v1 -vcl+backend {
import re from "${vmod_topbuild}/src/.libs/libvmod_re.so";
sub vcl_init {
new barbaz = re.regex("(bar)baz");
}
sub vcl_backend_response {
if (!barbaz.match(beresp.http.foo)) {
set beresp.status = 999;
}
if (beresp.http.foo ~ "bar(baz)") {
set beresp.http.tilde0 = barbaz.backref(0, "tilde0");
set beresp.http.tilde1 = barbaz.backref(1, "tilde1");
} else {
set beresp.status = 999;
}
if (beresp.http.foo !~ "bar(quux)") {
set beresp.http.neg0 = barbaz.backref(0, "neg0");
set beresp.http.neg1 = barbaz.backref(1, "neg1");
} else {
set beresp.status = 999;
}
set beresp.http.bar = regsub(beresp.http.foo, "bar(baz)", "\1");
set beresp.http.regsub0 = barbaz.backref(0, "regsub0");
set beresp.http.regsub1 = barbaz.backref(1, "regsub1");
set beresp.http.bar = regsuball(beresp.http.foo, "(.)", "x");
set beresp.http.regsuball0 = barbaz.backref(0, "regsuball0");
set beresp.http.regsuball1 = barbaz.backref(1, "regsuball1");
}
} -start
client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.tilde0 == "barbaz"
expect resp.http.tilde1 == "bar"
expect resp.http.neg0 == "barbaz"
expect resp.http.neg1 == "bar"
expect resp.http.regsub0 == "barbaz"
expect resp.http.regsub1 == "bar"
expect resp.http.regsuball0 == "barbaz"
expect resp.http.regsuball1 == "bar"
} -run
This diff is collapsed.
Module re
Init re_init
Function BOOL match(PRIV_VCL, PRIV_CALL, STRING, STRING)
Function BOOL match_dyn(PRIV_VCL, PRIV_CALL, STRING, STRING)
Function STRING backref(PRIV_VCL, INT, STRING)
Function STRING version()
#-
# Copyright (c) 2014 UPLEX Nils Goroll Systemoptimierung
# All rights reserved
#
# Authors: Geoffrey Simmons <geoffrey.simmons@uplex.de>
# Nils Goroll <nils.goroll@uplex.de>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
$Module re 3 Varnish Module for Regular Expression Matching with Subexpression Capture
DESCRIPTION
===========
Varnish Module (VMOD) for matching strings against regular expressions,
and for extracting captured substrings after matches.
Regular expression matching as implemented by the VMOD is equivalent
to VCL's infix operator ``~``. The VMOD is motivated by the fact that
backreference capture in standard VCL requires verbose and suboptimal
use of the ``regsub`` or ``regsuball`` functions. For example, this
common idiom in VCL captures a string of digits following the
substring ``"bar"`` from one request header into another::
sub vcl_recv {
if (req.http.Foo ~ "bar\d+")) {
set req.http.Baz = regsub(req.http.Foo,
"^.*bar(\d+).*$", "\1");
}
}
It requires two regex executions when a match is found, the second one
less efficient than the first (since it must match the entire string
while capturing a substring), and is just cumbersome.
The equivalent solution with the VMOD looks like this::
import re;
sub vcl_init {
new myregex = re.regex("bar(\d+)");
}
sub vcl_recv {
if (myregex.match(req.http.Foo)) {
set req.http.Baz = myregex.backref(1, "");
}
}
The object is created at VCL initialization with the regex containing
the capture expression, only describing the substring to be
matched. When a match with the ``match`` method succeeds, then a
captured string can be obtained from the ``backref`` method.
XXX: dynamic matches not yet implemented in this version
$Object regex(STRING)
Prototype
new OBJ = re.regex(STRING)
Description
Create a regex object with the given regular expression. The
expression is compiled when the constructor is called. It
should include any capturing parentheses that will be needed
for extracting backreferences.
Example
new myregex = re.regex("\bmax-age\s*=\s*(\d+)");
$Method BOOL .match(STRING)
Description
Determines whether the given string matches the regex;
functionally equivalent to VCL's infix operator ``~``.
Example
``if (myregex.match(beresp.http.Surrogate-Control)) { # ...``
$Method STRING .backref(INT, STRING)
Description
Extracts the `nth` subexpression of the most recent successful
call of the ``match`` method for this object in the same VCL
subroutine call, 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 ``backref``.
The VCL infix operators ``~`` and ``!~`` do not affect this
function, nor do the functions ``regsub`` or ``regsuball``.
If ``backref`` is called without any prior call to ``match``
for this object in the same VCL context, then an error message
is emitted to the Varnish log using the ``VCL_Error`` tag, and
the fallback string is returned.
Example
``set beresp.ttl = std.duration(myregex.backref(1, "120"), 120s);``
$Function STRING version()
Description
Returns the version string for this vmod.
Example
``set resp.http.X-re-version = re.version();``
INSTALLATION
============
The installation process is standard for a Varnish 4 VMOD -- build the
VMOD on a system where an instance of Varnish 4 is installed, and the
auto-tools will attempt to locate the Varnish instance, and then pull
in libraries and other support files from there.
This VMOD also requires a development version of the PCRE library for
the build (commonly in a package called ``pcre-devel`` in most Unix
distributions). The auto-tools attempt to use ``pcre-config`` to
determine compiler and linker options for PCRE.
Since the PCRE runtime library is already required for Varnish, the
VMOD adds no additional requirements for the runtime.
Quick start
-----------
This sequence should be enough in typical setups:
1. ``./autogen.sh`` (for git-installation)
2. ``./configure``
3. ``make``
4. ``make check`` (regression tests)
5. ``make install`` (may require root: sudo make install)
Alternative configs
-------------------
As with Varnish itself, you can set additional flags and macros in the
``configure`` step, and/or define environment variables to affect the
build config.
For example, if you are building the VMOD against a Varnish instance
with a non-standard installation prefix, then set these env variables
before running ``configure``:
* PREFIX=/path/to/varnish/install/prefix
* export PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig
* export ACLOCAL_PATH=$PREFIX/share/aclocal
* export PATH=$PREFIX/bin:$PREFIX/sbin:$PATH
If ``pcre-config`` is not on your ``PATH``, call ``configure`` with
the option ``--with-pcre-config=/path/to/pcre-config``. Alternatively,
you can specify compiler and linker options for pcre by setting the
environment variables ``PCRE_CFLAGS`` and ``PCRE_LIBS``, respectively.
``configure`` must locate the ``varnishtest`` and ``varnishd``
binaries so that ``make check`` can be run. Usually it should be able
to find them, but if necessary you can set the variables
``VARNISHTEST`` and/or ``VARNISHD`` with the full paths.
For developers
--------------
As with Varnish, you can use these ``configure`` options for stricter
compiling:
* ``--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.
AUTHORS
=======
* Geoffrey Simmons <geoff@uplex.de>
* Nils Goroll <nils.goroll@uplex.de>
UPLEX Nils Goroll Systemoptimierung
HISTORY
=======
Version 0.1: Initial version, compatible with Varnish 3
Version 0.2: various fixes, last version compatible with Varnish 3
Version 0.3: compatible with Varnish 4
LIMITATIONS
===========
Regular expressions passed into the constructor are compiled at
run-time, so there are no errors at VCL compile-time for invalid
expressions. If an expression is invalid, then a ``VCL_error`` message
is emitted to the Varnish log, and matches always fail.
The VMOD allocates memory for captured subexpressions from Varnish
workspaces, whose sizes are determined by the runtime parameters
``workspace_backend``, for calls within the ``vcl_backend_*``
subroutines, and ``workspace_client``, for the other VCL subs. The
VMOD copies the string to be matched into the workspace, along with
some overhead. For typical usage, the default workspace sizes are
probably enough; but if you are matching against many, long strings in
each client or backend context, you might need to increase the Varnish
parameters for workspace sizes. If the VMOD cannot allocate enough
workspace, then a ``VCL_error`` message is emitted, and both ``match``
and ``backref`` will fail. (If you're just using the regexen for
matching and not to capture backrefs, then you might as well just use
the standard VCL operators ``~`` and ``!~``, and save the workspace.)
``backref`` can extract up to 10 subexpressions, in addition to the
full expression indicated by backref 0. If the ``match`` operation
would have resulted in more than 11 captures (10 substrings and the
full string), then a ``VCL_Error`` message is emitted to the Varnish
log, and the captures are limited to 11.
XXX: the following paragraph is currently not true, bug is under
investigation
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)
* http://lassekarstensen.wordpress.com/2013/12/19/converting-a-varnish-3-0-vmod-to-4-0/
COPYRIGHT
=========
This document is licensed under the same license as the libvmod-re
project. See LICENSE for details.
* Copyright (c) 2014 UPLEX Nils Goroll Systemoptimierung
$Init vmod_re_init
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