Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
libvmod-re2
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-re2
Commits
da00d672
Commit
da00d672
authored
Nov 09, 2017
by
Geoff Simmons
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Code re-org: move the set object implementation into a separate source.
parent
493cdcb2
Pipeline
#370
skipped
Changes
5
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
537 additions
and
441 deletions
+537
-441
Makefile.am
src/Makefile.am
+3
-0
re2.c
src/re2.c
+52
-0
set.c
src/set.c
+418
-0
vmod_re2.c
src/vmod_re2.c
+2
-441
vmod_re2.h
src/vmod_re2.h
+62
-0
No files found.
src/Makefile.am
View file @
da00d672
...
...
@@ -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
\
...
...
src/re2.c
0 → 100644
View file @
da00d672
/*-
* 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
);
}
}
src/set.c
0 → 100644
View file @
da00d672
/*-
* 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
];
}
src/vmod_re2.c
View file @
da00d672
...
...
@@ -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\"): "
...
...
src/vmod_re2.h
0 → 100644
View file @
da00d672
/*-
* 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
,
...);
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