Commit a5bb7641 by Geoff Simmons

Add the set.sub() method.

parent c0a1057d
......@@ -803,7 +803,7 @@ set.add
::
VOID set.add(STRING, STRING string=0, BACKEND backend=0)
VOID set.add(STRING, STRING string=0, BACKEND backend=0, BOOL save=0, BOOL never_capture=0)
Add the given pattern to the set. If the pattern is invalid,
``.add()`` fails, and the VCL will fail to load, with an error message
......@@ -1042,6 +1042,15 @@ Examples::
# unsuccessful.
}
.. _func_set.sub:
set.sub
-------
::
STRING set.sub(STRING text, STRING rewrite, STRING fallback="**SUB METHOD FAILED**", INT n=0, ENUM {FIRST,LAST} select=0)
.. _func_set.string:
set.string
......
......@@ -27,19 +27,46 @@
*/
#include "vmod_re2.h"
#include <stdio.h>
#include "vbm.h"
#include "vre2/vre2set.h"
#define INIT(ctx) (((ctx)->method & VCL_MET_INIT) != 0)
#define STR_ADDED 0
#define BE_ADDED 1
#define RE_ADDED 2
#define NELEMS(a) (sizeof(a) / sizeof((a)[0]))
struct set_options {
VCL_INT max_mem;
unsigned utf8 : 1;
unsigned posix_syntax : 1;
unsigned longest_match : 1;
unsigned literal : 1;
unsigned never_nl : 1;
unsigned dot_nl : 1;
unsigned case_sensitive : 1;
unsigned perl_classes : 1;
unsigned word_boundary : 1;
unsigned one_line : 1;
};
struct vmod_re2_set {
unsigned magic;
unsigned magic;
#define VMOD_RE2_SET_MAGIC 0xf6d7b15a
vre2set *set;
char *vcl_name;
char **string;
VCL_BACKEND *backend;
unsigned compiled;
int npatterns;
vre2set *set;
struct vbitmap *added[3];
char *vcl_name;
char **string;
VCL_BACKEND *backend;
struct vmod_re2_regex **regex;
struct set_options opts;
unsigned compiled;
int npatterns;
};
struct task_set_match {
......@@ -49,6 +76,19 @@ struct task_set_match {
size_t nmatches;
};
static inline int
decimal_digits(int n)
{
int digits = 1;
assert(n >= 0);
while (n > 9) {
digits++;
n /= 10;
}
return digits;
}
/* Object set */
VCL_VOID
......@@ -88,9 +128,33 @@ vmod_set__init(VRT_CTX, struct vmod_re2_set **setp, const char *vcl_name,
VERR(ctx, "new %s = re2.set(): %s", vcl_name, err);
return;
}
for (unsigned i = 0; i < NELEMS(set->added); i++) {
set->added[i] = vbit_new(0);
AN(set->added[i]);
}
set->vcl_name = strdup(vcl_name);
AN(set->vcl_name);
#define SET(OPT) set->opts.OPT = OPT;
SET(utf8);
SET(posix_syntax);
SET(longest_match);
SET(max_mem);
SET(literal);
SET(never_nl);
SET(dot_nl);
SET(case_sensitive);
SET(perl_classes);
SET(word_boundary);
SET(one_line);
#undef SET
AZ(set->string);
AZ(set->backend);
AZ(set->regex);
AZ(set->compiled);
AZ(set->npatterns);
}
......@@ -105,6 +169,16 @@ vmod_set__fini(struct vmod_re2_set **setp)
set = *setp;
*setp = NULL;
vre2set_fini(&set->set);
for (int i = 0; i < set->npatterns; i++) {
if (vbit_test(set->added[STR_ADDED], i)
&& set->string[i] != NULL)
free(set->string[i]);
if (vbit_test(set->added[RE_ADDED], i)
&& set->regex[i] != NULL)
vmod_regex__fini(&set->regex[i]);
}
for (unsigned i = 0; i < NELEMS(set->added); i++)
vbit_destroy(set->added[i]);
if (set->vcl_name != NULL)
free(set->vcl_name);
FREE_OBJ(set);
......@@ -114,7 +188,8 @@ vmod_set__fini(struct vmod_re2_set **setp)
VCL_VOID
vmod_set_add(VRT_CTX, struct vmod_re2_set *set, VCL_STRING pattern,
VCL_STRING string, VCL_BACKEND backend)
VCL_STRING string, VCL_BACKEND backend, VCL_BOOL save,
VCL_BOOL never_capture)
{
const char *err;
int n;
......@@ -149,6 +224,8 @@ vmod_set_add(VRT_CTX, struct vmod_re2_set *set, VCL_STRING pattern,
return;
}
set->string[n] = strdup(string);
AN(set->string[n]);
vbit_set(set->added[STR_ADDED], n);
}
if (backend != NULL) {
if ((set->backend = realloc(set->backend,
......@@ -160,6 +237,41 @@ vmod_set_add(VRT_CTX, struct vmod_re2_set *set, VCL_STRING pattern,
return;
}
set->backend[n] = backend;
vbit_set(set->added[BE_ADDED], n);
}
if (save) {
struct vmod_re2_regex *re = NULL;
char *vcl_name;
size_t namelen;
int digits = decimal_digits(n);
assert(digits >= 1);
namelen = strlen(set->vcl_name) + digits + 2;
vcl_name = malloc(namelen);
snprintf(vcl_name, namelen, "%s_%d", set->vcl_name, n);
vmod_regex__init(ctx, &re, vcl_name, pattern, set->opts.utf8,
set->opts.posix_syntax,
set->opts.longest_match, set->opts.max_mem,
set->opts.literal, set->opts.never_nl,
set->opts.dot_nl, never_capture,
set->opts.case_sensitive,
set->opts.perl_classes,
set->opts.word_boundary, set->opts.one_line);
free(vcl_name);
if (re->vcl_name == NULL) {
vmod_regex__fini(&re);
return;
}
if ((set->regex
= realloc(set->regex,
(n + 1) * (sizeof(struct vmod_re2_regex *))))
== NULL) {
VERRNOMEM(ctx, ERR_PREFIX "saving regex", set->vcl_name,
pattern);
return;
}
set->regex[n] = re;
vbit_set(set->added[RE_ADDED], n);
}
set->npatterns++;
}
......@@ -380,6 +492,32 @@ vmod_set_which(VRT_CTX, struct vmod_re2_set *set, VCL_ENUM selects)
}
VCL_STRING
vmod_set_sub(VRT_CTX, struct vmod_re2_set *set, VCL_STRING text,
VCL_STRING rewrite, VCL_STRING fallback, VCL_INT n,
VCL_ENUM selects)
{
int idx;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
if (set->regex == NULL) {
VERR(ctx, "%s.sub(%lld): No regexen were saved for %s",
set->vcl_name, n, set->vcl_name);
return NULL;
}
idx = get_match_idx(ctx, set, n, selects, "string");
if (idx < 0)
return NULL;
if (!vbit_test(set->added[RE_ADDED], idx)) {
VERR(ctx, "%s.sub(%s, %s, %lld): Pattern %lld was not added",
set->vcl_name, text, rewrite, n, idx);
return NULL;
}
return vmod_regex_sub(ctx, set->regex[idx], text, rewrite, fallback);
}
VCL_STRING
vmod_set_string(VRT_CTX, struct vmod_re2_set *set, VCL_INT n, VCL_ENUM selects)
{
int idx;
......
# looks like -*- vcl -*-
varnishtest "set.sub() method"
varnish v1 -vcl {
import ${vmod_re2};
backend be { .host = "${bad_ip}"; }
sub vcl_init {
new s = re2.set();
s.add("(qu|[b-df-hj-np-tv-z]*)([a-z]+)", save=true);
s.add("\w+", save=true);
s.add("b", save=true);
s.compile();
}
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
set resp.http.sub-1
= s.sub("the quick brown fox jumps over the lazy dogs.",
"\2\1ay", n=1);
set resp.http.sub-2 = s.sub("abcd.efghi@google.com",
"\0-NOSPAM", n=2);
set resp.http.sub-3 = s.sub("ababababab", "bb", n=3);
set resp.http.match
= s.match("the quick brown fox jumps over the lazy dogs.");
set resp.http.n = s.nmatches();
set resp.http.pangram
= s.sub("the quick brown fox jumps over the lazy dogs.",
"\2\1ay", select=FIRST);
set resp.http.ab = s.sub("ababababab", "bb", select=LAST);
}
} -start
client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.sub-1 == "ethay quick brown fox jumps over the lazy dogs."
expect resp.http.sub-2 == "abcd-NOSPAM.efghi@google.com"
expect resp.http.sub-3 == "abbabababab"
expect resp.http.match == "true"
expect resp.http.n == "3"
expect resp.http.pangram == resp.http.sub-1
expect resp.http.ab == resp.http.sub-3
} -run
......@@ -706,7 +706,8 @@ Example::
perl_classes=true);
}
$Method VOID .add(STRING, STRING string=0, BACKEND backend=0)
$Method VOID .add(STRING, STRING string=0, BACKEND backend=0, BOOL save=0,
BOOL never_capture=0)
Add the given pattern to the set. If the pattern is invalid,
``.add()`` fails, and the VCL will fail to load, with an error message
......@@ -910,6 +911,10 @@ Examples::
# unsuccessful.
}
$Method STRING .sub(STRING text, STRING rewrite,
STRING fallback="**SUB METHOD FAILED**",
INT n=0, ENUM {FIRST, LAST} select=0)
$Method STRING .string(INT n=0, ENUM {FIRST, LAST} select=0)
Returns the string associated with the `nth` pattern added to the set,
......
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