Commit fca1f559 authored by Geoff Simmons's avatar Geoff Simmons

first version of the set object

parent e2113d0d
......@@ -34,6 +34,10 @@ CONTENTS
* STRING regex.backref(INT, STRING)
* BOOL regex.match(STRING)
* STRING regex.namedref(STRING, STRING)
* Object set
* VOID set.add(STRING)
* VOID set.compile()
* BOOL set.match(STRING)
* STRING version()
.. _obj_regex:
......@@ -66,6 +70,36 @@ STRING regex.namedref(STRING, STRING)
Prototype
STRING regex.namedref(STRING name, STRING fallback)
.. _obj_set:
Object set
==========
.. _func_set.add:
VOID set.add(STRING)
--------------------
Prototype
VOID set.add(STRING)
.. _func_set.compile:
VOID set.compile()
------------------
Prototype
VOID set.compile()
.. _func_set.match:
BOOL set.match(STRING)
----------------------
Prototype
BOOL set.match(STRING)
.. _func_match:
BOOL match(PRIV_TASK, STRING, STRING, BOOL, BOOL, BOOL, INT, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL, BOOL)
......
......@@ -12,7 +12,9 @@ libvmod_re2_la_LDFLAGS = -module -export-dynamic -avoid-version -shared
libvmod_re2_la_SOURCES = \
vmod_re2.c \
vre2/vre2.h \
vre2/vre2.cpp
vre2/vre2.cpp \
vre2/vre2set.h \
vre2/vre2set.cpp
nodist_libvmod_re2_la_SOURCES = \
vcc_if.c \
......@@ -28,6 +30,8 @@ vcc_if.c: vcc_if.h
vre2/vre2.cpp: vre2/vre2.h
vre2/vre2set.cpp: vre2/vre2set.h
vcc_if.h vmod_re2.man.rst: @VMODTOOL@ $(top_srcdir)/src/vmod_re2.vcc
@VMODTOOL@ $(top_srcdir)/src/vmod_re2.vcc
......
# looks like -*- vcl -*-
varnishtest "set objects"
# tests from re2 re2/testing/set_test.cc
varnish v1 -vcl {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new unanchored = re2.set();
unanchored.add("foo");
unanchored.add("bar");
unanchored.compile();
new unanchored_factored = re2.set();
unanchored_factored.add("foo");
unanchored_factored.add("foobar");
unanchored_factored.compile();
new unanchored_dollar = re2.set();
unanchored_dollar.add("foo$");
unanchored_dollar.compile();
new anchored = re2.set(anchor=both);
anchored.add("foo");
anchored.add("bar");
anchored.compile();
new empty_unanchored = re2.set();
empty_unanchored.compile();
new empty_anchored = re2.set(anchor=both);
empty_anchored.compile();
}
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
if (unanchored.match("foobar")) {
set resp.http.unanchored1 = "match";
}
if (unanchored.match("fooba")) {
set resp.http.unanchored2 = "match";
}
if (unanchored.match("oobar")) {
set resp.http.unanchored3 = "match";
}
if (unanchored_factored.match("foobar")) {
set resp.http.unanchored_factored1 = "match";
}
if (unanchored_factored.match("obarfoobaroo")) {
set resp.http.unanchored_factored2 = "match";
}
if (unanchored_factored.match("fooba")) {
set resp.http.unanchored_factored3 = "match";
}
if (unanchored_factored.match("oobar")) {
set resp.http.unanchored_factored4 = "match";
}
if (unanchored_dollar.match("foo")) {
set resp.http.unanchored_dollar1 = "match";
}
if (anchored.match("foobar")) {
set resp.http.anchored1 = "match";
}
if (anchored.match("fooba")) {
set resp.http.anchored2 = "match";
}
if (anchored.match("oobar")) {
set resp.http.anchored3 = "match";
}
if (anchored.match("foo")) {
set resp.http.anchored4 = "match";
}
if (anchored.match("bar")) {
set resp.http.anchored5 = "match";
}
if (empty_unanchored.match("")) {
set resp.http.empty_unanchored1 = "match";
}
if (empty_unanchored.match("foobar")) {
set resp.http.empty_unanchored2 = "match";
}
if (empty_anchored.match("")) {
set resp.http.empty_anchored1 = "match";
}
if (empty_anchored.match("foobar")) {
set resp.http.empty_anchored2 = "match";
}
}
} -start
client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.unanchored1 == "match"
expect resp.http.unanchored2 == "match"
expect resp.http.unanchored3 == "match"
expect resp.http.unanchored_factored1 == "match"
expect resp.http.unanchored_factored2 == "match"
expect resp.http.unanchored_factored3 == "match"
expect resp.http.unanchored_factored4 == <undef>
expect resp.http.unanchored_dollar1 == "match"
expect resp.http.anchored1 == <undef>
expect resp.http.anchored2 == <undef>
expect resp.http.anchored3 == <undef>
expect resp.http.anchored4 == "match"
expect resp.http.anchored5 == "match"
expect resp.http.empty_unanchored1 == <undef>
expect resp.http.empty_unanchored2 == <undef>
expect resp.http.empty_anchored1 == <undef>
expect resp.http.empty_anchored2 == <undef>
} -run
varnish v1 -errvcl {vmod re2 error: unanchored.add("("): missing ): (} {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new unanchored = re2.set();
unanchored.add("foo");
unanchored.add("(");
unanchored.add("bar");
unanchored.compile();
}
}
varnish v1 -errvcl {vmod re2 error: anchored.add("("): missing ): (} {
import re2 from "${vmod_topbuild}/src/.libs/libvmod_re2.so";
backend b { .host = "${bad_ip}"; }
sub vcl_init {
new anchored = re2.set(anchor=both);
anchored.add("foo");
anchored.add("(");
anchored.add("bar");
anchored.compile();
}
}
......@@ -41,6 +41,7 @@
#include "vcc_if.h"
#include "vre2/vre2.h"
#include "vre2/vre2set.h"
#define VERR(ctx, fmt, ...) \
errmsg((ctx), "vmod re2 error: " fmt, __VA_ARGS__)
......@@ -55,6 +56,13 @@ struct vmod_re2_regex {
unsigned never_capture;
};
struct vmod_re2_set {
unsigned magic;
#define VMOD_RE2_SET_MAGIC 0xf6d7b15a
vre2set *set;
char *vcl_name;
};
typedef struct task_match_t {
unsigned magic;
#define TASK_MATCH_MAGIC 0xa4b93c57
......@@ -234,6 +242,8 @@ event(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e)
return 0;
}
/* Object regex */
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,
......@@ -368,6 +378,125 @@ vmod_regex_namedref(VRT_CTX, struct vmod_re2_regex *re, VCL_STRING name,
#undef ERR_PREFIX
/* Object set */
VCL_VOID
vmod_set__init(VRT_CTX, struct vmod_re2_set **setp, const char *vcl_name,
VCL_ENUM anchor, VCL_BOOL utf8, VCL_BOOL posix_syntax,
VCL_BOOL longest_match, VCL_INT max_mem, VCL_BOOL literal,
VCL_BOOL never_nl, VCL_BOOL dot_nl, VCL_BOOL case_sensitive,
VCL_BOOL perl_classes, VCL_BOOL word_boundary, VCL_BOOL one_line)
{
struct vmod_re2_set *set;
anchor_e anchor_e;
const char *err;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
AN(setp);
AZ(*setp);
AN(vcl_name);
AN(anchor);
ALLOC_OBJ(set, VMOD_RE2_SET_MAGIC);
AN(set);
*setp = set;
if (strcmp(anchor, "none") == 0)
anchor_e = NONE;
else if (strcmp(anchor, "start") == 0)
anchor_e = START;
else if (strcmp(anchor, "both") == 0)
anchor_e = BOTH;
else
WRONG("illegal anchor");
if ((err = vre2set_init(&set->set, anchor_e, utf8, posix_syntax,
longest_match, max_mem, literal, never_nl,
dot_nl, case_sensitive, perl_classes,
word_boundary, one_line))
!= NULL) {
VERR(ctx, "new %s = re2.set(): %s", vcl_name, err);
return;
}
set->vcl_name = strdup(vcl_name);
}
VCL_VOID
vmod_set__fini(struct vmod_re2_set **setp)
{
struct vmod_re2_set *set;
set = *setp;
*setp = NULL;
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
vre2set_fini(&set->set);
if (set->vcl_name != NULL)
free(set->vcl_name);
FREE_OBJ(set);
}
#define ERR_PREFIX "%s.add(\"%s\"): "
VCL_VOID
vmod_set_add(VRT_CTX, struct vmod_re2_set *set, VCL_STRING pattern)
{
const char *err;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
/* XXX: check if compiled */
if ((err = vre2set_add(set->set, pattern)) != NULL) {
VERR(ctx, ERR_PREFIX "%s", set->vcl_name, pattern, err);
return;
}
}
#undef ERR_PREFIX
#define ERR_PREFIX "%s.compile(\"%s\"): "
VCL_VOID
vmod_set_compile(VRT_CTX, struct vmod_re2_set *set)
{
const char *err;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
/* XXX: check if compiled */
if ((err = vre2set_compile(set->set)) != NULL) {
VERR(ctx, ERR_PREFIX "%s", set->vcl_name, err);
return;
}
}
#undef ERR_PREFIX
#define ERR_PREFIX "%s.match(\"%s\"): "
VCL_BOOL
vmod_set_match(VRT_CTX, struct vmod_re2_set *set, VCL_STRING subject)
{
int match = 0;
const char *err;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
if (subject == NULL)
subject = "";
/* XXX: check if compiled */
if ((err = vre2set_match(set->set, subject, &match)) != NULL) {
VERR(ctx, ERR_PREFIX "%s", set->vcl_name, subject, err);
return 0;
}
return match;
}
#undef ERR_PREFIX
/* Regex function interface */
#define ERR_PREFIX "re2.match(pattern=\"%s\", text=\"%s\"): "
VCL_BOOL
......
......@@ -24,6 +24,18 @@ $Method STRING .backref(INT ref, STRING fallback = "**BACKREF METHOD FAILED**")
$Method STRING .namedref(STRING name,
STRING fallback = "**NAMEDREF METHOD FAILED**")
$Object set(ENUM { none, start, both } anchor="none", BOOL utf8=0,
BOOL posix_syntax=0, BOOL longest_match=0, INT max_mem=8388608,
BOOL literal=0, BOOL never_nl=0, BOOL dot_nl=0,
BOOL case_sensitive=1, BOOL perl_classes=0, BOOL word_boundary=0,
BOOL one_line=0)
$Method VOID .add(STRING)
$Method VOID .compile()
$Method BOOL .match(STRING)
$Function BOOL match(PRIV_TASK, STRING pattern, STRING subject, BOOL utf8=0,
BOOL posix_syntax=0, BOOL longest_match=0,
INT max_mem=8388608, BOOL literal=0, BOOL never_nl=0,
......
/*-
* Copyright (c) 2016 UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Geoffrey Simmons <geoffrey.simmons@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.
*
*/
#include "vre2set.h"
#define CATCHALL \
catch (const runtime_error& err) { \
return err.what(); \
} \
catch (const exception& ex) { \
return ex.what(); \
} \
catch (...) { \
return "Unknown error"; \
}
using namespace std;
vre2set::vre2set(RE2::Options * const opt, const RE2::Anchor anchor)
{
set_ = new RE2::Set(*opt, anchor);
}
vre2set::~vre2set()
{
if (set_) {
delete set_;
set_ = NULL;
}
}
inline int
vre2set::add(const char* pattern, string* error) const
{
return set_->Add(pattern, error);
}
inline bool
vre2set::compile() const
{
return set_->Compile();
}
inline bool
vre2set::match(const char* subject) const
{
return set_->Match(subject, NULL);
}
const char *
vre2set_init(vre2set **setp, anchor_e anchor, unsigned utf8,
unsigned posix_syntax, unsigned longest_match, long max_mem,
unsigned literal, unsigned never_nl, unsigned dot_nl,
unsigned case_sensitive, unsigned perl_classes, unsigned word_boundary,
unsigned one_line)
{
try {
RE2::Options opt;
RE2::Anchor re2_anchor;
switch(anchor) {
case NONE:
re2_anchor = RE2::UNANCHORED;
break;
case START:
re2_anchor = RE2::ANCHOR_START;
break;
case BOTH:
re2_anchor = RE2::ANCHOR_BOTH;
break;
default:
throw runtime_error("illegal anchor");
}
opt.set_log_errors(false);
opt.set_never_capture(true);
if (utf8)
opt.set_encoding(RE2::Options::EncodingUTF8);
else
opt.set_encoding(RE2::Options::EncodingLatin1);
opt.set_posix_syntax(posix_syntax);
opt.set_longest_match(longest_match);
opt.set_max_mem(max_mem);
opt.set_literal(literal);
opt.set_never_nl(never_nl);
opt.set_dot_nl(dot_nl);
opt.set_case_sensitive(case_sensitive);
opt.set_perl_classes(perl_classes);
opt.set_word_boundary(word_boundary);
opt.set_one_line(one_line);
*setp = new vre2set(&opt, re2_anchor);
return NULL;
}
CATCHALL
}
const char *
vre2set_add(vre2set *set, const char * const pattern)
{
try {
string err;
if (set->add(pattern, &err) == -1)
throw runtime_error(err);
return NULL;
}
CATCHALL
}
const char *
vre2set_compile(vre2set *set)
{
try {
if (!set->compile())
throw runtime_error("compile failed");
return NULL;
}
CATCHALL
}
const char *
vre2set_match(vre2set *set, const char * const subject, int * const match)
{
try {
*match = set->match(subject);
return NULL;
}
CATCHALL
}
const char *
vre2set_fini(vre2set **set)
{
try {
delete *set;
return NULL;
}
CATCHALL
}
/*-
* Copyright (c) 2016 UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Geoffrey Simmons <geoffrey.simmons@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.
*
*/
#ifndef _VRE2SET_H
#define _VRE2SET_H
#ifdef __cplusplus
#include <re2/re2.h>
#include <re2/set.h>
using namespace re2;
class vre2set {
private:
RE2::Set* set_;
public:
vre2set(RE2::Options * const opt, const RE2::Anchor anchor);
virtual ~vre2set();
int add(const char* pattern, string* error) const;
bool compile() const;
bool match(const char* subject) const;
};
#else
typedef struct vre2set vre2set;
#endif
typedef enum {
NONE,
START,
BOTH
} anchor_e;
#ifdef __cplusplus
extern "C" {
#endif
const char *vre2set_init(vre2set **set, anchor_e anchor, unsigned utf8,
unsigned posix_syntax, unsigned longest_match,
long max_mem, unsigned literal,
unsigned never_nl, unsigned dot_nl,
unsigned case_sensitive, unsigned perl_classes,
unsigned word_boundary, unsigned one_line);
const char *vre2set_fini(vre2set **vre2);
const char *vre2set_add(vre2set *set, const char *pattern);
const char *vre2set_compile(vre2set *set);
const char *vre2set_match(vre2set *set, const char *subject,
int * const match);
#ifdef __cplusplus
}
#endif
#endif /* _VRE2SET_H */
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