Commit 669080ed authored by Geoff Simmons's avatar Geoff Simmons

add .backref_named()

parent 025f5654
......@@ -29,6 +29,7 @@ CONTENTS
* Object regex
* STRING regex.backref(INT, STRING)
* STRING regex.backref_named(STRING, STRING)
* BOOL regex.match(STRING)
* STRING version()
......@@ -54,6 +55,14 @@ STRING regex.backref(INT, STRING)
Prototype
STRING regex.backref(INT ref, STRING fallback)
.. _func_regex.backref_named:
STRING regex.backref_named(STRING, STRING)
------------------------------------------
Prototype
STRING regex.backref_named(STRING name, STRING fallback)
.. _func_version:
STRING version()
......
# looks like -*- vcl -*-
varnishtest "backref_named()"
varnish v1 -vcl {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new barbaz = re2.regex("(?P<bar>bar)(?P<baz>baz)");
new never = re2.regex("(?P<bar>bar)(?P<baz>baz)",
never_capture=true);
}
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
if (barbaz.match("barbaz")) {
set resp.http.num0 = barbaz.backref(0, "error0");
set resp.http.num1 = barbaz.backref(1, "error1");
set resp.http.num2 = barbaz.backref(2, "error2");
set resp.http.bar
= barbaz.backref_named("bar", "error_bar");
set resp.http.baz
= barbaz.backref_named("baz", "error_baz");
set resp.http.quux
= barbaz.backref_named("quux", "error_quux");
}
if (never.match("barbaz")) {
set resp.http.never = "match";
set resp.http.neverbar
= never.backref_named("bar", "error_bar");
set resp.http.neverbaz
= never.backref_named("baz", "error_baz");
set resp.http.neverquux
= never.backref_named("quux", "error_quux");
}
}
} -start
client c1 {
txreq
rxresp
expect resp.http.num0 == "barbaz"
expect resp.http.num1 == "bar"
expect resp.http.num2 == "baz"
expect resp.http.bar == "bar"
expect resp.http.baz == "baz"
expect resp.http.quux == "error_quux"
expect resp.http.never == "match"
expect resp.http.neverbar == "error_bar"
expect resp.http.neverbaz == "error_baz"
expect resp.http.neverquux == "error_quux"
} -run
logexpect l1 -v v1 -d 1 -g vxid -q "VCL_Error" {
expect 0 * Begin req
expect * = VCL_Error "^vmod re2 error: barbaz\.backref_named\(\"quux\", \"error_quux\"\): no such named group$"
expect * = VCL_Error "^vmod re2 error: never\.backref_named\(\"bar\", \"error_bar\"\): never_capture is true for object never$"
expect * = VCL_Error "^vmod re2 error: never\.backref_named\(\"baz\", \"error_baz\"\): never_capture is true for object never$"
expect * = VCL_Error "^vmod re2 error: never\.backref_named\(\"quux\", \"error_quux\"\): never_capture is true for object never$"
expect * = End
} -run
......@@ -89,6 +89,51 @@ init_matchsz(void)
match_sz = vre2_matchsz();
}
#define ERR_PREFIX "%s backref %ld, fallback \"%s\": "
static VCL_STRING
backref(VRT_CTX, struct vmod_re2_regex *re, VCL_INT refnum, VCL_STRING fallback)
{
void *group;
const char *err, *capture;
char *backref;
int len;
group = pthread_getspecific(re->matchk);
if (group == NULL) {
VERR(ctx, ERR_PREFIX "backref called without prior match",
re->vcl_name, refnum, fallback);
return fallback;
}
if (group == match_failed)
return fallback;
assert((char *)group >= ctx->ws->s
&& (char *)(group + ((re->ngroups+1) * match_sz)) <= ctx->ws->e);
if ((err = vre2_capture(group, (int) refnum, &capture, &len))
!= NULL) {
VERR(ctx, ERR_PREFIX "error retrieving capture: %s",
re->vcl_name, refnum, fallback, err);
return fallback;
}
assert(len >= 0);
if (capture == NULL)
return fallback;
if (len == 0)
return "";
if ((backref = WS_Copy(ctx->ws, capture, len + 1)) == NULL) {
VERR(ctx, ERR_PREFIX "insufficient workspace for backref",
re->vcl_name, refnum, fallback);
return fallback;
}
backref[len] = '\0';
return backref;
}
#undef ERR_PREFIX
VCL_VOID
vmod_regex__init(const struct vrt_ctx *ctx, struct vmod_re2_regex **rep,
const char *vcl_name, VCL_STRING pattern, VCL_BOOL utf8,
......@@ -147,6 +192,8 @@ vmod_regex__fini(struct vmod_re2_regex **rep)
FREE_OBJ(re);
}
#define ERR_PREFIX "%s.match(\"%s\"): "
VCL_BOOL
vmod_regex_match(const struct vrt_ctx *ctx, struct vmod_re2_regex *re,
VCL_STRING subject)
......@@ -161,8 +208,6 @@ vmod_regex_match(const struct vrt_ctx *ctx, struct vmod_re2_regex *re,
if (subject == NULL)
subject = "";
#define ERR_PREFIX "%s.match(\"%s\"): "
AZ(pthread_setspecific(re->matchk, match_failed));
len = strlen(subject);
......@@ -197,24 +242,21 @@ vmod_regex_match(const struct vrt_ctx *ctx, struct vmod_re2_regex *re,
}
return match;
#undef ERR_PREFIX
}
#undef ERR_PREFIX
#define ERR_PREFIX "%s.backref(%ld, \"%s\"): "
VCL_STRING
vmod_regex_backref(VRT_CTX, struct vmod_re2_regex *re, VCL_INT refnum,
VCL_STRING fallback)
{
void *group;
const char *err, *capture;
char *backref;
int len;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(re, VMOD_RE2_REGEX_MAGIC);
AN(fallback);
assert(refnum >= 0);
#define ERR_PREFIX "%s.backref(%ld, \"%s\"): "
if (fallback == NULL)
fallback = "";
if (re->never_capture) {
VERR(ctx, ERR_PREFIX "never_capture is true for object %s",
......@@ -226,41 +268,47 @@ vmod_regex_backref(VRT_CTX, struct vmod_re2_regex *re, VCL_INT refnum,
re->vcl_name, refnum, fallback, re->ngroups);
return fallback;
}
return backref(ctx, re, refnum, fallback);
}
group = pthread_getspecific(re->matchk);
if (group == NULL) {
VERR(ctx, ERR_PREFIX "backref called without prior match",
re->vcl_name, refnum, fallback);
return fallback;
}
if (group == match_failed)
return fallback;
#undef ERR_PREFIX
assert((char *)group >= ctx->ws->s
&& (char *)(group + ((re->ngroups+1) * match_sz)) <= ctx->ws->e);
#define ERR_PREFIX "%s.backref_named(\"%s\", \"%s\"): "
if ((err = vre2_capture(group, (int) refnum, &capture, &len))
!= NULL) {
VERR(ctx, ERR_PREFIX "error retrieving capture: %s",
re->vcl_name, refnum, fallback, err);
return fallback;
}
VCL_STRING
vmod_regex_backref_named(VRT_CTX, struct vmod_re2_regex *re, VCL_STRING name,
VCL_STRING fallback)
{
int refnum;
const char *err;
assert(len >= 0);
if (capture == NULL)
return fallback;
if (len == 0)
return "";
if ((backref = WS_Copy(ctx->ws, capture, len + 1)) == NULL) {
VERR(ctx, ERR_PREFIX "insufficient workspace for backref",
re->vcl_name, refnum, fallback);
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(re, VMOD_RE2_REGEX_MAGIC);
if (name == NULL)
name = "";
if (fallback == NULL)
fallback = "";
if (re->never_capture) {
VERR(ctx, ERR_PREFIX "never_capture is true for object %s",
re->vcl_name, name, fallback, re->vcl_name);
return fallback;
}
backref[len] = '\0';
return backref;
#undef ERR_PREFIX
if ((err = vre2_get_group(re->vre2, name, &refnum)) != NULL) {
VERR(ctx, ERR_PREFIX "%s", re->vcl_name, name, fallback, err);
return fallback;
}
if (refnum == -1) {
VERR(ctx, ERR_PREFIX "no such named group", re->vcl_name, name,
fallback);
return fallback;
}
assert(refnum > 0 && refnum <= re->ngroups);
return backref(ctx, re, refnum, fallback);
}
#undef ERR_PREFIX
VCL_STRING
vmod_version(const struct vrt_ctx *ctx __attribute__((unused)))
{
......
......@@ -19,4 +19,7 @@ $Method BOOL .match(STRING)
$Method STRING .backref(INT ref, STRING fallback = "**BACKREF FAILED**")
$Method STRING .backref_named(STRING name,
STRING fallback = "**BACKREF FAILED**")
$Function STRING version()
......@@ -46,6 +46,7 @@ vre2::vre2(const char *pattern, RE2::Options * const opt) {
re_ = new RE2(pattern, *opt);
if (!re_->ok())
throw runtime_error(re_->error());
named_group = re_->NamedCapturingGroups();
}
vre2::~vre2() {
......@@ -53,6 +54,7 @@ vre2::~vre2() {
delete re_;
re_ = NULL;
}
delete &named_group;
}
inline bool
......@@ -68,6 +70,17 @@ vre2::ngroups() const
return re_->NumberOfCapturingGroups();
}
inline int
vre2::get_group(const char * const name) const
{
try {
return named_group.at(name);
}
catch(const out_of_range& ex) {
return -1;
}
}
const char *
vre2_init(vre2 **vre2p, const char *pattern, unsigned utf8,
unsigned posix_syntax, unsigned longest_match, long max_mem,
......@@ -141,6 +154,16 @@ vre2_ngroups(vre2 *vre2, int * const ngroups)
CATCHALL
}
const char *
vre2_get_group(vre2 *vre2, const char * const name, int * const refnum)
{
try {
*refnum = vre2->get_group(name);
return NULL;
}
CATCHALL
}
const char *
vre2_fini(vre2 **vre2)
{
......
......@@ -39,6 +39,7 @@ using namespace re2;
class vre2 {
private:
RE2* re_;
map<string, int> named_group;
public:
vre2(const char *pattern, RE2::Options * const opt);
......@@ -46,6 +47,7 @@ public:
bool match(const char *subject, size_t len, int ngroups,
StringPiece* groups) const;
const int ngroups() const;
int get_group(const char * const name) const;
};
#else
typedef struct vre2 vre2;
......@@ -70,6 +72,8 @@ extern "C" {
void * const group);
const char *vre2_capture(void *group, int refnum,
const char ** const capture, int * const len);
const char *vre2_get_group(vre2 *vre2, const char * const name,
int * const refnum);
#ifdef __cplusplus
}
......
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