Add escape/unescape functions

This commit is contained in:
Peter Eisentraut 2015-10-03 00:31:37 -04:00
parent 817deaaa30
commit 290dd477f3
7 changed files with 200 additions and 1 deletions

View File

@ -13,7 +13,7 @@ endif
PG_CPPFLAGS += $(shell $(PKG_CONFIG) --cflags-only-I liburiparser) PG_CPPFLAGS += $(shell $(PKG_CONFIG) --cflags-only-I liburiparser)
SHLIB_LINK += $(shell $(PKG_CONFIG) --libs liburiparser) SHLIB_LINK += $(shell $(PKG_CONFIG) --libs liburiparser)
REGRESS = init test REGRESS = init test escape
REGRESS_OPTS = --inputdir=test REGRESS_OPTS = --inputdir=test
PGXS := $(shell $(PG_CONFIG) --pgxs) PGXS := $(shell $(PG_CONFIG) --pgxs)

View File

@ -126,3 +126,22 @@ Other functions:
without normalization. If you want to consider distinct URIs without normalization. If you want to consider distinct URIs
without regard for mostly irrelevant syntax differences, pass them without regard for mostly irrelevant syntax differences, pass them
through this function. through this function.
- `uri_escape(text, space_to_plus boolean DEFAULT false, normalize_breaks boolean DEFAULT false) returns text`
Percent-encodes all reserved characters from the text. This can
be useful for constructing URIs from strings.
If `space_to_plus` is true, then spaces are replaced by plus
signs. If `normalize_breaks` is true, then line breaks are
converted to CR LF pairs (and subsequently percent-encoded). Note
that these two conversions come from the HTML standard for
encoding form data but are not part of the specification for URIs.
- `uri_unescape(text, plus_to_space boolean DEFAULT false, break_conversion boolean DEFAULT false) returns text`
Decodes all percent-encodings in the text.
If `plus_to_space` is true, then plus signs are converted to
spaces. If `break_conversion` is true, then CR LF pairs are
converted to simple newlines (`\n`).

99
test/expected/escape.out Normal file
View File

@ -0,0 +1,99 @@
SELECT uri_escape('foobar');
uri_escape
------------
foobar
(1 row)
SELECT uri_escape(':/?#[]@!$&''()*+,;=');
uri_escape
--------------------------------------------------------
%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D
(1 row)
SELECT uri_escape('foo bar');
uri_escape
------------
foo%20bar
(1 row)
SELECT uri_escape('foo bar', space_to_plus := false);
uri_escape
------------
foo%20bar
(1 row)
SELECT uri_escape('foo bar', space_to_plus := true);
uri_escape
------------
foo+bar
(1 row)
SELECT uri_escape(E'foo\nbar');
uri_escape
------------
foo%0Abar
(1 row)
SELECT uri_escape(E'foo\nbar', normalize_breaks := false);
uri_escape
------------
foo%0Abar
(1 row)
SELECT uri_escape(E'foo\nbar', normalize_breaks := true);
uri_escape
--------------
foo%0D%0Abar
(1 row)
SELECT uri_unescape('foobar');
uri_unescape
--------------
foobar
(1 row)
SELECT uri_unescape('%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D');
uri_unescape
--------------------
:/?#[]@!$&'()*+,;=
(1 row)
SELECT uri_unescape('foo+bar');
uri_unescape
--------------
foo+bar
(1 row)
SELECT uri_unescape('foo+bar', plus_to_space := false);
uri_unescape
--------------
foo+bar
(1 row)
SELECT uri_unescape('foo+bar', plus_to_space := true);
uri_unescape
--------------
foo bar
(1 row)
SELECT uri_unescape('foo%0D%0Abar');
uri_unescape
--------------
foo +
bar
(1 row)
SELECT uri_unescape('foo%0D%0Abar', break_conversion := false);
uri_unescape
--------------
foo +
bar
(1 row)
SELECT uri_unescape('foo%0D%0Abar', break_conversion := true);
uri_unescape
--------------
foo\r +
bar
(1 row)

