|
|
@@ -42,7 +42,12 @@
|
|
|
-type ip_port() :: tuple() | integer().
|
|
|
-type cipher() :: map().
|
|
|
-type port_number() :: 1..65536.
|
|
|
--type server_parse_option() :: #{default_port => port_number(), no_port => boolean()}.
|
|
|
+-type server_parse_option() :: #{
|
|
|
+ default_port => port_number(),
|
|
|
+ no_port => boolean(),
|
|
|
+ supported_schemes => [string()],
|
|
|
+ default_scheme => string()
|
|
|
+}.
|
|
|
-type url() :: binary().
|
|
|
-type json_binary() :: binary().
|
|
|
|
|
|
@@ -2896,7 +2901,10 @@ servers_validator(Opts, Required) ->
|
|
|
%% `no_port': by default it's `false', when set to `true',
|
|
|
%% a `throw' exception is raised if the port is found.
|
|
|
-spec parse_server(undefined | string() | binary(), server_parse_option()) ->
|
|
|
- {string(), port_number()}.
|
|
|
+ string()
|
|
|
+ | {string(), port_number()}
|
|
|
+ | {string(), string()}
|
|
|
+ | {string(), string(), port_number()}.
|
|
|
parse_server(Str, Opts) ->
|
|
|
case parse_servers(Str, Opts) of
|
|
|
undefined ->
|
|
|
@@ -2910,7 +2918,12 @@ parse_server(Str, Opts) ->
|
|
|
%% @doc Parse comma separated `host[:port][,host[:port]]' endpoints
|
|
|
%% into a list of `{Host, Port}' tuples or just `Host' string.
|
|
|
-spec parse_servers(undefined | string() | binary(), server_parse_option()) ->
|
|
|
- [{string(), port_number()}].
|
|
|
+ [
|
|
|
+ string()
|
|
|
+ | {string(), port_number()}
|
|
|
+ | {string(), string()}
|
|
|
+ | {string(), string(), port_number()}
|
|
|
+ ].
|
|
|
parse_servers(undefined, _Opts) ->
|
|
|
%% should not parse 'undefined' as string,
|
|
|
%% not to throw exception either,
|
|
|
@@ -2956,6 +2969,9 @@ split_host_port(Str) ->
|
|
|
do_parse_server(Str, Opts) ->
|
|
|
DefaultPort = maps:get(default_port, Opts, undefined),
|
|
|
NotExpectingPort = maps:get(no_port, Opts, false),
|
|
|
+ DefaultScheme = maps:get(default_scheme, Opts, undefined),
|
|
|
+ SupportedSchemes = maps:get(supported_schemes, Opts, []),
|
|
|
+ NotExpectingScheme = (not is_list(DefaultScheme)) andalso length(SupportedSchemes) =:= 0,
|
|
|
case is_integer(DefaultPort) andalso NotExpectingPort of
|
|
|
true ->
|
|
|
%% either provide a default port from schema,
|
|
|
@@ -2964,24 +2980,74 @@ do_parse_server(Str, Opts) ->
|
|
|
false ->
|
|
|
ok
|
|
|
end,
|
|
|
+ case is_list(DefaultScheme) andalso (not lists:member(DefaultScheme, SupportedSchemes)) of
|
|
|
+ true ->
|
|
|
+ %% inconsistent schema
|
|
|
+ error("bad_schema");
|
|
|
+ false ->
|
|
|
+ ok
|
|
|
+ end,
|
|
|
%% do not split with space, there should be no space allowed between host and port
|
|
|
case string:tokens(Str, ":") of
|
|
|
- [Hostname, Port] ->
|
|
|
+ [Scheme, "//" ++ Hostname, Port] ->
|
|
|
NotExpectingPort andalso throw("not_expecting_port_number"),
|
|
|
- {check_hostname(Hostname), parse_port(Port)};
|
|
|
- [Hostname] ->
|
|
|
+ NotExpectingScheme andalso throw("not_expecting_scheme"),
|
|
|
+ {check_scheme(Scheme, Opts), check_hostname(Hostname), parse_port(Port)};
|
|
|
+ [Scheme, "//" ++ Hostname] ->
|
|
|
+ NotExpectingScheme andalso throw("not_expecting_scheme"),
|
|
|
case is_integer(DefaultPort) of
|
|
|
true ->
|
|
|
- {check_hostname(Hostname), DefaultPort};
|
|
|
+ {check_scheme(Scheme, Opts), check_hostname(Hostname), DefaultPort};
|
|
|
false when NotExpectingPort ->
|
|
|
- check_hostname(Hostname);
|
|
|
+ {check_scheme(Scheme, Opts), check_hostname(Hostname)};
|
|
|
false ->
|
|
|
throw("missing_port_number")
|
|
|
end;
|
|
|
+ [Hostname, Port] ->
|
|
|
+ NotExpectingPort andalso throw("not_expecting_port_number"),
|
|
|
+ case is_list(DefaultScheme) of
|
|
|
+ false ->
|
|
|
+ {check_hostname(Hostname), parse_port(Port)};
|
|
|
+ true ->
|
|
|
+ {DefaultScheme, check_hostname(Hostname), parse_port(Port)}
|
|
|
+ end;
|
|
|
+ [Hostname] ->
|
|
|
+ case is_integer(DefaultPort) orelse NotExpectingPort of
|
|
|
+ true ->
|
|
|
+ ok;
|
|
|
+ false ->
|
|
|
+ throw("missing_port_number")
|
|
|
+ end,
|
|
|
+ case is_list(DefaultScheme) orelse NotExpectingScheme of
|
|
|
+ true ->
|
|
|
+ ok;
|
|
|
+ false ->
|
|
|
+ throw("missing_scheme")
|
|
|
+ end,
|
|
|
+ case {is_integer(DefaultPort), is_list(DefaultScheme)} of
|
|
|
+ {true, true} ->
|
|
|
+ {DefaultScheme, check_hostname(Hostname), DefaultPort};
|
|
|
+ {true, false} ->
|
|
|
+ {check_hostname(Hostname), DefaultPort};
|
|
|
+ {false, true} ->
|
|
|
+ {DefaultScheme, check_hostname(Hostname)};
|
|
|
+ {false, false} ->
|
|
|
+ check_hostname(Hostname)
|
|
|
+ end;
|
|
|
_ ->
|
|
|
throw("bad_host_port")
|
|
|
end.
|
|
|
|
|
|
+check_scheme(Str, Opts) ->
|
|
|
+ SupportedSchemes = maps:get(supported_schemes, Opts, []),
|
|
|
+ IsSupported = lists:member(Str, SupportedSchemes),
|
|
|
+ case IsSupported of
|
|
|
+ true ->
|
|
|
+ Str;
|
|
|
+ false ->
|
|
|
+ throw("unsupported_scheme")
|
|
|
+ end.
|
|
|
+
|
|
|
check_hostname(Str) ->
|
|
|
%% not intended to use inet_parse:domain here
|
|
|
%% only checking space because it interferes the parsing
|