summaryrefslogtreecommitdiff
path: root/deps/amqp_client/src/uri_parser.erl
diff options
context:
space:
mode:
Diffstat (limited to 'deps/amqp_client/src/uri_parser.erl')
-rw-r--r--deps/amqp_client/src/uri_parser.erl125
1 files changed, 125 insertions, 0 deletions
diff --git a/deps/amqp_client/src/uri_parser.erl b/deps/amqp_client/src/uri_parser.erl
new file mode 100644
index 0000000000..a2bb98dad7
--- /dev/null
+++ b/deps/amqp_client/src/uri_parser.erl
@@ -0,0 +1,125 @@
+%% This file is a copy of http_uri.erl from the R13B-1 Erlang/OTP
+%% distribution with several modifications.
+
+%% All modifications are Copyright (c) 2009-2020 VMware, Inc. or its affiliates.
+
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at https://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+%% AB. All Rights Reserved.''
+
+%% See https://tools.ietf.org/html/rfc3986
+
+-module(uri_parser).
+
+-export([parse/2]).
+
+%%%=========================================================================
+%%% API
+%%%=========================================================================
+
+%% Returns a key list of elements extracted from the URI. Note that
+%% only 'scheme' is guaranteed to exist. Key-Value pairs from the
+%% Defaults list will be used absence of a non-empty value extracted
+%% from the URI. The values extracted are strings, except for 'port'
+%% which is an integer, 'userinfo' which is a list of strings (split
+%% on $:), and 'query' which is a list of strings where no $= char
+%% found, or a {key,value} pair where a $= char is found (initial
+%% split on $& and subsequent optional split on $=). Possible keys
+%% are: 'scheme', 'userinfo', 'host', 'port', 'path', 'query',
+%% 'fragment'.
+
+-spec parse(AbsURI, Defaults :: list())
+ -> [{atom(), string()}] | {error, no_scheme | {malformed_uri, AbsURI, any()}}
+ when AbsURI :: string() | binary().
+parse(AbsURI, Defaults) ->
+ AbsUriString = rabbit_data_coercion:to_list(AbsURI),
+ case parse_scheme(AbsUriString) of
+ {error, Reason} ->
+ {error, Reason};
+ {Scheme, Rest} ->
+ case (catch parse_uri_rest(Rest, true)) of
+ [_|_] = List ->
+ merge_keylists([{scheme, Scheme} | List], Defaults);
+ E ->
+ {error, {malformed_uri, AbsURI, E}}
+ end
+ end.
+
+%%%========================================================================
+%%% Internal functions
+%%%========================================================================
+parse_scheme(AbsURI) ->
+ split_uri(AbsURI, ":", {error, no_scheme}).
+
+parse_uri_rest("//" ++ URIPart, true) ->
+ %% we have an authority
+ {Authority, PathQueryFrag} =
+ split_uri(URIPart, "/|\\?|#", {URIPart, ""}, 1, 0),
+ AuthorityParts = parse_authority(Authority),
+ parse_uri_rest(PathQueryFrag, false) ++ AuthorityParts;
+parse_uri_rest(PathQueryFrag, _Bool) ->
+ %% no authority, just a path and maybe query
+ {PathQuery, Frag} = split_uri(PathQueryFrag, "#", {PathQueryFrag, ""}),
+ {Path, QueryString} = split_uri(PathQuery, "\\?", {PathQuery, ""}),
+ QueryPropList = split_query(QueryString),
+ [{path, Path}, {'query', QueryPropList}, {fragment, Frag}].
+
+parse_authority(Authority) ->
+ {UserInfo, HostPort} = split_uri(Authority, "@", {"", Authority}),
+ UserInfoSplit = case re:split(UserInfo, ":", [{return, list}]) of
+ [""] -> [];
+ UIS -> UIS
+ end,
+ [{userinfo, UserInfoSplit} | parse_host_port(HostPort)].
+
+parse_host_port("[" ++ HostPort) -> %ipv6
+ {Host, ColonPort} = split_uri(HostPort, "\\]", {HostPort, ""}),
+ [{host, Host} | case split_uri(ColonPort, ":", not_found, 0, 1) of
+ not_found -> case ColonPort of
+ [] -> [];
+ _ -> throw({invalid_port, ColonPort})
+ end;
+ {_, Port} -> [{port, list_to_integer(Port)}]
+ end];
+
+parse_host_port(HostPort) ->
+ {Host, Port} = split_uri(HostPort, ":", {HostPort, not_found}),
+ [{host, Host} | case Port of
+ not_found -> [];
+ _ -> [{port, list_to_integer(Port)}]
+ end].
+
+split_query(Query) ->
+ case re:split(Query, "&", [{return, list}]) of
+ [""] -> [];
+ QParams -> [split_uri(Param, "=", Param) || Param <- QParams]
+ end.
+
+split_uri(UriPart, SplitChar, NoMatchResult) ->
+ split_uri(UriPart, SplitChar, NoMatchResult, 1, 1).
+
+split_uri(UriPart, SplitChar, NoMatchResult, SkipLeft, SkipRight) ->
+ case re:run(UriPart, SplitChar) of
+ {match, [{Match, _}]} ->
+ {string:substr(UriPart, 1, Match + 1 - SkipLeft),
+ string:substr(UriPart, Match + 1 + SkipRight, length(UriPart))};
+ nomatch ->
+ NoMatchResult
+ end.
+
+merge_keylists(A, B) ->
+ {AEmpty, ANonEmpty} = lists:partition(fun ({_Key, V}) -> V =:= [] end, A),
+ [AEmptyS, ANonEmptyS, BS] =
+ [lists:ukeysort(1, X) || X <- [AEmpty, ANonEmpty, B]],
+ lists:ukeymerge(1, lists:ukeymerge(1, ANonEmptyS, BS), AEmptyS).