Commit 43541478 authored by Geoff Simmons's avatar Geoff Simmons

Move the functions for matching into a separate source.

parent 30885ed8
......@@ -8,6 +8,7 @@ vmod_LTLIBRARIES = libvmod_selector.la
libvmod_selector_la_SOURCES = \
vmod_selector.c \
vmod_selector.h \
match.c \
associate.c \
qp.h \
qp.c \
......@@ -28,7 +29,7 @@ dist_man_MANS = vmod_selector.3
vmod_selector.h: qp.h
vmod_selector.c associate.c: vmod_selector.h
vmod_selector.c match.c associate.c: vmod_selector.h
vmod_selector.c qp.c: qp.h popcnt_compat.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"
#include <ctype.h>
#include "ph.h"
static struct match_data *
get_match_data(VRT_CTX, struct vmod_selector_set *set, const char *method)
{
struct vmod_priv *task;
struct match_data *match;
task = VRT_priv_task(ctx, set);
AN(task);
if (task->priv == NULL) {
if ((task->priv = WS_Alloc(ctx->ws, sizeof(*match))) == NULL) {
VERRNOMEM(ctx, "Allocating match data in %s.%s()",
set->vcl_name, method);
return (NULL);
}
task->len = sizeof(*match);
AZ(task->methods);
match = (struct match_data *)task->priv;
match->magic = MATCH_DATA_MAGIC;
}
else {
WS_Assert_Allocated(ctx->ws, task->priv, sizeof(*match));
CAST_OBJ(match, task->priv, MATCH_DATA_MAGIC);
}
return match;
}
VCL_BOOL
vmod_set_match(VRT_CTX, struct vmod_selector_set *set, VCL_STRING subject)
{
unsigned idx;
struct match_data *match;
char **members;
const char *subj;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
if (set->nmembers == 0) {
VFAIL(ctx, "%s.match(): no entries were added", set->vcl_name);
return (0);
}
if (set->hash == NULL) {
VFAIL(ctx, "%s.match(): set was not compiled", set->vcl_name);
return (0);
}
if (subject == NULL) {
VNOTICE(ctx, "%s.match(): subject string is NULL",
set->vcl_name);
return (0);
}
members = set->members;
subj = subject;
if (!set->case_sensitive) {
char *copy;
if ((copy = WS_Copy(ctx->ws, subject, -1)) == NULL) {
VERRNOMEM(ctx, "%s.match(): copying subject for "
"case-insensitive match", set->vcl_name);
return (0);
}
for (char *c = copy; *c; c++)
*c = tolower(*c);
subj = copy;
members = set->lomembers;
}
AN(members);
match = get_match_data(ctx, set, "match");
if ((idx = PH_Lookup(set->hash, members, subj)) == UINT_MAX) {
match->n = 0;
return (0);
}
if ((match->indices = WS_Alloc(ctx->ws, sizeof(unsigned))) == NULL) {
VERRNOMEM(ctx, "Reserving space for index in "
"%s.match(\"%.40s\")", set->vcl_name, subject);
return (0);
}
*match->indices = idx;
match->n = 1;
match->exact = idx;
return (1);
}
VCL_BOOL
vmod_set_hasprefix(VRT_CTX, struct vmod_selector_set *set, VCL_STRING subject)
{
struct match_data *match;
char **members;
const char *subj;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
if (set->nmembers == 0) {
VFAIL(ctx, "%s.hasprefix(): no entries were added",
set->vcl_name);
return (0);
}
if (set->origo == NULL) {
VFAIL(ctx, "%s.hasprefix(): set was not compiled",
set->vcl_name);
return (0);
}
if (subject == NULL) {
VNOTICE(ctx, "%s.hasprefix(): subject string is NULL",
set->vcl_name);
return (0);
}
members = set->members;
subj = subject;
if (!set->case_sensitive) {
char *copy;
if ((copy = WS_Copy(ctx->ws, subject, -1)) == NULL) {
VERRNOMEM(ctx, "%s.hasprefix(): copying subject for "
"case-insensitive match", set->vcl_name);
return (0);
}
for (char *c = copy; *c; c++)
*c = tolower(*c);
subj = copy;
members = set->lomembers;
}
AN(members);
match = get_match_data(ctx, set, "hasprefix");
if ((match->limit = WS_ReserveLumps(ctx->ws, sizeof(unsigned))) == 0) {
VERRNOMEM(ctx, "Reserving index array in "
"%s.hasprefix(\"%.40s\")", set->vcl_name, subject);
WS_Release(ctx->ws, 0);
return (0);
}
match->indices = (unsigned *)WS_Reservation(ctx->ws);
if (QP_Prefixes(set->origo, members, subj, match) != 0) {
VERRNOMEM(ctx, "Adding indices in %s.hasprefix(\"%.40s\")",
set->vcl_name, subject);
WS_Release(ctx->ws, 0);
return (0);
}
WS_Release(ctx->ws, match->n * sizeof(unsigned));
return (match->n > 0);
}
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;
}
VCL_INT
vmod_set_nmatches(VRT_CTX, struct vmod_selector_set *set)
{
struct match_data *match;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
match = get_existing_match_data(ctx, set, "nmatches");
if (match == NULL)
return (0);
return (match->n);
}
VCL_BOOL
vmod_set_matched(VRT_CTX, struct VPFX(selector_set) *set, VCL_INT idx,
VCL_STRING element, VCL_ENUM selects)
{
struct match_data *match;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
if (idx > set->nmembers) {
VFAIL(ctx, "%s.matched(%ld) out of range (%d members)",
set->vcl_name, idx, set->nmembers);
return (0);
}
match = get_existing_match_data(ctx, set, "matched");
if (match == NULL || match->n == 0)
return (0);
AN(match->indices);
WS_Assert_Allocated(ctx->ws, match->indices,
match->n * sizeof(unsigned));
if (idx > 0) {
/* XXX search algorithm? */
idx--;
for (unsigned i = 0; i < match->n; i++)
if (match->indices[i] == idx)
return (1);
return (0);
}
if (element != NULL) {
for (unsigned i = 0; i < match->n; i++)
if (strcmp(set->members[match->indices[i]], element)
== 0)
return (1);
return (0);
}
if (selects == VENUM(UNIQUE))
return (match->n == 1);
if (selects == VENUM(EXACT))
return (match->exact != UINT_MAX);
return (1);
}
......@@ -41,12 +41,6 @@
#include "ph.h"
#include "VSC_selector.h"
#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 vsc_entry {
unsigned magic;
#define VMOD_SELECTOR_VSC_MAGIC 0x4b99b64a
......@@ -558,235 +552,6 @@ vmod_set_compile(VRT_CTX, struct VPFX(selector_set) *set)
compile(ctx, set, ".compile()");
}
static struct match_data *
get_match_data(VRT_CTX, struct vmod_selector_set *set, const char *method)
{
struct vmod_priv *task;
struct match_data *match;
task = VRT_priv_task(ctx, set);
AN(task);
if (task->priv == NULL) {
if ((task->priv = WS_Alloc(ctx->ws, sizeof(*match))) == NULL) {
VERRNOMEM(ctx, "Allocating match data in %s.%s()",
set->vcl_name, method);
return (NULL);
}
task->len = sizeof(*match);
AZ(task->methods);
match = (struct match_data *)task->priv;
match->magic = MATCH_DATA_MAGIC;
}
else {
WS_Assert_Allocated(ctx->ws, task->priv, sizeof(*match));
CAST_OBJ(match, task->priv, MATCH_DATA_MAGIC);
}
return match;
}
VCL_BOOL
vmod_set_match(VRT_CTX, struct vmod_selector_set *set, VCL_STRING subject)
{
unsigned idx;
struct match_data *match;
char **members;
const char *subj;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
if (set->nmembers == 0) {
VFAIL(ctx, "%s.match(): no entries were added", set->vcl_name);
return (0);
}
if (set->hash == NULL) {
VFAIL(ctx, "%s.match(): set was not compiled", set->vcl_name);
return (0);
}
if (subject == NULL) {
VNOTICE(ctx, "%s.match(): subject string is NULL",
set->vcl_name);
return (0);
}
members = set->members;
subj = subject;
if (!set->case_sensitive) {
char *copy;
if ((copy = WS_Copy(ctx->ws, subject, -1)) == NULL) {
VERRNOMEM(ctx, "%s.match(): copying subject for "
"case-insensitive match", set->vcl_name);
return (0);
}
for (char *c = copy; *c; c++)
*c = tolower(*c);
subj = copy;
members = set->lomembers;
}
AN(members);
match = get_match_data(ctx, set, "match");
if ((idx = PH_Lookup(set->hash, members, subj)) == UINT_MAX) {
match->n = 0;
return (0);
}
if ((match->indices = WS_Alloc(ctx->ws, sizeof(unsigned))) == NULL) {
VERRNOMEM(ctx, "Reserving space for index in "
"%s.match(\"%.40s\")", set->vcl_name, subject);
return (0);
}
*match->indices = idx;
match->n = 1;
match->exact = idx;
return (1);
}
VCL_BOOL
vmod_set_hasprefix(VRT_CTX, struct vmod_selector_set *set, VCL_STRING subject)
{
struct match_data *match;
char **members;
const char *subj;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
if (set->nmembers == 0) {
VFAIL(ctx, "%s.hasprefix(): no entries were added",
set->vcl_name);
return (0);
}
if (set->origo == NULL) {
VFAIL(ctx, "%s.hasprefix(): set was not compiled",
set->vcl_name);
return (0);
}
if (subject == NULL) {
VNOTICE(ctx, "%s.hasprefix(): subject string is NULL",
set->vcl_name);
return (0);
}
members = set->members;
subj = subject;
if (!set->case_sensitive) {
char *copy;
if ((copy = WS_Copy(ctx->ws, subject, -1)) == NULL) {
VERRNOMEM(ctx, "%s.hasprefix(): copying subject for "
"case-insensitive match", set->vcl_name);
return (0);
}
for (char *c = copy; *c; c++)
*c = tolower(*c);
subj = copy;
members = set->lomembers;
}
AN(members);
match = get_match_data(ctx, set, "hasprefix");
if ((match->limit = WS_ReserveLumps(ctx->ws, sizeof(unsigned))) == 0) {
VERRNOMEM(ctx, "Reserving index array in "
"%s.hasprefix(\"%.40s\")", set->vcl_name, subject);
WS_Release(ctx->ws, 0);
return (0);
}
match->indices = (unsigned *)WS_Reservation(ctx->ws);
if (QP_Prefixes(set->origo, members, subj, match) != 0) {
VERRNOMEM(ctx, "Adding indices in %s.hasprefix(\"%.40s\")",
set->vcl_name, subject);
WS_Release(ctx->ws, 0);
return (0);
}
WS_Release(ctx->ws, match->n * sizeof(unsigned));
return (match->n > 0);
}
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;
}
VCL_INT
vmod_set_nmatches(VRT_CTX, struct vmod_selector_set *set)
{
struct match_data *match;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
match = get_existing_match_data(ctx, set, "nmatches");
if (match == NULL)
return (0);
return (match->n);
}
VCL_BOOL
vmod_set_matched(VRT_CTX, struct VPFX(selector_set) *set, VCL_INT idx,
VCL_STRING element, VCL_ENUM selects)
{
struct match_data *match;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(set, VMOD_SELECTOR_SET_MAGIC);
if (idx > set->nmembers) {
VFAIL(ctx, "%s.matched(%ld) out of range (%d members)",
set->vcl_name, idx, set->nmembers);
return (0);
}
match = get_existing_match_data(ctx, set, "matched");
if (match == NULL || match->n == 0)
return (0);
AN(match->indices);
WS_Assert_Allocated(ctx->ws, match->indices,
match->n * sizeof(unsigned));
if (idx > 0) {
/* XXX search algorithm? */
idx--;
for (unsigned i = 0; i < match->n; i++)
if (match->indices[i] == idx)
return (1);
return (0);
}
if (element != NULL) {
for (unsigned i = 0; i < match->n; i++)
if (strcmp(set->members[match->indices[i]], element)
== 0)
return (1);
return (0);
}
if (selects == VENUM(UNIQUE))
return (match->n == 1);
if (selects == VENUM(EXACT))
return (match->exact != UINT_MAX);
return (1);
}
VCL_VOID
vmod_set_create_stats(VRT_CTX, struct vmod_selector_set *set,
struct vmod_priv *priv)
......
......@@ -39,6 +39,12 @@
#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
......
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