mirror of
https://github.com/correl/urilib.git
synced 2024-11-22 03:00:16 +00:00
WIP commit
This commit is contained in:
parent
f16b0be421
commit
7b05c0c2b5
4 changed files with 192 additions and 13 deletions
2
Makefile
2
Makefile
|
@ -5,7 +5,7 @@ all: get-deps compile
|
||||||
|
|
||||||
build-plt:
|
build-plt:
|
||||||
@dialyzer --build_plt --output_plt ~/.$(PROJECT).plt \
|
@dialyzer --build_plt --output_plt ~/.$(PROJECT).plt \
|
||||||
--apps kernel stdlib erts
|
--apps kernel stdlib erts inets edoc
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@( $(REBAR) clean )
|
@( $(REBAR) clean )
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
{application, urilib, [
|
{application, urilib, [
|
||||||
{description, "RFC-3986 URI Library"},
|
{description, "RFC-3986 URI Library"},
|
||||||
{vsn, "0.1.0"},
|
{vsn, "0.1.0"},
|
||||||
{registered, []},
|
{registered, [urilib]},
|
||||||
{applications, [
|
{applications, [
|
||||||
kernel,
|
kernel,
|
||||||
stdlib,
|
stdlib,
|
||||||
|
inets,
|
||||||
edoc
|
edoc
|
||||||
]},
|
]},
|
||||||
{mod, {urilib, []}},
|
{mod, {urilib, []}},
|
||||||
|
|
132
src/urilib.erl
132
src/urilib.erl
|
@ -7,7 +7,6 @@
|
||||||
-module(urilib).
|
-module(urilib).
|
||||||
|
|
||||||
-export([build/1,
|
-export([build/1,
|
||||||
parse/1,
|
|
||||||
parse_uri/1,
|
parse_uri/1,
|
||||||
parse_url/1,
|
parse_url/1,
|
||||||
encode/1,
|
encode/1,
|
||||||
|
@ -30,22 +29,60 @@
|
||||||
%% @doc Returns a URI from the record passed in.
|
%% @doc Returns a URI from the record passed in.
|
||||||
%%
|
%%
|
||||||
%% @end
|
%% @end
|
||||||
build(_URL) ->
|
build(#uri{scheme=Scheme, userinfo=UserInfo, authority=Authority,
|
||||||
ok.
|
path=Path, query=QArgs, fragment=Fragment}) ->
|
||||||
|
U1 = url_add_scheme(Scheme),
|
||||||
|
U2 = url_maybe_add_user(UserInfo, U1),
|
||||||
-spec parse(string()) -> #uri{}.
|
U3 = url_add_host_and_port(Scheme,
|
||||||
parse(URL) -> parse_uri(URL).
|
Authority#authority.host,
|
||||||
|
Authority#authority.port, U2),
|
||||||
|
U4 = url_add_path(Path, U3),
|
||||||
|
U5 = url_maybe_add_qargs(QArgs, U4),
|
||||||
|
url_maybe_add_fragment(Fragment, U5).
|
||||||
|
|
||||||
|
|
||||||
-spec parse_uri(string()) -> #uri{}.
|
-spec parse_uri(string()) -> #uri{}.
|
||||||
parse_uri(_URL) ->
|
%% @spec parse_uri(URI) -> ParsedURI.
|
||||||
ok.
|
%% where
|
||||||
|
%% URI = string()
|
||||||
|
%% ParsedURI = #uri{}
|
||||||
|
%% @doc Parse a URI string returning the parsed data as a record
|
||||||
|
%% @end
|
||||||
|
parse_uri(URI) ->
|
||||||
|
case http_uri:parse(URI, [{scheme_defaults, http_uri:scheme_defaults()}, {fragment, true}]) of
|
||||||
|
{ok, {Scheme, UserInfo, Host, Port, Path, Query, Fragment}} ->
|
||||||
|
#uri{scheme=Scheme,
|
||||||
|
userinfo=parse_userinfo(UserInfo),
|
||||||
|
authority=#authority{host=Host,
|
||||||
|
port=Port},
|
||||||
|
path=Path,
|
||||||
|
query=parse_query(Query),
|
||||||
|
fragment=Fragment};
|
||||||
|
{error, Reason} -> {error, Reason}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
-spec parse_url(string()) -> #url{}.
|
-spec parse_url(string()) -> #url{}.
|
||||||
parse_url(_URL) ->
|
%% @spec parse_url(URL) -> ParsedURL.
|
||||||
ok.
|
%% where
|
||||||
|
%% URI = string()
|
||||||
|
%% ParsedURL = #url{}
|
||||||
|
%% @doc Parse a URL string returning the parsed data as a record
|
||||||
|
%% @end
|
||||||
|
parse_url(URL) ->
|
||||||
|
case http_uri:parse(URL, [{scheme_defaults, http_uri:scheme_defaults()}, {fragment, true}]) of
|
||||||
|
{ok, {Scheme, UserInfo, Host, Port, Path, Query, Fragment}} ->
|
||||||
|
User = parse_userinfo(UserInfo),
|
||||||
|
#url{scheme=Scheme,
|
||||||
|
username=User#userinfo.username,
|
||||||
|
password=User#userinfo.password,
|
||||||
|
host=Host,
|
||||||
|
port=Port,
|
||||||
|
path=Path,
|
||||||
|
query=parse_query(Query),
|
||||||
|
fragment=Fragment};
|
||||||
|
{error, Reason} -> {error, Reason}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
-spec encode(string()) -> string().
|
-spec encode(string()) -> string().
|
||||||
|
@ -97,3 +134,76 @@ decode(Value) ->
|
||||||
%% @end
|
%% @end
|
||||||
decode_plus(Value) ->
|
decode_plus(Value) ->
|
||||||
string:join([http_uri:decode(V) || V <- string:tokens(Value, "+")], " ").
|
string:join([http_uri:decode(V) || V <- string:tokens(Value, "+")], " ").
|
||||||
|
|
||||||
|
|
||||||
|
-spec parse_query(string()) -> [].
|
||||||
|
%% @private
|
||||||
|
parse_query([]) -> [];
|
||||||
|
parse_query(Query) ->
|
||||||
|
case re:split(Query, "[&|?]", [{return, list}]) of
|
||||||
|
[""] -> [];
|
||||||
|
QArgs -> [split_query_arg(Arg) || Arg <- QArgs, Arg =/= []]
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
-spec parse_userinfo(string()) -> #userinfo{}.
|
||||||
|
%% @private
|
||||||
|
parse_userinfo([]) -> #userinfo{};
|
||||||
|
parse_userinfo(Value) ->
|
||||||
|
case string:tokens(Value, ":") of
|
||||||
|
[User, Password] -> #userinfo{username=User, password=Password};
|
||||||
|
[User] -> #userinfo{username=User}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
-spec split_query_arg(string()) -> {string(), string()}.
|
||||||
|
%% @private
|
||||||
|
split_query_arg(Argument) ->
|
||||||
|
[K, V] = string:tokens(Argument, "="),
|
||||||
|
{K, V}.
|
||||||
|
|
||||||
|
|
||||||
|
%% @private
|
||||||
|
url_add_scheme(Scheme) ->
|
||||||
|
string:concat(atom_to_list(Scheme), "://").
|
||||||
|
|
||||||
|
|
||||||
|
%% @private
|
||||||
|
url_maybe_add_user([], URL) -> URL;
|
||||||
|
url_maybe_add_user(User, URL) ->
|
||||||
|
string:concat(URL, string:concat(User, "@")).
|
||||||
|
|
||||||
|
|
||||||
|
%% @private
|
||||||
|
url_add_host_and_port(http, Host, 80, URL) ->
|
||||||
|
string:concat(URL, Host);
|
||||||
|
|
||||||
|
|
||||||
|
%% @private
|
||||||
|
url_add_host_and_port(https, Host, 443, URL) ->
|
||||||
|
string:concat(URL, Host);
|
||||||
|
url_add_host_and_port(_, Host, Port, URL) ->
|
||||||
|
string:concat(URL, string:join([Host, integer_to_list(Port)], ":")).
|
||||||
|
|
||||||
|
|
||||||
|
%% @private
|
||||||
|
url_add_path(Path, URL) ->
|
||||||
|
Escaped = string:join([edoc_lib:escape_uri(P) || P <- string:tokens(Path, "/")], "/"),
|
||||||
|
string:join([URL, Escaped], "/").
|
||||||
|
|
||||||
|
|
||||||
|
%% @private
|
||||||
|
url_maybe_add_qargs([], URL) -> URL;
|
||||||
|
url_maybe_add_qargs(QArgs, URL) ->
|
||||||
|
QStr = string:join([string:join([encode_plus(K), encode_plus(V)], "=") || {K,V} <- QArgs], "&"),
|
||||||
|
string:join([URL, QStr], "?").
|
||||||
|
|
||||||
|
|
||||||
|
%% @private
|
||||||
|
url_maybe_add_fragment([], URL) -> URL;
|
||||||
|
url_maybe_add_fragment(Value, URL) ->
|
||||||
|
Fragment = case string:left(Value, 1) of
|
||||||
|
"#" -> edoc_lib:escape_uri(string:sub_string(Value, 2));
|
||||||
|
_ -> edoc_lib:escape_uri(Value)
|
||||||
|
end,
|
||||||
|
string:join([URL, Fragment], "#").
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
-include("urilib.hrl").
|
||||||
|
|
||||||
decode_test() ->
|
decode_test() ->
|
||||||
Value = "foo%2fbar%20baz",
|
Value = "foo%2fbar%20baz",
|
||||||
|
@ -27,3 +28,70 @@ encode_plus1_test() ->
|
||||||
Value = "foo/bar baz",
|
Value = "foo/bar baz",
|
||||||
Expect = "foo%2fbar+baz",
|
Expect = "foo%2fbar+baz",
|
||||||
?assertEqual(Expect, urilib:encode_plus(Value)).
|
?assertEqual(Expect, urilib:encode_plus(Value)).
|
||||||
|
|
||||||
|
parse_uri_variation1_test() ->
|
||||||
|
URI = "amqp://guest:rabbitmq@rabbitmq:5672/%2f?heartbeat=5",
|
||||||
|
Expect = #uri{scheme=amqp,
|
||||||
|
userinfo=#userinfo{username="guest",
|
||||||
|
password="rabbitmq"},
|
||||||
|
authority=#authority{host="rabbitmq", port=5672},
|
||||||
|
path="/%2f",
|
||||||
|
query=[{"heartbeat", "5"}],
|
||||||
|
fragment=[]},
|
||||||
|
?assertEqual(Expect, urilib:parse_uri(URI)).
|
||||||
|
|
||||||
|
parse_uri_variation2_test() ->
|
||||||
|
URI = "http://www.google.com/search?foo=bar#baz",
|
||||||
|
Expect = #uri{scheme=http,
|
||||||
|
userinfo=#userinfo{},
|
||||||
|
authority=#authority{host="www.google.com", port=80},
|
||||||
|
path="/search",
|
||||||
|
query=[{"foo", "bar"}],
|
||||||
|
fragment="#baz"},
|
||||||
|
?assertEqual(Expect, urilib:parse_uri(URI)).
|
||||||
|
|
||||||
|
parse_uri_variation3_test() ->
|
||||||
|
URI = "https://www.google.com/search",
|
||||||
|
Expect = #uri{scheme=https,
|
||||||
|
userinfo=#userinfo{},
|
||||||
|
authority=#authority{host="www.google.com", port=443},
|
||||||
|
path="/search",
|
||||||
|
query=[],
|
||||||
|
fragment=[]},
|
||||||
|
?assertEqual(Expect, urilib:parse_uri(URI)).
|
||||||
|
|
||||||
|
parse_url_variation1_test() ->
|
||||||
|
URL = "amqp://guest:rabbitmq@rabbitmq:5672/%2f?heartbeat=5",
|
||||||
|
Expect = #url{scheme=amqp,
|
||||||
|
username="guest",
|
||||||
|
password="rabbitmq",
|
||||||
|
host="rabbitmq",
|
||||||
|
port=5672,
|
||||||
|
path="/%2f",
|
||||||
|
query=[{"heartbeat", "5"}],
|
||||||
|
fragment=[]},
|
||||||
|
?assertEqual(Expect, urilib:parse_url(URL)).
|
||||||
|
|
||||||
|
parse_url_variation2_test() ->
|
||||||
|
URL = "http://www.google.com/search?foo=bar#baz",
|
||||||
|
Expect = #url{scheme=http,
|
||||||
|
username=undefined,
|
||||||
|
password=undefined,
|
||||||
|
host="www.google.com",
|
||||||
|
port=80,
|
||||||
|
path="/search",
|
||||||
|
query=[{"foo", "bar"}],
|
||||||
|
fragment="#baz"},
|
||||||
|
?assertEqual(Expect, urilib:parse_url(URL)).
|
||||||
|
|
||||||
|
parse_url_variation3_test() ->
|
||||||
|
URL = "https://www.google.com/search",
|
||||||
|
Expect = #url{scheme=https,
|
||||||
|
username=undefined,
|
||||||
|
password=undefined,
|
||||||
|
host="www.google.com",
|
||||||
|
port=443,
|
||||||
|
path="/search",
|
||||||
|
query=[],
|
||||||
|
fragment=[]},
|
||||||
|
?assertEqual(Expect, urilib:parse_url(URL)).
|
||||||
|
|
Loading…
Reference in a new issue