diff --git a/include/urilib.hrl b/include/urilib.hrl new file mode 100644 index 0000000..f2e92de --- /dev/null +++ b/include/urilib.hrl @@ -0,0 +1,27 @@ +%% ============================================================================= +%% @author Gavin M. Roy +%% @copyright 2016 +%% @end +%% ============================================================================= + +-record(authority, {host :: string(), + port :: integer()}). + +-record(userinfo, {username :: string() | undefined, + password :: string() | undefined}). + +-record(uri, {scheme :: atom(), + userinfo :: #userinfo{} | undefined, + authority :: #authority{}, + path :: string() | undefined, + query, + fragment :: string() | undefined}). + +-record(url, {scheme :: atom(), + username :: string() | undefined, + password :: string() | undefined, + host :: string(), + port :: integer(), + path :: string() | undefined, + query, + fragment :: string() | undefined}). diff --git a/src/urilib.app.src b/src/urilib.app.src new file mode 100644 index 0000000..54821cd --- /dev/null +++ b/src/urilib.app.src @@ -0,0 +1,12 @@ +{application, urilib, [ + {description, "RFC-3986 URI Library"}, + {vsn, "0.1.0"}, + {registered, []}, + {applications, [ + kernel, + stdlib, + edoc + ]}, + {mod, {urilib, []}}, + {env, []} +]}. diff --git a/src/urilib.erl b/src/urilib.erl new file mode 100644 index 0000000..fdb878b --- /dev/null +++ b/src/urilib.erl @@ -0,0 +1,111 @@ +%% ============================================================================= +%% @author Gavin M. Roy +%% @copyright 2016 +%% @doc urilib is a RFC-3986 URI Library for Erlang +%% @end +%% ============================================================================= +-module(urilib). + +-export([build/1, + parse/1, + parse_uri/1, + parse_url/1, + encode/1, + encode/2, + encode_plus/1, + encode_plus/2, + decode/1, + decode_plus/1]). + +-include("urilib.hrl"). + +%% Export all for unit tests +-ifdef(TEST). +-compile(export_all). +-endif. + +-spec build(#uri{} | #url{}) -> string(). +%% @spec build(Value) -> URI +%% where +%% Value = #uri{} | #url{} +%% URI = string() +%% @doc Returns a URI from the record passed in. +%% +%% @end +build(_URL) -> + ok. + + +-spec parse(string()) -> #uri{}. +parse(URL) -> parse_uri(URL). + + +-spec parse_uri(string()) -> #uri{}. +parse_uri(_URL) -> + ok. + + +-spec parse_url(string()) -> #url{}. +parse_url(_URL) -> + ok. + + +-spec encode(string()) -> string(). +%% @spec encode(Value) -> EncodedValue +%% where +%% Value = string() +%% EncodedValue = string() +%% @doc Percent encode a string value. +%% @end +encode(Value) -> + edoc_lib:escape_uri(Value). + + +-spec encode(string(), string()) -> string(). +encode(_Value, _Safe) -> + ok. + + +-spec encode_plus(string()) -> string(). +%% @spec encode_plus(Value) -> EncodedValue +%% where +%% Value = string() +%% EncodedValue = string() +%% @doc Percent encode a string value similar to encode/1, but encodes spaces with a +%% plus (+) instead of %20. This function can be used for encoding query arguments. +%% +%% Note: The use of plus for space is defined in RFC-1630 but does not appear +%% in RFC-3986. +%% @end +encode_plus(Value) -> + string:join([edoc_lib:escape_uri(V) || V <- string:tokens(Value, " ")], "+"). + + +-spec encode_plus(string(), string()) -> string(). +encode_plus(_Value, _Safe) -> + ok. + + +%% @spec decode(Value) -> DecodedValue +%% where +%% Value = string() +%% DecodeValue = string() +%% @doc Decode a percent encoded string value. +%% @end +-spec decode(string()) -> string(). +decode(Value) -> + http_uri:decode(Value). + + +-spec decode_plus(string()) -> string(). +%% @spec decode_plus(Value) -> DecodedValue +%% where +%% Value = string() +%% DecodeValue = string() +%% @doc Decode a percent encoded string value that uses pluses for spaces. +%% +%% Note: The use of plus for space is defined in RFC-1630 but does not appear +%% in RFC-3986. +%% @end +decode_plus(Value) -> + string:join([http_uri:decode(V) || V <- string:tokens(Value, "+")], " "). diff --git a/test/urilib_tests.erl b/test/urilib_tests.erl new file mode 100644 index 0000000..bc30a5e --- /dev/null +++ b/test/urilib_tests.erl @@ -0,0 +1,24 @@ +-module(urilib_tests). + +-include_lib("eunit/include/eunit.hrl"). + + +decode_test() -> + Value = "foo%2fbar%20baz", + Expect = "foo/bar baz", + ?assertEqual(Expect, urilib:decode(Value)). + +encode1_test() -> + Value = "foo/bar baz", + Expect = "foo%2fbar%20baz", + ?assertEqual(Expect, urilib:encode(Value)). + +encode1_unicode_test() -> + Value = "foo/bar✈baz", + Expect = "foo%2fbar%c0%88baz", + ?assertEqual(Expect, urilib:encode(Value)). + +encode_plus1_test() -> + Value = "foo/bar baz", + Expect = "foo%2fbar+baz", + ?assertEqual(Expect, urilib:encode_plus(Value)).