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)
SHLIB_LINK += $(shell $(PKG_CONFIG) --libs liburiparser)
REGRESS = init test
REGRESS = init test escape
REGRESS_OPTS = --inputdir=test
PGXS := $(shell $(PG_CONFIG) --pgxs)

View File

@ -126,3 +126,22 @@ Other functions:
without normalization. If you want to consider distinct URIs
without regard for mostly irrelevant syntax differences, pass them
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
OPERATOR 1 =,
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
OPERATOR 1 =,
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;
}
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));
}