Commit 4159b52c authored by Geoff Simmons's avatar Geoff Simmons

Move the "associative array" functions into a separate source.

vmod_selector.c was over 1000 lines.
parent 340c3be2
......@@ -7,6 +7,8 @@ vmod_LTLIBRARIES = libvmod_selector.la
libvmod_selector_la_SOURCES = \
vmod_selector.c \
vmod_selector.h \
associate.c \
qp.h \
qp.c \
popcnt_compat.h \
......@@ -24,6 +26,10 @@ dist_man_MANS = vmod_selector.3
@BUILD_VSC_SELECTOR@
vmod_selector.h: qp.h
vmod_selector.c associate.c: vmod_selector.h
vmod_selector.c qp.c: qp.h popcnt_compat.h
vmod_selector.c ph.c: ph.h rnd.h
......
/*-
* Copyright (c) 2021 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_selector.h"
static struct match_data *
get_existing_match_data(VRT_CTX,
const struct vmod_selector_set * const restrict set,
const char * const restrict method)
{
struct vmod_priv *task;
struct match_data *match;
task = VRT_priv_task(ctx, set);
AN(task);
if (task->priv == NULL) {
VFAIL(ctx, "%s.%s() called without prior match", set->vcl_name,
method);
return (NULL);
}
WS_Assert_Allocated(ctx->ws, task->priv, sizeof(*match));
CAST_OBJ(match, task->priv, MATCH_DATA_MAGIC);
return match;
}
static unsigned
select(VRT_CTX, const struct match_data * const restrict match,
const char * const restrict obj, VCL_ENUM const restrict selects,
const char * const restrict method)
{
if (selects == VENUM(EXACT)) {
if (match->exact == UINT_MAX)
VFAIL(ctx, "%s.%s(select=EXACT): "
"no element matched exactly", obj, method);
return match->exact;
}
if (match->n == 1)
return match->indices[0];
switch (selects[0]) {
case 'U':
assert(selects == VENUM(UNIQUE));
VFAIL(ctx, "%s.%s(select=UNIQUE): %d elements were matched",
obj, method, match->n);
return (UINT_MAX);
case 'L':
if (selects == VENUM(LAST))
return match->max;
if (selects == VENUM(LONGEST))
return match->indices[match->n - 1];
WRONG("illegal select enum");
case 'F':
assert(selects == VENUM(FIRST));
return match->min;
case 'S':
assert(selects == VENUM(SHORTEST));
return match->indices[0];
default:
WRONG("illegal select enum");
}
}
VCL_INT
vmod_set_which(VRT_CTX, struct vmod_selector_set *set, VCL_ENUM selects,
VCL_STRING element)
{
struct match_data *match;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
if (element != NULL)
if (!vmod_set_match(ctx, TRUST_ME(set), element)) {
VFAIL(ctx, "%s.which(element=\"%s\"): no such element",
set->vcl_name, element);
return (UINT_MAX);
}
match = get_existing_match_data(ctx, set, "which");
if (element != NULL) {
CHECK_OBJ_NOTNULL(match, MATCH_DATA_MAGIC);
assert(match->n == 1);
return (match->indices[0] + 1);
}
if (match == NULL || match->n == 0)
return (0);
return (select(ctx, match, set->vcl_name, selects, "which") + 1);
}
static unsigned
get_idx(VRT_CTX, VCL_INT n, const struct vmod_selector_set * const restrict set,
const char * const restrict method, VCL_STRING const restrict element,
VCL_ENUM const restrict selects)
{
struct match_data *match;
if (n > 0) {
if (n > set->nmembers) {
VFAIL(ctx, "%s.%s(%ld): set has %d elements",
set->vcl_name, method, n, set->nmembers);
return (UINT_MAX);
}
return (n - 1);
}
if (element != NULL)
if (!vmod_set_match(ctx, TRUST_ME(set), element)) {
VFAIL(ctx, "%s.%s(element=\"%s\"): no such element",
set->vcl_name, method, element);
return (UINT_MAX);
}
match = get_existing_match_data(ctx, set, method);
if (match == NULL || match->n == 0)
return (UINT_MAX);
return (select(ctx, match, set->vcl_name, selects, method));
}
VCL_STRING
vmod_set_element(VRT_CTX, struct vmod_selector_set *set, VCL_INT n,
VCL_ENUM selects)
{
unsigned idx;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, "element", NULL, selects);
if (idx == UINT_MAX)
return (NULL);
return (set->members[idx]);
}
static inline int
check_added(VRT_CTX, const struct vmod_selector_set * const restrict set,
unsigned idx, enum bitmap_e bitmap,
const char * const restrict method,
const char * const restrict type)
{
if (!is_added(set, idx, bitmap)) {
VFAIL(ctx, "%s.%s(): %s not added for element %u",
set->vcl_name, method, type, idx + 1);
return (0);
}
return (1);
}
VCL_BACKEND
vmod_set_backend(VRT_CTX, struct vmod_selector_set *set, VCL_INT n,
VCL_STRING element, VCL_ENUM selects)
{
unsigned idx;
VCL_BACKEND b;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, "backend", element, selects);
if (idx == UINT_MAX)
return (NULL);
if (!check_added(ctx, set, idx, BACKEND, "backend", "backend"))
return (NULL);
b = set->table[idx]->backend;
CHECK_OBJ_ORNULL(b, DIRECTOR_MAGIC);
return (b);
}
VCL_STRING
vmod_set_string(VRT_CTX, struct vmod_selector_set * set, VCL_INT n,
VCL_STRING element, VCL_ENUM selects)
{
unsigned idx;
VCL_STRING s;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, "string", element, selects);
if (idx == UINT_MAX)
return (NULL);
if (!check_added(ctx, set, idx, STRING, "string", "string"))
return (NULL);
s = set->table[idx]->string;
AN(s);
return (s);
}
VCL_INT
vmod_set_integer(VRT_CTX, struct vmod_selector_set * set, VCL_INT n,
VCL_STRING element, VCL_ENUM selects)
{
unsigned idx;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, "integer", element, selects);
if (idx == UINT_MAX)
return (0);
if (!check_added(ctx, set, idx, INTEGER, "integer", "integer"))
return (0);
return (set->table[idx]->integer);
}
static vre_t *
get_re(VRT_CTX, const struct vmod_selector_set * const restrict set,
VCL_INT n, VCL_STRING element, VCL_ENUM const restrict selects,
const char * const restrict method)
{
unsigned idx;
vre_t *re;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, method, element, selects);
if (idx == UINT_MAX)
return (NULL);
if (!check_added(ctx, set, idx, REGEX, method, "regex"))
return (NULL);
re = set->table[idx]->re;
AN(re);
return (re);
}
VCL_BOOL
vmod_set_re_match(VRT_CTX, struct vmod_selector_set *set, VCL_STRING subject,
VCL_INT n, VCL_STRING element, VCL_ENUM selects)
{
vre_t *re;
re = get_re(ctx, set, n, element, selects, "re_match");
if (re == NULL)
return (0);
return (VRT_re_match(ctx, subject, re));
}
VCL_STRING
vmod_set_sub(VRT_CTX, struct vmod_selector_set *set, VCL_STRING str,
VCL_STRING sub, VCL_BOOL all, VCL_INT n, VCL_STRING element,
VCL_ENUM selects)
{
vre_t *re;
re = get_re(ctx, set, n, element, selects, "sub");
if (re == NULL)
return (NULL);
return (VRT_regsub(ctx, all, str, re, sub));
}
......@@ -29,71 +29,24 @@
/* for strdup() */
#define _POSIX_C_SOURCE 200809L
#include "config.h"
#include "vmod_selector.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "cache/cache.h"
#include "vcl.h"
#include "vre.h"
#include "vbm.h"
#include "vrnd.h"
#include "cache/cache_director.h"
#include "vcc_if.h"
#include "ph.h"
#include "qp.h"
#include "VSC_selector.h"
#define VFAIL(ctx, fmt, ...) \
VRT_fail((ctx), "vmod selector failure: " fmt, __VA_ARGS__)
#define VERRNOMEM(ctx, fmt, ...) \
VFAIL((ctx), "out of space: " fmt, __VA_ARGS__)
#define VNOTICE(ctx, fmt, ...) \
VSLb((ctx)->vsl, SLT_Notice, "vmod_selector: " fmt, __VA_ARGS__)
struct entry {
unsigned magic;
#define VMOD_SELECTOR_ENTRY_MAGIC 0x733dbe63
char *string;
VCL_BACKEND backend;
vre_t *re;
VCL_INT integer;
};
enum bitmap_e {
STRING = 0,
BACKEND,
REGEX,
INTEGER,
__MAX_BITMAP,
};
struct bitmaps {
unsigned magic;
#define VMOD_SELECTOR_BITMAPS_MAGIC 0x5b17093f
struct vbitmap *bitmaps[__MAX_BITMAP];
};
struct vmod_selector_set {
unsigned magic;
#define VMOD_SELECTOR_SET_MAGIC 0x838979ef
unsigned nmembers;
struct entry **table;
char **members;
char **lomembers;
struct qp_y *origo;
struct ph *hash;
char *vcl_name;
struct bitmaps *bitmaps;
unsigned int case_sensitive:1;
unsigned int allow_overlaps:1;
};
struct vsc_entry {
unsigned magic;
#define VMOD_SELECTOR_VSC_MAGIC 0x4b99b64a
......@@ -464,17 +417,6 @@ set_added(struct vmod_selector_set *set, unsigned idx, enum bitmap_e bitmap)
vbit_set(set->bitmaps->bitmaps[bitmap], idx);
}
static inline int
is_added(const struct vmod_selector_set *set, unsigned idx,
enum bitmap_e bitmap)
{
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
CHECK_OBJ_NOTNULL(set->bitmaps, VMOD_SELECTOR_BITMAPS_MAGIC);
AN(set->bitmaps->bitmaps[bitmap]);
return (vbit_test(set->bitmaps->bitmaps[bitmap], idx));
}
VCL_VOID
vmod_set__fini(struct vmod_selector_set **setp)
{
......@@ -845,234 +787,6 @@ vmod_set_matched(VRT_CTX, struct VPFX(selector_set) *set, VCL_INT idx,
return (1);
}
static unsigned
select(VRT_CTX, const struct match_data * const restrict match,
const char * const restrict obj, VCL_ENUM const restrict selects,
const char * const restrict method)
{
if (selects == VENUM(EXACT)) {
if (match->exact == UINT_MAX)
VFAIL(ctx, "%s.%s(select=EXACT): "
"no element matched exactly", obj, method);
return match->exact;
}
if (match->n == 1)
return match->indices[0];
switch (selects[0]) {
case 'U':
assert(selects == VENUM(UNIQUE));
VFAIL(ctx, "%s.%s(select=UNIQUE): %d elements were matched",
obj, method, match->n);
return (UINT_MAX);
case 'L':
if (selects == VENUM(LAST))
return match->max;
if (selects == VENUM(LONGEST))
return match->indices[match->n - 1];
WRONG("illegal select enum");
case 'F':
assert(selects == VENUM(FIRST));
return match->min;
case 'S':
assert(selects == VENUM(SHORTEST));
return match->indices[0];
default:
WRONG("illegal select enum");
}
}
VCL_INT
vmod_set_which(VRT_CTX, struct vmod_selector_set *set, VCL_ENUM selects,
VCL_STRING element)
{
struct match_data *match;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
if (element != NULL)
if (!vmod_set_match(ctx, TRUST_ME(set), element)) {
VFAIL(ctx, "%s.which(element=\"%s\"): no such element",
set->vcl_name, element);
return (UINT_MAX);
}
match = get_existing_match_data(ctx, set, "which");
if (element != NULL) {
CHECK_OBJ_NOTNULL(match, MATCH_DATA_MAGIC);
assert(match->n == 1);
return (match->indices[0] + 1);
}
if (match == NULL || match->n == 0)
return (0);
return (select(ctx, match, set->vcl_name, selects, "which") + 1);
}
static unsigned
get_idx(VRT_CTX, VCL_INT n, const struct vmod_selector_set * const restrict set,
const char * const restrict method, VCL_STRING const restrict element,
VCL_ENUM const restrict selects)
{
struct match_data *match;
if (n > 0) {
if (n > set->nmembers) {
VFAIL(ctx, "%s.%s(%ld): set has %d elements",
set->vcl_name, method, n, set->nmembers);
return (UINT_MAX);
}
return (n - 1);
}
if (element != NULL)
if (!vmod_set_match(ctx, TRUST_ME(set), element)) {
VFAIL(ctx, "%s.%s(element=\"%s\"): no such element",
set->vcl_name, method, element);
return (UINT_MAX);
}
match = get_existing_match_data(ctx, set, method);
if (match == NULL || match->n == 0)
return (UINT_MAX);
return (select(ctx, match, set->vcl_name, selects, method));
}
VCL_STRING
vmod_set_element(VRT_CTX, struct vmod_selector_set *set, VCL_INT n,
VCL_ENUM selects)
{
unsigned idx;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, "element", NULL, selects);
if (idx == UINT_MAX)
return (NULL);
return (set->members[idx]);
}
static inline int
check_added(VRT_CTX, const struct vmod_selector_set * const restrict set,
unsigned idx, enum bitmap_e bitmap,
const char * const restrict method,
const char * const restrict type)
{
if (!is_added(set, idx, bitmap)) {
VFAIL(ctx, "%s.%s(): %s not added for element %u",
set->vcl_name, method, type, idx + 1);
return (0);
}
return (1);
}
VCL_BACKEND
vmod_set_backend(VRT_CTX, struct vmod_selector_set *set, VCL_INT n,
VCL_STRING element, VCL_ENUM selects)
{
unsigned idx;
VCL_BACKEND b;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, "backend", element, selects);
if (idx == UINT_MAX)
return (NULL);
if (!check_added(ctx, set, idx, BACKEND, "backend", "backend"))
return (NULL);
b = set->table[idx]->backend;
CHECK_OBJ_ORNULL(b, DIRECTOR_MAGIC);
return (b);
}
VCL_STRING
vmod_set_string(VRT_CTX, struct vmod_selector_set * set, VCL_INT n,
VCL_STRING element, VCL_ENUM selects)
{
unsigned idx;
VCL_STRING s;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, "string", element, selects);
if (idx == UINT_MAX)
return (NULL);
if (!check_added(ctx, set, idx, STRING, "string", "string"))
return (NULL);
s = set->table[idx]->string;
AN(s);
return (s);
}
VCL_INT
vmod_set_integer(VRT_CTX, struct vmod_selector_set * set, VCL_INT n,
VCL_STRING element, VCL_ENUM selects)
{
unsigned idx;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, "integer", element, selects);
if (idx == UINT_MAX)
return (0);
if (!check_added(ctx, set, idx, INTEGER, "integer", "integer"))
return (0);
return (set->table[idx]->integer);
}
static vre_t *
get_re(VRT_CTX, const struct vmod_selector_set * const restrict set,
VCL_INT n, VCL_STRING element, VCL_ENUM const restrict selects,
const char * const restrict method)
{
unsigned idx;
vre_t *re;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
idx = get_idx(ctx, n, set, method, element, selects);
if (idx == UINT_MAX)
return (NULL);
if (!check_added(ctx, set, idx, REGEX, method, "regex"))
return (NULL);
re = set->table[idx]->re;
AN(re);
return (re);
}
VCL_BOOL
vmod_set_re_match(VRT_CTX, struct vmod_selector_set *set, VCL_STRING subject,
VCL_INT n, VCL_STRING element, VCL_ENUM selects)
{
vre_t *re;
re = get_re(ctx, set, n, element, selects, "re_match");
if (re == NULL)
return (0);
return (VRT_re_match(ctx, subject, re));
}
VCL_STRING
vmod_set_sub(VRT_CTX, struct vmod_selector_set *set, VCL_STRING str,
VCL_STRING sub, VCL_BOOL all, VCL_INT n, VCL_STRING element,
VCL_ENUM selects)
{
vre_t *re;
re = get_re(ctx, set, n, element, selects, "sub");
if (re == NULL)
return (NULL);
return (VRT_regsub(ctx, all, str, re, sub));
}
VCL_VOID
vmod_set_create_stats(VRT_CTX, struct vmod_selector_set *set,
struct vmod_priv *priv)
......
/*-
* Copyright (c) 2021 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 "config.h"
#include "cache/cache.h"
#include "vbm.h"
#include "vre.h"
#include "cache/cache_director.h"
#include "vcc_if.h"
#include "qp.h"
#define VFAIL(ctx, fmt, ...) \
VRT_fail((ctx), "vmod selector failure: " fmt, __VA_ARGS__)
struct entry {
unsigned magic;
#define VMOD_SELECTOR_ENTRY_MAGIC 0x733dbe63
char *string;
VCL_BACKEND backend;
vre_t *re;
VCL_INT integer;
};
enum bitmap_e {
STRING = 0,
BACKEND,
REGEX,
INTEGER,
__MAX_BITMAP,
};
struct bitmaps {
unsigned magic;
#define VMOD_SELECTOR_BITMAPS_MAGIC 0x5b17093f
struct vbitmap *bitmaps[__MAX_BITMAP];
};
struct vmod_selector_set {
unsigned magic;
#define VMOD_SELECTOR_SET_MAGIC 0x838979ef
unsigned nmembers;
struct entry **table;
char **members;
char **lomembers;
struct qp_y *origo;
struct ph *hash;
char *vcl_name;
struct bitmaps *bitmaps;
unsigned int case_sensitive:1;
unsigned int allow_overlaps:1;
};
static inline int
is_added(const struct vmod_selector_set *set, unsigned idx,
enum bitmap_e bitmap)
{
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
CHECK_OBJ_NOTNULL(set->bitmaps, VMOD_SELECTOR_BITMAPS_MAGIC);
AN(set->bitmaps->bitmaps[bitmap]);
return (vbit_test(set->bitmaps->bitmaps[bitmap], idx));
}
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