feat(schema): add support for schemes in server parser/validator
This commit is contained in:
parent
4bcfbea056
commit
dc48032309
|
@ -42,7 +42,12 @@
|
||||||
-type ip_port() :: tuple() | integer().
|
-type ip_port() :: tuple() | integer().
|
||||||
-type cipher() :: map().
|
-type cipher() :: map().
|
||||||
-type port_number() :: 1..65536.
|
-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 url() :: binary().
|
||||||
-type json_binary() :: binary().
|
-type json_binary() :: binary().
|
||||||
|
|
||||||
|
@ -2896,7 +2901,10 @@ servers_validator(Opts, Required) ->
|
||||||
%% `no_port': by default it's `false', when set to `true',
|
%% `no_port': by default it's `false', when set to `true',
|
||||||
%% a `throw' exception is raised if the port is found.
|
%% a `throw' exception is raised if the port is found.
|
||||||
-spec parse_server(undefined | string() | binary(), server_parse_option()) ->
|
-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) ->
|
parse_server(Str, Opts) ->
|
||||||
case parse_servers(Str, Opts) of
|
case parse_servers(Str, Opts) of
|
||||||
undefined ->
|
undefined ->
|
||||||
|
@ -2910,7 +2918,12 @@ parse_server(Str, Opts) ->
|
||||||
%% @doc Parse comma separated `host[:port][,host[:port]]' endpoints
|
%% @doc Parse comma separated `host[:port][,host[:port]]' endpoints
|
||||||
%% into a list of `{Host, Port}' tuples or just `Host' string.
|
%% into a list of `{Host, Port}' tuples or just `Host' string.
|
||||||
-spec parse_servers(undefined | string() | binary(), server_parse_option()) ->
|
-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) ->
|
parse_servers(undefined, _Opts) ->
|
||||||
%% should not parse 'undefined' as string,
|
%% should not parse 'undefined' as string,
|
||||||
%% not to throw exception either,
|
%% not to throw exception either,
|
||||||
|
@ -2956,6 +2969,9 @@ split_host_port(Str) ->
|
||||||
do_parse_server(Str, Opts) ->
|
do_parse_server(Str, Opts) ->
|
||||||
DefaultPort = maps:get(default_port, Opts, undefined),
|
DefaultPort = maps:get(default_port, Opts, undefined),
|
||||||
NotExpectingPort = maps:get(no_port, Opts, false),
|
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
|
case is_integer(DefaultPort) andalso NotExpectingPort of
|
||||||
true ->
|
true ->
|
||||||
%% either provide a default port from schema,
|
%% either provide a default port from schema,
|
||||||
|
@ -2964,24 +2980,74 @@ do_parse_server(Str, Opts) ->
|
||||||
false ->
|
false ->
|
||||||
ok
|
ok
|
||||||
end,
|
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
|
%% do not split with space, there should be no space allowed between host and port
|
||||||
case string:tokens(Str, ":") of
|
case string:tokens(Str, ":") of
|
||||||
[Hostname, Port] ->
|
[Scheme, "//" ++ Hostname, Port] ->
|
||||||
NotExpectingPort andalso throw("not_expecting_port_number"),
|
NotExpectingPort andalso throw("not_expecting_port_number"),
|
||||||
{check_hostname(Hostname), parse_port(Port)};
|
NotExpectingScheme andalso throw("not_expecting_scheme"),
|
||||||
[Hostname] ->
|
{check_scheme(Scheme, Opts), check_hostname(Hostname), parse_port(Port)};
|
||||||
|
[Scheme, "//" ++ Hostname] ->
|
||||||
|
NotExpectingScheme andalso throw("not_expecting_scheme"),
|
||||||
case is_integer(DefaultPort) of
|
case is_integer(DefaultPort) of
|
||||||
true ->
|
true ->
|
||||||
{check_hostname(Hostname), DefaultPort};
|
{check_scheme(Scheme, Opts), check_hostname(Hostname), DefaultPort};
|
||||||
false when NotExpectingPort ->
|
false when NotExpectingPort ->
|
||||||
check_hostname(Hostname);
|
{check_scheme(Scheme, Opts), check_hostname(Hostname)};
|
||||||
false ->
|
false ->
|
||||||
throw("missing_port_number")
|
throw("missing_port_number")
|
||||||
end;
|
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")
|
throw("bad_host_port")
|
||||||
end.
|
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) ->
|
check_hostname(Str) ->
|
||||||
%% not intended to use inet_parse:domain here
|
%% not intended to use inet_parse:domain here
|
||||||
%% only checking space because it interferes the parsing
|
%% only checking space because it interferes the parsing
|
||||||
|
|
|
@ -350,7 +350,7 @@ parse_server_test_() ->
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
?T(
|
?T(
|
||||||
"multiple servers wihtout port, mixed list(binary|string)",
|
"multiple servers without port, mixed list(binary|string)",
|
||||||
?assertEqual(
|
?assertEqual(
|
||||||
["host1", "host2"],
|
["host1", "host2"],
|
||||||
Parse2([<<"host1">>, "host2"], #{no_port => true})
|
Parse2([<<"host1">>, "host2"], #{no_port => true})
|
||||||
|
@ -447,6 +447,171 @@ parse_server_test_() ->
|
||||||
"bad_schema",
|
"bad_schema",
|
||||||
emqx_schema:parse_server("whatever", #{default_port => 10, no_port => true})
|
emqx_schema:parse_server("whatever", #{default_port => 10, no_port => true})
|
||||||
)
|
)
|
||||||
|
),
|
||||||
|
?T(
|
||||||
|
"scheme, hostname and port",
|
||||||
|
?assertEqual(
|
||||||
|
{"pulsar+ssl", "host", 6651},
|
||||||
|
emqx_schema:parse_server(
|
||||||
|
"pulsar+ssl://host:6651",
|
||||||
|
#{
|
||||||
|
default_port => 6650,
|
||||||
|
supported_schemes => ["pulsar", "pulsar+ssl"]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
?T(
|
||||||
|
"scheme and hostname, default port",
|
||||||
|
?assertEqual(
|
||||||
|
{"pulsar", "host", 6650},
|
||||||
|
emqx_schema:parse_server(
|
||||||
|
"pulsar://host",
|
||||||
|
#{
|
||||||
|
default_port => 6650,
|
||||||
|
supported_schemes => ["pulsar", "pulsar+ssl"]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
?T(
|
||||||
|
"scheme and hostname, no port",
|
||||||
|
?assertEqual(
|
||||||
|
{"pulsar", "host"},
|
||||||
|
emqx_schema:parse_server(
|
||||||
|
"pulsar://host",
|
||||||
|
#{
|
||||||
|
no_port => true,
|
||||||
|
supported_schemes => ["pulsar", "pulsar+ssl"]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
?T(
|
||||||
|
"scheme and hostname, missing port",
|
||||||
|
?assertThrow(
|
||||||
|
"missing_port_number",
|
||||||
|
emqx_schema:parse_server(
|
||||||
|
"pulsar://host",
|
||||||
|
#{
|
||||||
|
no_port => false,
|
||||||
|
supported_schemes => ["pulsar", "pulsar+ssl"]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
?T(
|
||||||
|
"hostname, default scheme, no default port",
|
||||||
|
?assertEqual(
|
||||||
|
{"pulsar", "host"},
|
||||||
|
emqx_schema:parse_server(
|
||||||
|
"host",
|
||||||
|
#{
|
||||||
|
default_scheme => "pulsar",
|
||||||
|
no_port => true,
|
||||||
|
supported_schemes => ["pulsar", "pulsar+ssl"]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
?T(
|
||||||
|
"hostname, default scheme, default port",
|
||||||
|
?assertEqual(
|
||||||
|
{"pulsar", "host", 6650},
|
||||||
|
emqx_schema:parse_server(
|
||||||
|
"host",
|
||||||
|
#{
|
||||||
|
default_port => 6650,
|
||||||
|
default_scheme => "pulsar",
|
||||||
|
supported_schemes => ["pulsar", "pulsar+ssl"]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
?T(
|
||||||
|
"just hostname, expecting missing scheme",
|
||||||
|
?assertThrow(
|
||||||
|
"missing_scheme",
|
||||||
|
emqx_schema:parse_server(
|
||||||
|
"host",
|
||||||
|
#{
|
||||||
|
no_port => true,
|
||||||
|
supported_schemes => ["pulsar", "pulsar+ssl"]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
?T(
|
||||||
|
"hostname, default scheme, defined port",
|
||||||
|
?assertEqual(
|
||||||
|
{"pulsar", "host", 6651},
|
||||||
|
emqx_schema:parse_server(
|
||||||
|
"host:6651",
|
||||||
|
#{
|
||||||
|
default_port => 6650,
|
||||||
|
default_scheme => "pulsar",
|
||||||
|
supported_schemes => ["pulsar", "pulsar+ssl"]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
?T(
|
||||||
|
"inconsistent scheme opts",
|
||||||
|
?assertError(
|
||||||
|
"bad_schema",
|
||||||
|
emqx_schema:parse_server(
|
||||||
|
"pulsar+ssl://host:6651",
|
||||||
|
#{
|
||||||
|
default_port => 6650,
|
||||||
|
default_scheme => "something",
|
||||||
|
supported_schemes => ["not", "supported"]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
?T(
|
||||||
|
"hostname, default scheme, defined port",
|
||||||
|
?assertEqual(
|
||||||
|
{"pulsar", "host", 6651},
|
||||||
|
emqx_schema:parse_server(
|
||||||
|
"host:6651",
|
||||||
|
#{
|
||||||
|
default_port => 6650,
|
||||||
|
default_scheme => "pulsar",
|
||||||
|
supported_schemes => ["pulsar", "pulsar+ssl"]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
?T(
|
||||||
|
"unsupported scheme",
|
||||||
|
?assertThrow(
|
||||||
|
"unsupported_scheme",
|
||||||
|
emqx_schema:parse_server(
|
||||||
|
"pulsar+quic://host:6651",
|
||||||
|
#{
|
||||||
|
default_port => 6650,
|
||||||
|
supported_schemes => ["pulsar"]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
?T(
|
||||||
|
"multiple hostnames with schemes (1)",
|
||||||
|
?assertEqual(
|
||||||
|
[
|
||||||
|
{"pulsar", "host", 6649},
|
||||||
|
{"pulsar+ssl", "other.host", 6651},
|
||||||
|
{"pulsar", "yet.another", 6650}
|
||||||
|
],
|
||||||
|
emqx_schema:parse_servers(
|
||||||
|
"pulsar://host:6649, pulsar+ssl://other.host:6651,pulsar://yet.another",
|
||||||
|
#{
|
||||||
|
default_port => 6650,
|
||||||
|
supported_schemes => ["pulsar", "pulsar+ssl"]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
].
|
].
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue