Commit da00d672 authored by Geoff Simmons's avatar Geoff Simmons

Code re-org: move the set object implementation into a separate source.

parent 493cdcb2
Pipeline #370 skipped
......@@ -7,7 +7,10 @@ AM_CXXFLAGS = -Wall -Werror -Wextra -std=c++11 @RE2_CFLAGS@
vmod_LTLIBRARIES = libvmod_re2.la
libvmod_re2_la_SOURCES = \
vmod_re2.h \
vmod_re2.c \
set.c \
re2.c \
vre2/vre2.h \
vre2/vre2.cpp \
vre2/vre2set.h \
......
/*-
* Copyright (c) 2017 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 "vmod_re2.h"
/* XXX: replace this with VRT_fail() */
void
errmsg(VRT_CTX, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (ctx->vsl)
VSLbv(ctx->vsl, SLT_VCL_Error, fmt, args);
else
VSLv(SLT_VCL_Error, 0, fmt, args);
va_end(args);
if (ctx->method == VCL_MET_INIT) {
AN(ctx->msg);
va_start(args, fmt);
VSB_vprintf(ctx->msg, fmt, args);
VSB_putc(ctx->msg, '\n');
va_end(args);
VRT_handling(ctx, VCL_RET_FAIL);
}
}
/*-
* Copyright (c) 2017 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 "vmod_re2.h"
#include "vre2/vre2set.h"
#define INIT(ctx) (((ctx)->method & VCL_MET_INIT) != 0)
struct vmod_re2_set {
unsigned magic;
#define VMOD_RE2_SET_MAGIC 0xf6d7b15a
vre2set *set;
char *vcl_name;
char **string;
VCL_BACKEND *backend;
unsigned compiled;
int npatterns;
};
struct task_set_match {
unsigned magic;
#define TASK_SET_MATCH_MAGIC 0x7a24a90b
int *matches;
size_t nmatches;
};
/* 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);
AZ(set->string);
AZ(set->backend);
AZ(set->npatterns);
}
VCL_VOID
vmod_set__fini(struct vmod_re2_set **setp)
{
struct vmod_re2_set *set;
if (setp == NULL || *setp == NULL)
return;
CHECK_OBJ(*setp, VMOD_RE2_SET_MAGIC);
set = *setp;
*setp = NULL;
vre2set_fini(&set->set);
if (set->vcl_name != NULL)
free(set->vcl_name);
FREE_OBJ(set);
}
#define ERR_PREFIX "%s.add(\"%.40s\"): "
VCL_VOID
vmod_set_add(VRT_CTX, struct vmod_re2_set *set, VCL_STRING pattern,
VCL_STRING string, VCL_BACKEND backend)
{
const char *err;
int n;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
if (pattern == NULL)
pattern = "";
if (!INIT(ctx)) {
VERR(ctx, ERR_PREFIX ".add() may only be called in vcl_init",
set->vcl_name, pattern);
return;
}
if (set->compiled) {
VERR(ctx, ERR_PREFIX "%s has already been compiled",
set->vcl_name, pattern, set->vcl_name);
return;
}
if ((err = vre2set_add(set->set, pattern, &n)) != NULL) {
VERR(ctx, ERR_PREFIX "Cannot compile '%.40s': %s",
set->vcl_name, pattern, pattern, err);
return;
}
if (string != NULL) {
if ((set->string = realloc(set->string,
(n + 1) * (sizeof(char *))))
== NULL) {
VERRNOMEM(ctx, ERR_PREFIX "adding string %s",
set->vcl_name, pattern, string);
return;
}
set->string[n] = strdup(string);
}
if (backend != NULL) {
if ((set->backend = realloc(set->backend,
(n + 1) * (sizeof(VCL_BACKEND))))
== NULL) {
VERRNOMEM(ctx, ERR_PREFIX "adding backend %s",
set->vcl_name, pattern,
VRT_BACKEND_string(backend));
return;
}
set->backend[n] = backend;
}
set->npatterns++;
}
#undef ERR_PREFIX
#define ERR_PREFIX "%s.compile(): "
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);
if (!INIT(ctx)) {
VERR(ctx, ERR_PREFIX ".compile() may only be called in "
"vcl_init", set->vcl_name);
return;
}
if (set->npatterns == 0) {
VERR(ctx, ERR_PREFIX "no patterns were added", set->vcl_name);
return;
}
if (set->compiled) {
VERR(ctx, ERR_PREFIX "%s has already been compiled",
set->vcl_name, set->vcl_name);
return;
}
if ((err = vre2set_compile(set->set)) != NULL) {
VERR(ctx, ERR_PREFIX "failed, possibly insufficient memory",
set->vcl_name);
return;
}
set->compiled = 1;
}
#undef ERR_PREFIX
#define ERR_PREFIX "%s.match(\"%.40s\"): "
VCL_BOOL
vmod_set_match(VRT_CTX, struct vmod_re2_set *set, VCL_STRING subject)
{
int match = 0;
struct vmod_priv *priv;
struct task_set_match *task;
char *buf;
size_t buflen;
const char *err;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
if (subject == NULL)
subject = "";
if (!set->compiled) {
VERR(ctx, ERR_PREFIX "%s was not compiled", set->vcl_name,
subject, set->vcl_name);
return 0;
}
priv = VRT_priv_task(ctx, set);
AN(priv);
if (priv->priv == NULL) {
if ((priv->priv = WS_Alloc(ctx->ws, sizeof(*task))) == NULL) {
VERRNOMEM(ctx, ERR_PREFIX "allocating match data",
set->vcl_name, subject);
return 0;
}
priv->len = sizeof(*task);
priv->free = NULL;
task = priv->priv;
task->magic = TASK_SET_MATCH_MAGIC;
}
else {
WS_Assert_Allocated(ctx->ws, priv->priv, sizeof(*task));
CAST_OBJ(task, priv->priv, TASK_SET_MATCH_MAGIC);
}
buf = WS_Front(ctx->ws);
buflen = WS_Reserve(ctx->ws, 0);
if ((err = vre2set_match(set->set, subject, &match, buf, buflen,
&task->nmatches)) != NULL) {
VERR(ctx, ERR_PREFIX "%s", set->vcl_name, subject, err);
WS_Release(ctx->ws, 0);
return 0;
}
if (match) {
task->matches = (int *)buf;
WS_Release(ctx->ws, task->nmatches * sizeof(int));
}
else
WS_Release(ctx->ws, 0);
return match;
}
#undef ERR_PREFIX
static struct task_set_match *
get_task_data(VRT_CTX, struct vmod_re2_set *set)
{
struct vmod_priv *priv;
struct task_set_match *task;
priv = VRT_priv_task(ctx, set);
AN(priv);
if (priv->priv == NULL)
return NULL;
WS_Assert_Allocated(ctx->ws, priv->priv, sizeof(*task));
CAST_OBJ(task, priv->priv, TASK_SET_MATCH_MAGIC);
return task;
}
VCL_BOOL
vmod_set_matched(VRT_CTX, struct vmod_re2_set *set, VCL_INT n)
{
struct task_set_match *task;
int hi, lo = 0;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
if (n < 1 || n > set->npatterns) {
VERR(ctx, "n=%d out of range in %s.matched() (%d patterns)", n,
set->vcl_name, set->npatterns);
return 0;
}
if ((task = get_task_data(ctx, set)) == NULL) {
VERR(ctx, "%s.matched(%d) called without prior match",
set->vcl_name, n);
return 0;
}
if (task->nmatches == 0)
return 0;
WS_Assert_Allocated(ctx->ws, task->matches,
task->nmatches * sizeof(int));
n--;
hi = task->nmatches;
do {
int m = lo + (hi - lo) / 2;
if (task->matches[m] == n)
return 1;
if (task->matches[m] < n)
lo = m + 1;
else
hi = m - 1;
} while (lo <= hi);
return 0;
}
VCL_INT
vmod_set_nmatches(VRT_CTX, struct vmod_re2_set *set)
{
struct task_set_match *task;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
if ((task = get_task_data(ctx, set)) == NULL) {
VERR(ctx, "%s.nmatches() called without prior match",
set->vcl_name);
return 0;
}
return task->nmatches;
}
static int
get_match_idx(VRT_CTX, struct vmod_re2_set *set, VCL_INT n, VCL_ENUM selects,
const char *method)
{
struct task_set_match *task;
int idx = 0;
if (n > set->npatterns) {
VERR(ctx, "%s.%s(%lld): set has %d patterns", set->vcl_name,
method, n, set->npatterns);
return -1;
}
if (n > 0)
return n - 1;
if ((task = get_task_data(ctx, set)) == NULL) {
VERR(ctx, "%s.%s() called without prior match", set->vcl_name,
method);
return -1;
}
if (task->nmatches == 0) {
VERR(ctx, "%s.%s(%lld): previous match was unsuccessful",
set->vcl_name, method, n);
return -1;
}
if (task->nmatches > 1) {
if (selects == NULL) {
VERR(ctx, "%s.%s(%lld): %d successful matches",
set->vcl_name, method, n, task->nmatches);
return -1;
}
if (strcmp(selects, "LAST") == 0)
idx = task->nmatches - 1;
else
AZ(strcmp(selects, "FIRST"));
}
WS_Assert_Allocated(ctx->ws, task->matches,
task->nmatches * sizeof(int));
return task->matches[idx];
}
VCL_INT
vmod_set_which(VRT_CTX, struct vmod_re2_set *set, VCL_ENUM selects)
{
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
return get_match_idx(ctx, set, 0, selects, "which") + 1;
}
VCL_STRING
vmod_set_string(VRT_CTX, struct vmod_re2_set *set, 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->string == NULL) {
VERR(ctx, "%s.string(%lld): No strings were set 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;
return set->string[idx];
}
VCL_BACKEND
vmod_set_backend(VRT_CTX, struct vmod_re2_set *set, 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->backend == NULL) {
VERR(ctx, "%s.backend(%lld): No backends were set for %s",
set->vcl_name, n, set->vcl_name);
return NULL;
}
idx = get_match_idx(ctx, set, n, selects, "backend");
if (idx < 0)
return NULL;
return set->backend[idx];
}
......@@ -26,51 +26,9 @@
* SUCH DAMAGE.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include "cache/cache.h"
#include "vcl.h"
#include "vas.h"
#include "vsb.h"
#include "miniobj.h"
#include "vcc_if.h"
#include "vre2/vre2.h"
#include "vre2/vre2set.h"
#define ERR(ctx, msg) \
errmsg((ctx), "vmod re2 error: " msg)
#define VERR(ctx, fmt, ...) \
errmsg((ctx), "vmod re2 error: " fmt, __VA_ARGS__)
#include "vmod_re2.h"
#define VERRNOMEM(ctx, fmt, ...) \
VERR((ctx), fmt ", out of space", __VA_ARGS__)
#define INIT(ctx) (((ctx)->method & VCL_MET_INIT) != 0)
struct vmod_re2_regex {
unsigned magic;
#define VMOD_RE2_REGEX_MAGIC 0x5c3f6f24
vre2 *vre2;
char *vcl_name;
int ngroups;
unsigned never_capture;
};
struct vmod_re2_set {
unsigned magic;
#define VMOD_RE2_SET_MAGIC 0xf6d7b15a
vre2set *set;
char *vcl_name;
char **string;
VCL_BACKEND *backend;
unsigned compiled;
int npatterns;
};
#include "config.h"
typedef struct task_match_t {
unsigned magic;
......@@ -81,13 +39,6 @@ typedef struct task_match_t {
unsigned never_capture;
} task_match_t;
struct task_set_match {
unsigned magic;
#define TASK_SET_MATCH_MAGIC 0x7a24a90b
int *matches;
size_t nmatches;
};
static char c;
static const void *match_failed = (void *) &c;
......@@ -99,28 +50,6 @@ static const char * const rewrite_name[] = {
[EXTRACT] = "extract",
};
static void
errmsg(VRT_CTX, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (ctx->vsl)
VSLbv(ctx->vsl, SLT_VCL_Error, fmt, args);
else
VSLv(SLT_VCL_Error, 0, fmt, args);
va_end(args);
if (ctx->method == VCL_MET_INIT) {
AN(ctx->msg);
va_start(args, fmt);
VSB_vprintf(ctx->msg, fmt, args);
VSB_putc(ctx->msg, '\n');
va_end(args);
VRT_handling(ctx, VCL_RET_FAIL);
}
}
static void
free_task_match(void *p)
{
......@@ -537,374 +466,6 @@ vmod_regex_extract(VRT_CTX, struct vmod_re2_regex *re, VCL_STRING text,
return rewrite_method(ctx, EXTRACT, re, text, rewrite, fallback);
}
/* 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);
AZ(set->string);
AZ(set->backend);
AZ(set->npatterns);
}
VCL_VOID
vmod_set__fini(struct vmod_re2_set **setp)
{
struct vmod_re2_set *set;
if (setp == NULL || *setp == NULL)
return;
CHECK_OBJ(*setp, VMOD_RE2_SET_MAGIC);
set = *setp;
*setp = NULL;
vre2set_fini(&set->set);
if (set->vcl_name != NULL)
free(set->vcl_name);
FREE_OBJ(set);
}
#define ERR_PREFIX "%s.add(\"%.40s\"): "
VCL_VOID
vmod_set_add(VRT_CTX, struct vmod_re2_set *set, VCL_STRING pattern,
VCL_STRING string, VCL_BACKEND backend)
{
const char *err;
int n;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
if (pattern == NULL)
pattern = "";
if (!INIT(ctx)) {
VERR(ctx, ERR_PREFIX ".add() may only be called in vcl_init",
set->vcl_name, pattern);
return;
}
if (set->compiled) {
VERR(ctx, ERR_PREFIX "%s has already been compiled",
set->vcl_name, pattern, set->vcl_name);
return;
}
if ((err = vre2set_add(set->set, pattern, &n)) != NULL) {
VERR(ctx, ERR_PREFIX "Cannot compile '%.40s': %s",
set->vcl_name, pattern, pattern, err);
return;
}
if (string != NULL) {
if ((set->string = realloc(set->string,
(n + 1) * (sizeof(char *))))
== NULL) {
VERRNOMEM(ctx, ERR_PREFIX "adding string %s",
set->vcl_name, pattern, string);
return;
}
set->string[n] = strdup(string);
}
if (backend != NULL) {
if ((set->backend = realloc(set->backend,
(n + 1) * (sizeof(VCL_BACKEND))))
== NULL) {
VERRNOMEM(ctx, ERR_PREFIX "adding backend %s",
set->vcl_name, pattern,
VRT_BACKEND_string(backend));
return;
}
set->backend[n] = backend;
}
set->npatterns++;
}
#undef ERR_PREFIX
#define ERR_PREFIX "%s.compile(): "
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);
if (!INIT(ctx)) {
VERR(ctx, ERR_PREFIX ".compile() may only be called in "
"vcl_init", set->vcl_name);
return;
}
if (set->npatterns == 0) {
VERR(ctx, ERR_PREFIX "no patterns were added", set->vcl_name);
return;
}
if (set->compiled) {
VERR(ctx, ERR_PREFIX "%s has already been compiled",
set->vcl_name, set->vcl_name);
return;
}
if ((err = vre2set_compile(set->set)) != NULL) {
VERR(ctx, ERR_PREFIX "failed, possibly insufficient memory",
set->vcl_name);
return;
}
set->compiled = 1;
}
#undef ERR_PREFIX
#define ERR_PREFIX "%s.match(\"%.40s\"): "
VCL_BOOL
vmod_set_match(VRT_CTX, struct vmod_re2_set *set, VCL_STRING subject)
{
int match = 0;
struct vmod_priv *priv;
struct task_set_match *task;
char *buf;
size_t buflen;
const char *err;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
if (subject == NULL)
subject = "";
if (!set->compiled) {
VERR(ctx, ERR_PREFIX "%s was not compiled", set->vcl_name,
subject, set->vcl_name);
return 0;
}
priv = VRT_priv_task(ctx, set);
AN(priv);
if (priv->priv == NULL) {
if ((priv->priv = WS_Alloc(ctx->ws, sizeof(*task))) == NULL) {
VERRNOMEM(ctx, ERR_PREFIX "allocating match data",
set->vcl_name, subject);
return 0;
}
priv->len = sizeof(*task);
priv->free = NULL;
task = priv->priv;
task->magic = TASK_SET_MATCH_MAGIC;
}
else {
WS_Assert_Allocated(ctx->ws, priv->priv, sizeof(*task));
CAST_OBJ(task, priv->priv, TASK_SET_MATCH_MAGIC);
}
buf = WS_Front(ctx->ws);
buflen = WS_Reserve(ctx->ws, 0);
if ((err = vre2set_match(set->set, subject, &match, buf, buflen,
&task->nmatches)) != NULL) {
VERR(ctx, ERR_PREFIX "%s", set->vcl_name, subject, err);
WS_Release(ctx->ws, 0);
return 0;
}
if (match) {
task->matches = (int *)buf;
WS_Release(ctx->ws, task->nmatches * sizeof(int));
}
else
WS_Release(ctx->ws, 0);
return match;
}
#undef ERR_PREFIX
static struct task_set_match *
get_task_data(VRT_CTX, struct vmod_re2_set *set)
{
struct vmod_priv *priv;
struct task_set_match *task;
priv = VRT_priv_task(ctx, set);
AN(priv);
if (priv->priv == NULL)
return NULL;
WS_Assert_Allocated(ctx->ws, priv->priv, sizeof(*task));
CAST_OBJ(task, priv->priv, TASK_SET_MATCH_MAGIC);
return task;
}
VCL_BOOL
vmod_set_matched(VRT_CTX, struct vmod_re2_set *set, VCL_INT n)
{
struct task_set_match *task;
int hi, lo = 0;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
if (n < 1 || n > set->npatterns) {
VERR(ctx, "n=%d out of range in %s.matched() (%d patterns)", n,
set->vcl_name, set->npatterns);
return 0;
}
if ((task = get_task_data(ctx, set)) == NULL) {
VERR(ctx, "%s.matched(%d) called without prior match",
set->vcl_name, n);
return 0;
}
if (task->nmatches == 0)
return 0;
WS_Assert_Allocated(ctx->ws, task->matches,
task->nmatches * sizeof(int));
n--;
hi = task->nmatches;
do {
int m = lo + (hi - lo) / 2;
if (task->matches[m] == n)
return 1;
if (task->matches[m] < n)
lo = m + 1;
else
hi = m - 1;
} while (lo <= hi);
return 0;
}
VCL_INT
vmod_set_nmatches(VRT_CTX, struct vmod_re2_set *set)
{
struct task_set_match *task;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
if ((task = get_task_data(ctx, set)) == NULL) {
VERR(ctx, "%s.nmatches() called without prior match",
set->vcl_name);
return 0;
}
return task->nmatches;
}
static int
get_match_idx(VRT_CTX, struct vmod_re2_set *set, VCL_INT n, VCL_ENUM selects,
const char *method)
{
struct task_set_match *task;
int idx = 0;
if (n > set->npatterns) {
VERR(ctx, "%s.%s(%lld): set has %d patterns", set->vcl_name,
method, n, set->npatterns);
return -1;
}
if (n > 0)
return n - 1;
if ((task = get_task_data(ctx, set)) == NULL) {
VERR(ctx, "%s.%s() called without prior match", set->vcl_name,
method);
return -1;
}
if (task->nmatches == 0) {
VERR(ctx, "%s.%s(%lld): previous match was unsuccessful",
set->vcl_name, method, n);
return -1;
}
if (task->nmatches > 1) {
if (selects == NULL) {
VERR(ctx, "%s.%s(%lld): %d successful matches",
set->vcl_name, method, n, task->nmatches);
return -1;
}
if (strcmp(selects, "LAST") == 0)
idx = task->nmatches - 1;
else
AZ(strcmp(selects, "FIRST"));
}
WS_Assert_Allocated(ctx->ws, task->matches,
task->nmatches * sizeof(int));
return task->matches[idx];
}
VCL_INT
vmod_set_which(VRT_CTX, struct vmod_re2_set *set, VCL_ENUM selects)
{
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_RE2_SET_MAGIC);
return get_match_idx(ctx, set, 0, selects, "which") + 1;
}
VCL_STRING
vmod_set_string(VRT_CTX, struct vmod_re2_set *set, 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->string == NULL) {
VERR(ctx, "%s.string(%lld): No strings were set 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;
return set->string[idx];
}
VCL_BACKEND
vmod_set_backend(VRT_CTX, struct vmod_re2_set *set, 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->backend == NULL) {
VERR(ctx, "%s.backend(%lld): No backends were set for %s",
set->vcl_name, n, set->vcl_name);
return NULL;
}
idx = get_match_idx(ctx, set, n, selects, "backend");
if (idx < 0)
return NULL;
return set->backend[idx];
}
/* Regex function interface */
#define ERR_PREFIX "re2.match(pattern=\"%.40s\", text=\"%.40s\"): "
......
/*-
* Copyright (c) 2017 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.
*/
/* for strdup() */
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <string.h>
#include "cache/cache.h"
#include "vcl.h"
#include "vas.h"
#include "vsb.h"
#include "miniobj.h"
#include "vcc_if.h"
#include "vre2/vre2.h"
#define ERR(ctx, msg) \
errmsg((ctx), "vmod re2 error: " msg)
#define VERR(ctx, fmt, ...) \
errmsg((ctx), "vmod re2 error: " fmt, __VA_ARGS__)
#define VERRNOMEM(ctx, fmt, ...) \
VERR((ctx), fmt ", out of space", __VA_ARGS__)
struct vmod_re2_regex {
unsigned magic;
#define VMOD_RE2_REGEX_MAGIC 0x5c3f6f24
vre2 *vre2;
char *vcl_name;
int ngroups;
unsigned never_capture;
};
void errmsg(VRT_CTX, const char *fmt, ...);
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