aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/stdlib/doc/src/uri_string.xml2
-rw-r--r--lib/stdlib/src/uri_string.erl142
2 files changed, 67 insertions, 77 deletions
diff --git a/lib/stdlib/doc/src/uri_string.xml b/lib/stdlib/doc/src/uri_string.xml
index 55d8690b98..8fa2a92370 100644
--- a/lib/stdlib/doc/src/uri_string.xml
+++ b/lib/stdlib/doc/src/uri_string.xml
@@ -119,7 +119,7 @@
<item><c>invalid_utf8</c></item>
<item><c>missing_value</c></item>
</list>
- <p>The third component is a list or binary providing additional information about the
+ <p>The third component is a term providing additional information about the
cause of the error.</p>
</desc>
</datatype>
diff --git a/lib/stdlib/src/uri_string.erl b/lib/stdlib/src/uri_string.erl
index cf8c388f54..2c73e38324 100644
--- a/lib/stdlib/src/uri_string.erl
+++ b/lib/stdlib/src/uri_string.erl
@@ -273,7 +273,7 @@
%% %x96 ` grave / accent
%%-------------------------------------------------------------------------
-type uri_string() :: iodata().
--type error() :: {error, atom(), list() | binary()}.
+-type error() :: {error, atom(), term()}.
%%-------------------------------------------------------------------------
@@ -298,10 +298,11 @@
normalize(URIString) ->
%% Case normalization and percent-encoding normalization are achieved
%% by running parse and recompose on the input URI string.
- M = parse(URIString),
- M1 = normalize_scheme_based(M),
- M2 = normalize_path_segment(M1),
- recompose(M2).
+ recompose(
+ normalize_path_segment(
+ normalize_scheme_based(
+ parse(URIString)))).
+
%%-------------------------------------------------------------------------
%% Parse URIs
@@ -311,8 +312,7 @@ normalize(URIString) ->
URIMap :: uri_map()
| error().
parse(URIString) when is_binary(URIString) ->
- try parse_uri_reference(URIString, #{}) of
- Result -> Result
+ try parse_uri_reference(URIString, #{})
catch
throw:{error, Atom, RestData} -> {error, Atom, RestData}
end;
@@ -321,8 +321,6 @@ parse(URIString) when is_list(URIString) ->
Binary = unicode:characters_to_binary(URIString),
Map = parse_uri_reference(Binary, #{}),
convert_mapfields_to_list(Map)
- of
- Result -> Result
catch
throw:{error, Atom, RestData} -> {error, Atom, RestData}
end.
@@ -348,8 +346,6 @@ recompose(Map) ->
T4 = update_path(Map, T3),
T5 = update_query(Map, T4),
update_fragment(Map, T5)
- of
- Result -> Result
catch
throw:{error, Atom, RestData} -> {error, Atom, RestData}
end
@@ -371,8 +367,6 @@ transcode(URIString, Options) when is_binary(URIString) ->
List = convert_list(URIString, InEnc),
Output = transcode(List, [], InEnc, OutEnc),
convert_binary(Output, utf8, OutEnc)
- of
- Result -> Result
catch
throw:{error, Atom, RestData} -> {error, Atom, RestData}
end;
@@ -380,8 +374,7 @@ transcode(URIString, Options) when is_list(URIString) ->
InEnc = proplists:get_value(in_encoding, Options, utf8),
OutEnc = proplists:get_value(out_encoding, Options, utf8),
Flattened = flatten_list(URIString, InEnc),
- try transcode(Flattened, [], InEnc, OutEnc) of
- Result -> Result
+ try transcode(Flattened, [], InEnc, OutEnc)
catch
throw:{error, Atom, RestData} -> {error, Atom, RestData}
end.
@@ -413,8 +406,7 @@ compose_query(List) ->
compose_query([],_Options) ->
[];
compose_query(List, Options) ->
- try compose_query(List, Options, false, <<>>) of
- Result -> Result
+ try compose_query(List, Options, false, <<>>)
catch
throw:{error, Atom, RestData} -> {error, Atom, RestData}
end.
@@ -423,8 +415,7 @@ compose_query([{Key,Value}|Rest], Options, IsList, Acc) ->
Separator = get_separator(Options, Rest),
K = form_urlencode(Key),
V = form_urlencode(Value),
- Flag = is_list(Key) orelse is_list(Value),
- IsListNew = IsList orelse Flag,
+ IsListNew = IsList orelse is_list(Key) orelse is_list(Value),
compose_query(Rest, Options, IsListNew, <<Acc/binary,K/binary,"=",V/binary,Separator/binary>>);
compose_query([], _Options, IsList, Acc) ->
case IsList of
@@ -448,14 +439,11 @@ dissect_query(QueryString) when is_list(QueryString) ->
try
B = convert_binary(QueryString, utf8, utf8),
dissect_query_key(B, true, [], <<>>, <<>>)
- of
- Result -> Result
catch
throw:{error, Atom, RestData} -> {error, Atom, RestData}
end;
dissect_query(QueryString) ->
- try dissect_query_key(QueryString, false, [], <<>>, <<>>) of
- Result -> Result
+ try dissect_query_key(QueryString, false, [], <<>>, <<>>)
catch
throw:{error, Atom, RestData} -> {error, Atom, RestData}
end.
@@ -485,8 +473,7 @@ convert_mapfields_to_list(Map) ->
-spec parse_uri_reference(binary(), uri_map()) -> uri_map().
parse_uri_reference(<<>>, _) -> #{path => <<>>};
parse_uri_reference(URIString, URI) ->
- try parse_scheme_start(URIString, URI) of
- Res -> Res
+ try parse_scheme_start(URIString, URI)
catch
throw:{_,_,_} ->
parse_relative_part(URIString, URI)
@@ -1177,9 +1164,7 @@ calculate_parsed_query_fragment(Input, Unparsed) ->
get_port(<<>>) ->
undefined;
get_port(B) ->
- try binary_to_integer(B) of
- Port ->
- Port
+ try binary_to_integer(B)
catch
error:badarg ->
throw({error, invalid_uri, B})
@@ -1480,60 +1465,65 @@ bracket_ipv6(Addr) when is_list(Addr) ->
%%-------------------------------------------------------------------------
%% Checks if input Map has valid combination of fields that can be
%% recomposed into a URI.
-%% It filters out the following combinations from the set of all possible
-%% values:
-%% - <no-userinfo> <no-host> port
-%% E.g. ":8080" - invalid URI
-%% - userinfo <no-host> <no-port>
-%% E.g. "//user@" - invalid URI
-%% - userinfo <no-host> port
-%% E.g. "//user@:8080" => #{host => [],port => 8080,userinfo => "user"}
-%% There is always at least an empty host when both userinfo and port
-%% are present.
-%% - #{path => "///"} otherwise the following would be true:
-%% "/////" = uri_string:recompose(#{host => "", path => "///"})
-%% "/////" = uri_string:recompose(#{path => "/////"})
-%% AND
-%% path-absolute = "/" [ segment-nz *( "/" segment ) ]
-%%-------------------------------------------------------------------------
-is_valid_map(Map) ->
- case
- ((not maps:is_key(userinfo, Map) andalso
- not maps:is_key(host, Map) andalso
- maps:is_key(port, Map))
- orelse
- (maps:is_key(userinfo, Map) andalso
- not maps:is_key(host, Map) andalso
- not maps:is_key(port, Map))
- orelse
- (maps:is_key(userinfo, Map) andalso
- not maps:is_key(host, Map) andalso
- maps:is_key(port, Map))) orelse
- not maps:is_key(path, Map) orelse
- not is_host_and_path_valid(Map) orelse
- invalid_field_present(Map)
- of
+%%
+%% The implementation is based on a decision tree that fulfills the
+%% following rules:
+%% - 'path' shall always be present in the input map
+%% URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+%% hier-part = "//" authority path-abempty
+%% / path-absolute
+%% / path-rootless
+%% / path-empty
+%% - 'host' shall be present in the input map when 'path' starts with
+%% two slashes ("//")
+%% path = path-abempty ; begins with "/" or is empty
+%% / path-absolute ; begins with "/" but not "//"
+%% / path-noscheme ; begins with a non-colon segment
+%% / path-rootless ; begins with a segment
+%% / path-empty ; zero characters
+%% path-abempty = *( "/" segment )
+%% segment = *pchar
+%% - 'host' shall be present if userinfo or port is present in input map
+%% authority = [ userinfo "@" ] host [ ":" port ]
+%% - All fields shall be valid (scheme, userinfo, host, port, path, query
+%% or fragment).
+%%-------------------------------------------------------------------------
+is_valid_map(#{path := Path} = Map) ->
+ case starts_with_two_slash(Path) of
true ->
- false;
+ is_valid_map_host(Map);
false ->
- true
- end.
+ case maps:is_key(userinfo, Map) of
+ true ->
+ is_valid_map_host(Map);
+ false ->
+ case maps:is_key(port, Map) of
+ true ->
+ is_valid_map_host(Map);
+ false ->
+ all_fields_valid(Map)
+ end
+ end
+ end;
+is_valid_map(#{}) ->
+ false.
-invalid_field_present(Map) ->
- Fun = fun(K, _, AccIn) -> AccIn orelse
- ((K =/= scheme) andalso (K =/= userinfo)
- andalso (K =/= host) andalso (K =/= port)
- andalso (K =/= path) andalso (K =/= query)
- andalso (K =/= fragment))
- end,
- maps:fold(Fun, false, Map).
+is_valid_map_host(Map) ->
+ maps:is_key(host, Map) andalso all_fields_valid(Map).
-is_host_and_path_valid(Map) ->
- Host = maps:get(host, Map, undefined),
- Path = maps:get(path, Map, undefined),
- not (Host =:= undefined andalso starts_with_two_slash(Path)).
+all_fields_valid(Map) ->
+ Fun = fun(scheme, _, Acc) -> Acc;
+ (userinfo, _, Acc) -> Acc;
+ (host, _, Acc) -> Acc;
+ (port, _, Acc) -> Acc;
+ (path, _, Acc) -> Acc;
+ (query, _, Acc) -> Acc;
+ (fragment, _, Acc) -> Acc;
+ (_, _, _) -> false
+ end,
+ maps:fold(Fun, true, Map).
starts_with_two_slash([$/,$/|_]) ->