21
test/sql/escape.sql Normal file
View File

@ -0,0 +1,21 @@
SELECT uri_escape('foobar');
SELECT uri_escape(':/?#[]@!$&''()*+,;=');
SELECT uri_escape('foo bar');
SELECT uri_escape('foo bar', space_to_plus := false);
SELECT uri_escape('foo bar', space_to_plus := true);
SELECT uri_escape(E'foo\nbar');
SELECT uri_escape(E'foo\nbar', normalize_breaks := false);
SELECT uri_escape(E'foo\nbar', normalize_breaks := true);
SELECT uri_unescape('foobar');
SELECT uri_unescape('%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D');
SELECT uri_unescape('foo+bar');
SELECT uri_unescape('foo+bar', plus_to_space := false);
SELECT uri_unescape('foo+bar', plus_to_space := true);
SELECT uri_unescape('foo%0D%0Abar');
SELECT uri_unescape('foo%0D%0Abar', break_conversion := false);
SELECT uri_unescape('foo%0D%0Abar', break_conversion := true);

View File

@ -8,3 +8,15 @@ CREATE OPERATOR CLASS uri_ops_hash
DEFAULT FOR TYPE uri USING hash AS DEFAULT FOR TYPE uri USING hash AS
OPERATOR 1 =, OPERATOR 1 =,
FUNCTION 1 uri_hash(uri); FUNCTION 1 uri_hash(uri);
CREATE FUNCTION uri_escape(text, space_to_plus boolean DEFAULT false, normalize_breaks boolean DEFAULT false) RETURNS text
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_unescape(text, plus_to_space boolean DEFAULT false, break_conversion boolean DEFAULT false) RETURNS text
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';

View File

@ -211,3 +211,15 @@ CREATE OPERATOR CLASS uri_ops_hash
DEFAULT FOR TYPE uri USING hash AS DEFAULT FOR TYPE uri USING hash AS
OPERATOR 1 =, OPERATOR 1 =,
FUNCTION 1 uri_hash(uri); FUNCTION 1 uri_hash(uri);
CREATE FUNCTION uri_escape(text, space_to_plus boolean DEFAULT false, normalize_breaks boolean DEFAULT false) RETURNS text
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';
CREATE FUNCTION uri_unescape(text, plus_to_space boolean DEFAULT false, break_conversion boolean DEFAULT false) RETURNS text
IMMUTABLE
STRICT
LANGUAGE C
AS '$libdir/uri';

36
uri.c
View File

@ -455,3 +455,39 @@ uri_hash(PG_FUNCTION_ARGS)
return result; return result;
} }
PG_FUNCTION_INFO_V1(uri_escape);
Datum
uri_escape(PG_FUNCTION_ARGS)
{
text *arg = PG_GETARG_TEXT_PP(0);
bool space_to_plus = PG_GETARG_BOOL(1);
bool normalize_breaks = PG_GETARG_BOOL(2);
size_t chars_required;
char *ret;
chars_required = (VARSIZE(arg) - 4) * (normalize_breaks ? 6 : 3) + 1;
ret = palloc(chars_required);
uriEscapeExA(VARDATA(arg),
VARDATA(arg) + VARSIZE(arg) - 4,
ret,
space_to_plus, normalize_breaks);
PG_RETURN_TEXT_P(cstring_to_text(ret));
}
PG_FUNCTION_INFO_V1(uri_unescape);
Datum
uri_unescape(PG_FUNCTION_ARGS)
{
text *arg = PG_GETARG_TEXT_PP(0);
bool plus_to_space = PG_GETARG_BOOL(1);
bool break_conversion = PG_GETARG_BOOL(2);
char *s = text_to_cstring(arg);
uriUnescapeInPlaceExA(s, plus_to_space, break_conversion);
PG_RETURN_TEXT_P(cstring_to_text(s));
}