Commit 798a37b7 authored by Geoff Simmons's avatar Geoff Simmons

Add the quotemeta() function.

parent 67e4e04b
......@@ -72,6 +72,9 @@ SYNOPSIS
BOOL <obj>.saved([ENUM {REGEX, STR, BE} which] [, INT n]
[, ENUM select])
# utility function
STRING re2.quotemeta(STRING)
# VMOD version
STRING re2.version()
......@@ -1664,6 +1667,35 @@ Example::
.. _func_quotemeta:
STRING quotemeta(STRING, STRING fallback)
-----------------------------------------
::
STRING quotemeta(
STRING,
STRING fallback="**QUOTEMETA FUNCTION FAILED**"
)
Returns a copy of the argument string with all regex metacharacters
escaped via backslash. When the returned string is used as a regular
expression, it will exactly match the original string, regardless of
any special characters. This function has a purpose similar to a
``\Q..\E`` sequence within a regex, or the ``literal=true`` setting in
a regex constructor.
The function fails and returns ``fallback`` if there is insufficient
workspace for the return string.
Example::
# The following are always true:
re2.quotemeta("1.5-2.0?") == "1\.5\-2\.0\?"
re2.match(re2.quotemeta("1.5-2.0?"), "1.5-2.0?"
.. _func_version:
STRING version()
......
# looks like -*- vcl -*-
varnishtest "quotemeta() function"
varnish v1 -vcl {
import ${vmod_re2};
backend be { .host = "${bad_ip}"; }
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
# Tests from re2 testing/re2_test.cc
set resp.http.q1 =
re2.match(re2.quotemeta("foo"), "foo");
set resp.http.q2 =
re2.match(re2.quotemeta("foo.bar"), "foo.bar");
set resp.http.q3 =
re2.match(re2.quotemeta("foo\.bar"), "foo\.bar");
set resp.http.q4 =
re2.match(re2.quotemeta("[1-9]"), "[1-9]");
set resp.http.q5 =
re2.match(re2.quotemeta("1.5-2.0?"), "1.5-2.0?");
set resp.http.q6 =
re2.match(re2.quotemeta("\d"), "\d");
set resp.http.q7 =
re2.match(re2.quotemeta("Who doesn't like ice cream?"),
"Who doesn't like ice cream?");
set resp.http.q8 =
re2.match(re2.quotemeta("((a|b)c?d*e+[f-h]i)"),
"((a|b)c?d*e+[f-h]i)");
set resp.http.q9 =
re2.match(re2.quotemeta("((?!)xxx).*yyy"),
"((?!)xxx).*yyy");
set resp.http.q10 =
re2.match(re2.quotemeta("(["), "([");
set resp.http.n1 =
re2.match(re2.quotemeta("..."), "bar");
set resp.http.n2 =
re2.match(re2.quotemeta("\."), ".");
set resp.http.n3 =
re2.match(re2.quotemeta("\."), "..");
set resp.http.n4 =
re2.match(re2.quotemeta("(a)"), "a");
set resp.http.n5 =
re2.match(re2.quotemeta("(a|b)"), "a");
set resp.http.n6 =
re2.match(re2.quotemeta("(a|b)"), "(a)");
set resp.http.n7 =
re2.match(re2.quotemeta("(a|b)"), "a|b");
set resp.http.n8 =
re2.match(re2.quotemeta("[0-9]"), "0");
set resp.http.n9 =
re2.match(re2.quotemeta("[0-9]"), "0-9");
set resp.http.n10 =
re2.match(re2.quotemeta("[0-9]"), "[9]");
set resp.http.latin1 =
re2.match(re2.quotemeta("3\xb2 = 9"), "3\xb2 = 9");
set resp.http.utf8-1 =
re2.match(re2.quotemeta("Plácido Domingo"),
"Plácido Domingo", utf8=true);
set resp.http.utf8-2 =
re2.match(re2.quotemeta("xyz"), "xyz", utf8=true);
set resp.http.utf8-3 =
re2.match(re2.quotemeta("\xc2\xb0"), "\xc2\xb0", utf8=true);
set resp.http.utf8-4 =
re2.match(re2.quotemeta("27\xc2\xb0 degrees"),
"27\xc2\xb0 degrees", utf8=true);
set resp.http.utf8-5 =
re2.match(re2.quotemeta("\xe2\x80\xb3"),
"\xe2\x80\xb3", utf8=true);
set resp.http.utf8-6 =
re2.match(re2.quotemeta("\xf0\x9d\x85\x9f"),
"\xf0\x9d\x85\x9f", utf8=true);
set resp.http.utf8-7 =
re2.match(re2.quotemeta("27\xc2\xb0"),
"27\xc2\xb0", utf8=true);
set resp.http.utf8-n =
re2.match(re2.quotemeta("27\xc2\xb0"),
"27\\xc2\\xb0", utf8=true);
# Example from re2.h
set resp.http.re2-h = re2.quotemeta("1.5-2.0?");
}
} -start
client c1 {
txreq
rxresp
expect resp.http.q1 == "true"
expect resp.http.q2 == "true"
expect resp.http.q3 == "true"
expect resp.http.q4 == "true"
expect resp.http.q5 == "true"
expect resp.http.q6 == "true"
expect resp.http.q7 == "true"
expect resp.http.q8 == "true"
expect resp.http.q9 == "true"
expect resp.http.q10 == "true"
expect resp.http.n1 == "false"
expect resp.http.n2 == "false"
expect resp.http.n3 == "false"
expect resp.http.n4 == "false"
expect resp.http.n5 == "false"
expect resp.http.n6 == "false"
expect resp.http.n7 == "false"
expect resp.http.n8 == "false"
expect resp.http.n9 == "false"
expect resp.http.n10 == "false"
expect resp.http.latin1 == "true"
expect resp.http.utf8-1 == "true"
expect resp.http.utf8-2 == "true"
expect resp.http.utf8-3 == "true"
expect resp.http.utf8-4 == "true"
expect resp.http.utf8-5 == "true"
expect resp.http.utf8-6 == "true"
expect resp.http.utf8-7 == "true"
expect resp.http.utf8-n == "false"
expect resp.http.re2-h == {1\.5\-2\.0\?}
} -run
......@@ -711,6 +711,34 @@ vmod_extract(VRT_CTX, VCL_STRING pattern, VCL_STRING text, VCL_STRING rewrite,
one_line);
}
#define ERR_PREFIX \
"re2.quotemeta(\"%.40s\", fallback=\"%.40s\"): "
VCL_STRING
vmod_quotemeta(VRT_CTX, VCL_STRING unquoted, VCL_STRING fallback)
{
size_t bytes, len;
char *ret;
const char *err;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
ret = WS_Front(ctx->ws);
bytes = WS_Reserve(ctx->ws, 0);
if (bytes == 0) {
VERR(ctx, ERR_PREFIX "workspace overflow", unquoted, fallback);
return fallback;
}
if ((err = vre2_quotemeta(unquoted, ret, bytes, &len)) != NULL) {
VERR(ctx, ERR_PREFIX "%s", unquoted, fallback, err);
WS_Release(ctx->ws, 0);
return fallback;
}
WS_Release(ctx->ws, len + 1);
return ret;
}
#undef ERR_PREFIX
VCL_STRING
vmod_version(const struct vrt_ctx *ctx __attribute__((unused)))
{
......
......@@ -59,6 +59,9 @@ SYNOPSIS
BOOL <obj>.saved([ENUM {REGEX, STR, BE} which] [, INT n]
[, ENUM select])
# utility function
STRING re2.quotemeta(STRING)
# VMOD version
STRING re2.version()
......@@ -1355,6 +1358,25 @@ Example::
# and which=REGEX by default.
}
$Function STRING quotemeta(STRING,
STRING fallback="**QUOTEMETA FUNCTION FAILED**")
Returns a copy of the argument string with all regex metacharacters
escaped via backslash. When the returned string is used as a regular
expression, it will exactly match the original string, regardless of
any special characters. This function has a purpose similar to a
``\Q..\E`` sequence within a regex, or the ``literal=true`` setting in
a regex constructor.
The function fails and returns ``fallback`` if there is insufficient
workspace for the return string.
Example::
# The following are always true:
re2.quotemeta("1.5-2.0?") == "1\.5\-2\.0\?"
re2.match(re2.quotemeta("1.5-2.0?"), "1.5-2.0?"
$Function STRING version()
Return the version string for this VMOD.
......
......@@ -218,6 +218,24 @@ vre2_rewrite(vre2 *vre2, const rewrite_e mode, const char * const text,
CATCHALL
}
const char *
vre2_quotemeta(const char * const unquoted, char * const dest,
const size_t bytes, size_t * const len)
{
try {
string result;
result = RE2::QuoteMeta(unquoted);
if (result.size() + 1 > bytes)
throw runtime_error("insufficient workspace");
*len = result.size();
result.copy(dest, *len);
dest[*len] = '\0';
return NULL;
}
CATCHALL
}
const char *
vre2_fini(vre2 **vre2)
{
......
......@@ -91,6 +91,9 @@ extern "C" {
const char * const rewrite,
char * const dest, const size_t bytes,
int * const match, size_t * const len);
const char *vre2_quotemeta(const char * const unquoted,
char * const dest, const size_t bytes,
size_t * const len);
#ifdef __cplusplus
}
......
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