-
Notifications
You must be signed in to change notification settings - Fork 2
/
uri.erl
92 lines (77 loc) · 2.37 KB
/
uri.erl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
%%%-------------------------------------------------------------------
%%% File : url.erl
%%% Author : Jesper Louis Andersen <jesper.louis.andersen@gmail.com>
%%% Description : URI handling code, as in RFC3986
%%%
%%% Created : 14 Oct 2010 by Jesper Louis Andersen <jesper.louis.andersen@gmail.com>
%%%-------------------------------------------------------------------
-module(uri).
%% API
-export([mk/2, mk/3, mk/4,
mk_hier/2,
to_iolist/1, to_string/1]).
-record(hier,
{authority :: string() | none,
path :: string() | none}).
-record(uri,
{scheme :: atom(),
hier :: #hier{},
q :: [{string(), string()}],
fragment :: string() | none}).
%%====================================================================
%% API
%%====================================================================
mk(S, H) ->
mk(S,H,[],none).
mk(S,H,Q) ->
mk(S,H,Q,none).
mk(S,H,Q,F) ->
#uri{scheme = S, hier = H, q = Q, fragment = F}.
mk_hier(A, P) ->
#hier{authority = A, path = P}.
-spec to_iolist(#uri{}) -> iolist().
to_iolist(#uri{scheme = S, hier = H, q = Q, fragment = F}) ->
[atom_to_list(S),":",
hier_to_iolist(H),
query_to_iolist(Q),
fragment_to_iolist(F)].
-spec to_string(#uri{}) -> string().
to_string(Uri) ->
lists:flatten(to_iolist(Uri)).
%%====================================================================
%% Internal functions
%%====================================================================
hier_to_iolist(#hier{authority = A, path = P}) ->
case {A,P} of
{none, none} -> "";
{none, P1} -> P1;
{A1, none} -> ["//", A1];
{A1, P1} -> ["//", A1, "/", P1]
end.
query_to_iolist([]) ->
"";
query_to_iolist(L) ->
["?", [[percent_encode(K), "=", percent_encode(V)] || {K, V} <- L]].
fragment_to_iolist(none) ->
"";
fragment_to_iolist(Frag) ->
["#", percent_encode(Frag)].
should_escape(C) when $A =< C andalso C =< $Z -> false;
should_escape(C) when $a =< C andalso C =< $z -> false;
should_escape(C) when $0 =< C andalso C =< $9 -> false;
should_escape(C) when is_integer(C) ->
not lists:member(C, "_.-~").
hex(B) ->
binary:sub(B, <<"0123456789abcdef">>).
hex_write(C) ->
Upper = C bsr 4,
Lower = C band 15,
[hex(Upper), hex(Lower)].
percent_encode(Str) ->
[begin
case should_escape(C) of
false -> C;
true when 0 =< C andalso C < 256 ->
["%", hex_write(C)]
end
end || C <- Str].