mirror of
https://github.com/valitydev/woody_erlang.git
synced 2024-11-06 02:15:19 +00:00
Fixup TLS client options after resolving (#24)
This commit is contained in:
parent
2866b658ea
commit
aa8f9d0cd2
@ -124,7 +124,7 @@ send(Url, Body, Options, ResOpts, WoodyState) ->
|
||||
% MSPF-416: We resolve url host to an ip here to prevent
|
||||
% reusing keep-alive connections to dead hosts
|
||||
case woody_resolver:resolve_url(Url, WoodyState, ResOpts) of
|
||||
{ok, {OldUrl, NewUrl}} ->
|
||||
{ok, {OldUrl, NewUrl}, _ConnectOpts} ->
|
||||
Headers = add_host_header(OldUrl, make_woody_headers(Context)),
|
||||
Options1 = set_defaults(Options),
|
||||
Options2 = set_timeouts(Options1, Context),
|
||||
|
@ -154,11 +154,16 @@ send_call(Buffer, #{url := Url} = Opts, WoodyState) ->
|
||||
% MSPF-416: We resolve url host to an ip here to prevent
|
||||
% reusing keep-alive connections to dead hosts
|
||||
case woody_resolver:resolve_url(Url, WoodyState, ResolverOpts) of
|
||||
{ok, {OldUrl, NewUrl}} ->
|
||||
{ok, {OldUrl, NewUrl}, ConnectOpts} ->
|
||||
Headers = add_host_header(OldUrl, make_woody_headers(Context)),
|
||||
TransportOpts1 = set_defaults(TransportOpts),
|
||||
TransportOpts2 = set_timeouts(TransportOpts1, Context),
|
||||
Result = hackney:request(post, NewUrl, Headers, Buffer, maps:to_list(TransportOpts2)),
|
||||
% NOTE
|
||||
% This is to ensure hackney won't try to resolve original hostname again in
|
||||
% `set_tls_overrides/2`.
|
||||
TransportOpts3 = append_connect_opts(TransportOpts2, ConnectOpts),
|
||||
TransportOpts4 = set_tls_overrides(TransportOpts3, OldUrl),
|
||||
Result = hackney:request(post, NewUrl, Headers, Buffer, maps:to_list(TransportOpts4)),
|
||||
handle_response(Result, WoodyState);
|
||||
{error, Reason} ->
|
||||
Error = {error, {resolve_failed, Reason}},
|
||||
@ -203,6 +208,19 @@ calc_timeouts(Timeout) ->
|
||||
T
|
||||
end.
|
||||
|
||||
append_connect_opts(Options, ConnectOpts) ->
|
||||
Options#{connect_options => maps:get(connect_options, Options, []) ++ ConnectOpts}.
|
||||
|
||||
set_tls_overrides(Options = #{ssl_options := _}, _OrigUrl) ->
|
||||
Options;
|
||||
set_tls_overrides(Options, #hackney_url{scheme = https, host = OrigHost}) ->
|
||||
% NOTE
|
||||
% Beware, we're abusing implementation details here.
|
||||
SslOpts = hackney_connection:connect_options(hackney_ssl, OrigHost, maps:to_list(Options)),
|
||||
Options#{ssl_options => SslOpts};
|
||||
set_tls_overrides(Options, #hackney_url{scheme = _}) ->
|
||||
Options.
|
||||
|
||||
-spec make_woody_headers(woody_context:ctx()) -> http_headers().
|
||||
make_woody_headers(Context) ->
|
||||
add_optional_headers(Context, [
|
||||
|
@ -36,13 +36,13 @@
|
||||
%%
|
||||
|
||||
-spec resolve_url(url(), woody_state:st()) ->
|
||||
{ok, resolve_result()}
|
||||
{ok, resolve_result(), [gen_tcp:connect_option()]}
|
||||
| {error, resolve_error()}.
|
||||
resolve_url(Url, WoodyState) ->
|
||||
resolve_url(Url, WoodyState, #{}).
|
||||
|
||||
-spec resolve_url(url(), woody_state:st(), options()) ->
|
||||
{ok, resolve_result()}
|
||||
{ok, resolve_result(), [gen_tcp:connect_option()]}
|
||||
| {error, resolve_error()}.
|
||||
resolve_url(Url, WoodyState, Opts) when is_list(Url) ->
|
||||
resolve_url(unicode:characters_to_binary(Url), WoodyState, Opts);
|
||||
@ -61,21 +61,28 @@ parse_url(Url) ->
|
||||
resolve_parsed_url(ParsedUrl = #hackney_url{}, WoodyState, Opts) ->
|
||||
case inet:parse_address(ParsedUrl#hackney_url.host) of
|
||||
% url host is already an ip, move on
|
||||
{ok, _} -> {ok, {ParsedUrl, ParsedUrl}};
|
||||
{error, _} -> do_resolve_url(ParsedUrl, WoodyState, Opts)
|
||||
{ok, IpAddr} ->
|
||||
IpFamily =
|
||||
case tuple_size(IpAddr) of
|
||||
4 -> inet;
|
||||
8 -> inet6
|
||||
end,
|
||||
{ok, {ParsedUrl, ParsedUrl}, [IpFamily]};
|
||||
{error, _} ->
|
||||
do_resolve_url(ParsedUrl, WoodyState, Opts)
|
||||
end.
|
||||
|
||||
do_resolve_url(ParsedUrl, WoodyState, Opts) ->
|
||||
UnresolvedHost = ParsedUrl#hackney_url.host,
|
||||
_ = log_event(?EV_CLIENT_RESOLVE_BEGIN, WoodyState, #{host => UnresolvedHost}),
|
||||
case lookup_host(UnresolvedHost, Opts) of
|
||||
{ok, {IpAddr, _} = AddrInfo} ->
|
||||
{ok, {IpAddr, IpFamily} = AddrInfo} ->
|
||||
_ = log_event(?EV_CLIENT_RESOLVE_RESULT, WoodyState, #{
|
||||
status => ok,
|
||||
host => UnresolvedHost,
|
||||
address => inet:ntoa(IpAddr)
|
||||
}),
|
||||
{ok, {ParsedUrl, replace_host(ParsedUrl, AddrInfo)}};
|
||||
{ok, {ParsedUrl, replace_host(ParsedUrl, AddrInfo)}, [IpFamily]};
|
||||
{error, Reason} ->
|
||||
_ = log_event(?EV_CLIENT_RESOLVE_RESULT, WoodyState, #{
|
||||
status => error,
|
||||
|
@ -23,7 +23,8 @@
|
||||
-export([
|
||||
client_wo_cert_test/1,
|
||||
valid_client_cert_test/1,
|
||||
invalid_client_cert_test/1
|
||||
invalid_client_cert_test/1,
|
||||
valid_cert_external_server/1
|
||||
]).
|
||||
|
||||
%% woody_server_thrift_handler callback
|
||||
@ -58,7 +59,8 @@ all() ->
|
||||
[
|
||||
{group, 'tlsv1.3'},
|
||||
{group, 'tlsv1.2'},
|
||||
{group, 'tlsv1.1'}
|
||||
{group, 'tlsv1.1'},
|
||||
valid_cert_external_server
|
||||
].
|
||||
|
||||
-spec groups() -> [{group_name(), list(), [case_name()]}].
|
||||
@ -141,6 +143,30 @@ invalid_client_cert_test(C) ->
|
||||
{match, _} = re:run(Reason, <<"^{tls_alert,[\"\{]unknown[ _]ca.*$">>, [])
|
||||
end.
|
||||
|
||||
-spec valid_cert_external_server(config()) -> _.
|
||||
valid_cert_external_server(_C) ->
|
||||
% NOTE
|
||||
% This testcase needs internet connectivity.
|
||||
% This testcase relies on correct TLS setup and implementation on example.org servers.
|
||||
Url = <<"https://example.org/just-testing-tls-nevermind">>,
|
||||
Context = woody_context:new(to_binary(?FUNCTION_NAME)),
|
||||
Service = {?THRIFT_DEFS, 'Weapons'},
|
||||
Options = #{
|
||||
url => Url,
|
||||
event_handler => {woody_ct_event_h, {client, external}}
|
||||
},
|
||||
try
|
||||
_ = woody_client:call({Service, get_weapon, {<<"Example">>, <<>>}}, Options, Context),
|
||||
error(unreachable)
|
||||
catch
|
||||
error:{woody_error, {
|
||||
external,
|
||||
result_unexpected,
|
||||
<<"This server does not implement the woody protocol", _/binary>>
|
||||
}} ->
|
||||
ok
|
||||
end.
|
||||
|
||||
-spec client_ssl_opts(atom()) -> [ssl:tls_client_option()].
|
||||
client_ssl_opts('tlsv1.3') ->
|
||||
% NOTE
|
||||
|
@ -945,30 +945,30 @@ calls_with_cache(_) ->
|
||||
woody_resolver_inet(C) ->
|
||||
WoodyState = woody_state:new(client, woody_context:new(), ?MODULE),
|
||||
ok = inet_db:set_inet6(false),
|
||||
{ok, ?RESPONSE(http, <<"127.0.0.1">>, <<"127.0.0.1">>, <<"/test">>)} =
|
||||
{ok, ?RESPONSE(http, <<"127.0.0.1">>, <<"127.0.0.1">>, <<"/test">>), [inet]} =
|
||||
woody_resolver:resolve_url(<<"http://127.0.0.1/test">>, WoodyState),
|
||||
{ok, ?RESPONSE(http, <<"localhost">>, <<"127.0.0.1:80">>, <<"/test">>)} =
|
||||
{ok, ?RESPONSE(http, <<"localhost">>, <<"127.0.0.1:80">>, <<"/test">>), [inet]} =
|
||||
woody_resolver:resolve_url(<<"http://localhost/test">>, WoodyState),
|
||||
{ok, ?RESPONSE(http, <<"localhost">>, <<"127.0.0.1:80">>, <<"/test?q=a">>)} =
|
||||
{ok, ?RESPONSE(http, <<"localhost">>, <<"127.0.0.1:80">>, <<"/test?q=a">>), [inet]} =
|
||||
woody_resolver:resolve_url("http://localhost/test?q=a", WoodyState),
|
||||
{ok, ?RESPONSE(https, <<"localhost:8080">>, <<"127.0.0.1:8080">>, <<"/test">>)} =
|
||||
{ok, ?RESPONSE(https, <<"localhost:8080">>, <<"127.0.0.1:8080">>, <<"/test">>), [inet]} =
|
||||
woody_resolver:resolve_url(<<"https://localhost:8080/test">>, WoodyState),
|
||||
{ok, ?RESPONSE(https, <<"localhost">>, <<"127.0.0.1:443">>, <<>>)} =
|
||||
{ok, ?RESPONSE(https, <<"localhost">>, <<"127.0.0.1:443">>, <<>>), [inet]} =
|
||||
woody_resolver:resolve_url(<<"https://localhost">>, WoodyState),
|
||||
ok = inet_db:set_inet6(?config(env_inet6, C)).
|
||||
|
||||
woody_resolver_inet6(C) ->
|
||||
WoodyState = woody_state:new(client, woody_context:new(), ?MODULE),
|
||||
ok = inet_db:set_inet6(true),
|
||||
{ok, ?RESPONSE(http, <<"[::1]">>, <<"[::1]">>, <<"/test">>)} =
|
||||
{ok, ?RESPONSE(http, <<"[::1]">>, <<"[::1]">>, <<"/test">>), [inet6]} =
|
||||
woody_resolver:resolve_url(<<"http://[::1]/test">>, WoodyState),
|
||||
{ok, ?RESPONSE(http, <<"localhost">>, <<"[::1]:80">>, <<"/test">>)} =
|
||||
{ok, ?RESPONSE(http, <<"localhost">>, <<"[::1]:80">>, <<"/test">>), [inet6]} =
|
||||
woody_resolver:resolve_url(<<"http://localhost/test">>, WoodyState),
|
||||
{ok, ?RESPONSE(http, <<"localhost">>, <<"[::1]:80">>, <<"/test?q=a">>)} =
|
||||
{ok, ?RESPONSE(http, <<"localhost">>, <<"[::1]:80">>, <<"/test?q=a">>), [inet6]} =
|
||||
woody_resolver:resolve_url("http://localhost/test?q=a", WoodyState),
|
||||
{ok, ?RESPONSE(https, <<"localhost:8080">>, <<"[::1]:8080">>, <<"/test">>)} =
|
||||
{ok, ?RESPONSE(https, <<"localhost:8080">>, <<"[::1]:8080">>, <<"/test">>), [inet6]} =
|
||||
woody_resolver:resolve_url(<<"https://localhost:8080/test">>, WoodyState),
|
||||
{ok, ?RESPONSE(https, <<"localhost">>, <<"[::1]:443">>, <<>>)} =
|
||||
{ok, ?RESPONSE(https, <<"localhost">>, <<"[::1]:443">>, <<>>), [inet6]} =
|
||||
woody_resolver:resolve_url(<<"https://localhost">>, WoodyState),
|
||||
ok = inet_db:set_inet6(?config(env_inet6, C)).
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user