Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
libvmod-selector
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
uplex-varnish
libvmod-selector
Commits
7f187041
Commit
7f187041
authored
Jun 24, 2018
by
Geoff Simmons
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add methods .hasprefix(), .nmatches(), .matched() and .which().
parent
c517ccfb
Changes
6
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
1730 additions
and
10 deletions
+1730
-10
README.rst
README.rst
+66
-0
patricia.c
src/patricia.c
+58
-0
patricia.h
src/patricia.h
+12
-9
prefix.vtc
src/tests/prefix.vtc
+1365
-0
vmod_selector.c
src/vmod_selector.c
+189
-1
vmod_selector.vcc
src/vmod_selector.vcc
+40
-0
No files found.
README.rst
View file @
7f187041
...
...
@@ -26,7 +26,11 @@ CONTENTS
* :ref:`obj_set`
* :ref:`func_set.add`
* :ref:`func_set.debug`
* :ref:`func_set.hasprefix`
* :ref:`func_set.match`
* :ref:`func_set.matched`
* :ref:`func_set.nmatches`
* :ref:`func_set.which`
* :ref:`func_version`
...
...
@@ -107,6 +111,68 @@ Example::
}
.. _func_set.hasprefix:
BOOL xset.hasprefix(STRING)
---------------------------
Returns ``true`` if and only if ...
Example::
if (myset.hasprefix(req.url)) {
call do_if_prefix_matched;
}
.. _func_set.nmatches:
INT xset.nmatches()
-------------------
Returns ...
Example::
if (myset.hasprefix(req.url)) {
# ...
}
.. _func_set.matched:
BOOL xset.matched(INT)
----------------------
Returns ...
Example::
if (myset.hasprefix(req.url)) {
# ...
}
.. _func_set.which:
INT xset.which(ENUM select)
---------------------------
::
INT xset.which(
ENUM {UNIQUE, FIRST, LAST, SHORTEST, LONGEST} select=UNIQUE
)
Returns ...
Example::
if (myset.hasprefix(req.url)) {
# ...
}
.. _func_set.debug:
STRING xset.debug()
...
...
src/patricia.c
View file @
7f187041
...
...
@@ -256,6 +256,64 @@ PT_Lookup(const struct pt_y * const restrict root,
return
(
UINT_MAX
);
}
static
int
pt_search
(
const
struct
pt_y
*
const
restrict
y
,
char
*
const
restrict
*
const
restrict
strings
,
const
unsigned
char
*
restrict
c
,
struct
match_data
*
const
restrict
match
)
{
const
unsigned
char
*
restrict
s
;
unsigned
short
i
;
if
(
y
==
NULL
)
return
(
0
);
CHECK_OBJ
(
y
,
PT_Y_MAGIC
);
s
=
(
unsigned
char
*
)
strings
[
y
->
idx
]
+
y
->
off
;
for
(
i
=
0
;
*
c
!=
'\0'
&&
i
<
y
->
len
&&
s
[
i
]
==
*
c
;
i
++
)
c
++
;
if
(
s
[
i
]
==
'\0'
)
{
if
(
match
->
n
==
match
->
limit
)
return
(
-
1
);
match
->
indices
[
match
->
n
]
=
y
->
idx
;
match
->
n
++
;
if
(
y
->
idx
<
match
->
min
)
match
->
min
=
y
->
idx
;
if
(
y
->
idx
>
match
->
max
)
match
->
max
=
y
->
idx
;
}
if
(
i
<
y
->
len
)
return
(
0
);
if
(
pt_search
(
y
->
leaf
[
0
],
strings
,
c
,
match
)
!=
0
)
return
(
-
1
);
if
(
pt_search
(
y
->
leaf
[
1
],
strings
,
c
,
match
)
!=
0
)
return
(
-
1
);
return
(
0
);
}
int
PT_Prefixes
(
const
struct
pt_y
*
const
restrict
root
,
char
*
const
restrict
*
const
restrict
strings
,
const
char
*
const
restrict
subject
,
struct
match_data
*
const
restrict
match
)
{
CHECK_OBJ_NOTNULL
(
match
,
MATCH_DATA_MAGIC
);
AN
(
match
->
indices
);
AN
(
match
->
limit
);
AN
(
strings
);
AN
(
subject
);
match
->
n
=
0
;
match
->
min
=
UINT_MAX
;
match
->
max
=
0
;
return
(
pt_search
(
root
,
strings
,
(
unsigned
char
*
)
subject
,
match
));
}
void
PT_Free
(
struct
pt_y
*
y
)
{
...
...
src/patricia.h
View file @
7f187041
...
...
@@ -34,16 +34,15 @@
struct
pt_y
;
#if 0
struct t_stats {
struct
match_data
{
unsigned
magic
;
#define
T_STATS_MAGIC 0xf92e6603
double d_mean
;
unsigned
d_max
;
unsigned n
_nodes
;
unsigned
n_leaves
;
}
#endif
#define
MATCH_DATA_MAGIC 0x0d9a845e
unsigned
*
indices
;
unsigned
limit
;
unsigned
n
;
unsigned
min
;
unsigned
max
;
};
void
PT_Init
(
void
);
int
PT_Inited
(
void
);
...
...
@@ -52,5 +51,9 @@ int PT_Insert(struct pt_y * * restrict root, unsigned idx,
unsigned
PT_Lookup
(
const
struct
pt_y
*
const
restrict
root
,
char
*
const
restrict
*
const
restrict
strings
,
const
char
*
const
restrict
subject
);
int
PT_Prefixes
(
const
struct
pt_y
*
const
restrict
root
,
char
*
const
restrict
*
const
restrict
strings
,
const
char
*
const
restrict
subject
,
struct
match_data
*
const
restrict
match
);
void
PT_Free
(
struct
pt_y
*
y
);
struct
vsb
*
PT_Dump
(
struct
pt_y
*
root
,
char
**
strings
);
src/tests/prefix.vtc
0 → 100644
View file @
7f187041
This diff is collapsed.
Click to expand it.
src/vmod_selector.c
View file @
7f187041
...
...
@@ -39,6 +39,7 @@
#include "vre.h"
#include "cache/cache_director.h"
#include "vcc_if.h"
#include "patricia.h"
#define VFAIL(ctx, fmt, ...) \
...
...
@@ -48,6 +49,9 @@
VSLb((ctx)->vsl, SLT_VCL_Error, "vmod selector error: " fmt, \
__VA_ARGS__)
#define VERRNOMEM(ctx, fmt, ...) \
VERR((ctx), "out of space: " fmt, __VA_ARGS__)
struct
entry
{
unsigned
magic
;
#define VMOD_SELECTOR_ENTRY_MAGIC 0x733dbe63
...
...
@@ -205,11 +209,42 @@ vmod_set_add(VRT_CTX, struct vmod_selector_set *set, VCL_STRING member,
set
->
table
[
n
-
1
]
=
entry
;
}
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
);
task
->
free
=
NULL
;
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
;
CHECK_OBJ_NOTNULL
(
ctx
,
VRT_CTX_MAGIC
);
CHECK_OBJ_NOTNULL
(
set
,
VMOD_SELECTOR_SET_MAGIC
);
AN
(
set
->
origo
);
AN
(
set
->
members
);
if
(
subject
==
NULL
)
{
VERR
(
ctx
,
"%s.match(): subject string is NULL"
,
set
->
vcl_name
);
...
...
@@ -220,9 +255,162 @@ vmod_set_match(VRT_CTX, struct vmod_selector_set *set, VCL_STRING subject)
return
(
0
);
}
match
=
get_match_data
(
ctx
,
set
,
"match"
);
if
((
idx
=
PT_Lookup
(
set
->
origo
,
set
->
members
,
subject
))
==
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
;
return
(
1
);
}
VCL_BOOL
vmod_set_hasprefix
(
VRT_CTX
,
struct
vmod_selector_set
*
set
,
VCL_STRING
subject
)
{
struct
match_data
*
match
;
CHECK_OBJ_NOTNULL
(
ctx
,
VRT_CTX_MAGIC
);
CHECK_OBJ_NOTNULL
(
set
,
VMOD_SELECTOR_SET_MAGIC
);
AN
(
set
->
origo
);
AN
(
set
->
members
);
return
(
PT_Lookup
(
set
->
origo
,
set
->
members
,
subject
)
!=
UINT_MAX
);
if
(
subject
==
NULL
)
{
VERR
(
ctx
,
"%s.hasprefix(): subject string is NULL"
,
set
->
vcl_name
);
return
(
0
);
}
if
(
set
->
nmembers
==
0
)
{
VERR
(
ctx
,
"%s.hasprefix(): no entries were added"
,
set
->
vcl_name
);
return
(
0
);
}
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
);
return
(
0
);
}
match
->
indices
=
(
unsigned
*
)
WS_Front
(
ctx
->
ws
);
if
(
PT_Prefixes
(
set
->
origo
,
set
->
members
,
subject
,
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
);
}
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
)
{
VERR
(
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
vmod_selector_set
*
set
,
VCL_INT
idx
)
{
struct
match_data
*
match
;
CHECK_OBJ_NOTNULL
(
ctx
,
VRT_CTX_MAGIC
);
CHECK_OBJ_NOTNULL
(
set
,
VMOD_SELECTOR_SET_MAGIC
);
if
(
idx
<
1
||
idx
>
set
->
nmembers
)
{
VERR
(
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
));
/* XXX search algorithm? */
idx
--
;
for
(
unsigned
i
=
0
;
i
<
match
->
n
;
i
++
)
if
(
match
->
indices
[
i
]
==
idx
)
return
(
1
);
return
(
0
);
}
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
==
vmod_enum_UNIQUE
)
{
if
(
match
->
n
!=
1
)
{
VERR
(
ctx
,
"%s.%s(select=UNIQUE): "
"%d elements were matched"
,
obj
,
method
,
match
->
n
);
return
(
UINT_MAX
);
}
return
match
->
indices
[
0
];
}
if
(
selects
==
vmod_enum_FIRST
)
return
match
->
min
;
if
(
selects
==
vmod_enum_LAST
)
return
match
->
max
;
if
(
selects
==
vmod_enum_SHORTEST
)
return
match
->
indices
[
0
];
if
(
selects
==
vmod_enum_LONGEST
)
return
match
->
indices
[
match
->
n
-
1
];
WRONG
(
"illegal select enum"
);
return
(
UINT_MAX
);
}
VCL_INT
vmod_set_which
(
VRT_CTX
,
struct
vmod_selector_set
*
set
,
VCL_ENUM
selects
)
{
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
,
"which"
);
if
(
match
==
NULL
||
match
->
n
==
0
)
return
(
0
);
return
(
select
(
ctx
,
match
,
set
->
vcl_name
,
selects
,
"which"
)
+
1
);
}
VCL_STRING
...
...
src/vmod_selector.vcc
View file @
7f187041
...
...
@@ -64,6 +64,46 @@ Example::
call do_on_match;
}
$Method BOOL .hasprefix(STRING)
Returns ``true`` if and only if ...
Example::
if (myset.hasprefix(req.url)) {
call do_if_prefix_matched;
}
$Method INT .nmatches()
Returns ...
Example::
if (myset.hasprefix(req.url)) {
# ...
}
$Method BOOL .matched(INT)
Returns ...
Example::
if (myset.hasprefix(req.url)) {
# ...
}
$Method INT .which(ENUM {UNIQUE, FIRST, LAST, SHORTEST, LONGEST} select=UNIQUE)
Returns ...
Example::
if (myset.hasprefix(req.url)) {
# ...
}
$Method STRING .debug()
Intentionally not documented.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment