aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2019-07-26 14:25:59 +0200
committerLoïc Hoguin <[email protected]>2019-07-26 14:30:38 +0200
commit56b7fdd6eb15564ad821885937b03516a03dce4b (patch)
tree9fa4980d1eb59dbd038f1b4fdd1967be4ed420ba
parent00b0b29eacf3eb8a51273dc43064c6367573c4c4 (diff)
downloadgun-56b7fdd6eb15564ad821885937b03516a03dce4b.tar.gz
gun-56b7fdd6eb15564ad821885937b03516a03dce4b.tar.bz2
gun-56b7fdd6eb15564ad821885937b03516a03dce4b.zip
Add the transport_changed event
Also test protocol_changed over CONNECT.
-rw-r--r--src/gun.erl11
-rw-r--r--src/gun_default_event_h.erl12
-rw-r--r--src/gun_event.erl48
-rw-r--r--test/event_SUITE.erl123
4 files changed, 150 insertions, 44 deletions
diff --git a/src/gun.erl b/src/gun.erl
index ada6272..d158a53 100644
--- a/src/gun.erl
+++ b/src/gun.erl
@@ -1076,8 +1076,6 @@ commands([Error={error, _}|_], State) ->
disconnect(State, Error);
commands([{state, ProtoState}|Tail], State) ->
commands(Tail, State#state{protocol_state=ProtoState});
-%% @todo The scheme should probably not be ignored.
-%%
%% Order is important: the origin must be changed before
%% the transport and/or protocol in order to keep track
%% of the intermediaries properly.
@@ -1094,9 +1092,14 @@ commands([{origin, Scheme, Host, Port, Type}|Tail],
},
commands(Tail, State#state{origin_scheme=Scheme,
origin_host=Host, origin_port=Port, intermediaries=[Info|Intermediaries]});
-commands([{switch_transport, Transport, Socket}|Tail], State) ->
+commands([{switch_transport, Transport, Socket}|Tail], State=#state{
+ event_handler=EvHandler, event_handler_state=EvHandlerState0}) ->
+ EvHandlerState = EvHandler:transport_changed(#{
+ socket => Socket,
+ transport => Transport:name()
+ }, EvHandlerState0),
commands(Tail, active(State#state{socket=Socket, transport=Transport,
- messages=Transport:messages()}));
+ messages=Transport:messages(), event_handler_state=EvHandlerState}));
%% @todo The two loops should be reunified and this clause generalized.
commands([{switch_protocol, Protocol=gun_ws, ProtoState}], State=#state{
event_handler=EvHandler, event_handler_state=EvHandlerState0}) ->
diff --git a/src/gun_default_event_h.erl b/src/gun_default_event_h.erl
index 213db06..579fb20 100644
--- a/src/gun_default_event_h.erl
+++ b/src/gun_default_event_h.erl
@@ -33,12 +33,13 @@
-export([response_trailers/2]).
-export([response_end/2]).
-export([ws_upgrade/2]).
--export([protocol_changed/2]).
-export([ws_recv_frame_start/2]).
-export([ws_recv_frame_header/2]).
-export([ws_recv_frame_end/2]).
-export([ws_send_frame_start/2]).
-export([ws_send_frame_end/2]).
+-export([protocol_changed/2]).
+-export([transport_changed/2]).
-export([cancel/2]).
-export([disconnect/2]).
-export([terminate/2]).
@@ -97,9 +98,6 @@ response_end(_EventData, State) ->
ws_upgrade(_EventData, State) ->
State.
-protocol_changed(_EventData, State) ->
- State.
-
ws_recv_frame_start(_EventData, State) ->
State.
@@ -115,6 +113,12 @@ ws_send_frame_start(_EventData, State) ->
ws_send_frame_end(_EventData, State) ->
State.
+protocol_changed(_EventData, State) ->
+ State.
+
+transport_changed(_EventData, State) ->
+ State.
+
cancel(_EventData, State) ->
State.
diff --git a/src/gun_event.erl b/src/gun_event.erl
index 8a40518..2f12b4c 100644
--- a/src/gun_event.erl
+++ b/src/gun_event.erl
@@ -64,7 +64,7 @@
-type tls_handshake_event() :: #{
stream_ref => reference(),
reply_to => pid(),
- socket := inet:socket() | ssl:sslsocket(), %% The socket before/after will be different.
+ socket := inet:socket() | ssl:sslsocket() | pid(), %% The socket before/after will be different.
tls_opts := [ssl:connect_option()],
timeout := timeout(),
protocol => http | http2,
@@ -178,21 +178,6 @@
-callback ws_upgrade(ws_upgrade_event(), State) -> State.
-%% protocol_changed.
-%%
-%% This event can occur either following a successful ws_upgrade
-%% event or following a successful CONNECT request.
-%%
-%% @todo Currently there is only a connection-wide variant of this
-%% event. In the future there will be a stream-wide variant to
-%% support CONNECT and Websocket over HTTP/2.
-
--type protocol_changed_event() :: #{
- protocol := http2 | ws
-}.
-
--callback protocol_changed(protocol_changed_event(), State) -> State.
-
%% ws_recv_frame_start.
-type ws_recv_frame_start_event() :: #{
@@ -243,6 +228,36 @@
-callback ws_send_frame_start(ws_send_frame_event(), State) -> State.
-callback ws_send_frame_end(ws_send_frame_event(), State) -> State.
+%% protocol_changed.
+%%
+%% This event can occur either following a successful ws_upgrade
+%% event or following a successful CONNECT request.
+%%
+%% @todo Currently there is only a connection-wide variant of this
+%% event. In the future there will be a stream-wide variant to
+%% support CONNECT and Websocket over HTTP/2.
+
+-type protocol_changed_event() :: #{
+ protocol := http2 | ws
+}.
+
+-callback protocol_changed(protocol_changed_event(), State) -> State.
+
+%% transport_changed.
+%%
+%% This event can occur following a successful CONNECT request.
+%%
+%% @todo Currently there is only a connection-wide variant of this
+%% event. In the future there will be a stream-wide variant to
+%% support CONNECT through TLS proxies over HTTP/2.
+
+-type transport_changed_event() :: #{
+ socket := ssl:sslsocket() | pid(),
+ transport := tls | tls_proxy
+}.
+
+-callback transport_changed(transport_changed_event(), State) -> State.
+
%% cancel.
%%
%% In the case of HTTP/1.1 we cannot actually cancel the stream,
@@ -280,4 +295,3 @@
-callback terminate(terminate_event(), State) -> State.
%% @todo origin_changed
-%% @todo transport_changed
diff --git a/test/event_SUITE.erl b/test/event_SUITE.erl
index b1bfbcb..d593a59 100644
--- a/test/event_SUITE.erl
+++ b/test/event_SUITE.erl
@@ -38,7 +38,7 @@ groups() ->
WsTests = [T || T <- Tests, lists:sublist(atom_to_list(T), 3) =:= "ws_"],
[
{http, [parallel], Tests -- [cancel_remote|PushTests]},
- {http2, [parallel], (Tests -- [protocol_changed|WsTests]) -- HTTP1Tests}
+ {http2, [parallel], (Tests -- WsTests) -- HTTP1Tests}
].
init_per_suite(Config) ->
@@ -734,20 +734,6 @@ ws_upgrade_all_events(Config) ->
} = do_receive_event(protocol_changed),
gun:close(Pid).
-protocol_changed(Config) ->
- doc("Confirm that the protocol_changed event callback is called."),
- do_protocol_changed_ws(Config, ?FUNCTION_NAME).
- %% @todo do_protocol_changed_connect
-
-do_protocol_changed_ws(Config, EventName) ->
- {ok, Pid, _} = do_gun_open(Config),
- {ok, _} = gun:await_up(Pid),
- _ = gun:ws_upgrade(Pid, "/ws"),
- #{
- protocol := ws
- } = do_receive_event(EventName),
- gun:close(Pid).
-
ws_recv_frame_start(Config) ->
doc("Confirm that the ws_recv_frame_start event callback is called."),
{ok, Pid, _} = do_gun_open(Config),
@@ -824,6 +810,101 @@ do_ws_send_frame(Config, EventName) ->
} = do_receive_event(EventName),
gun:close(Pid).
+ws_protocol_changed(Config) ->
+ doc("Confirm that the protocol_changed event callback is called on Websocket upgrade success."),
+ {ok, Pid, _} = do_gun_open(Config),
+ {ok, _} = gun:await_up(Pid),
+ _ = gun:ws_upgrade(Pid, "/ws"),
+ #{
+ protocol := ws
+ } = do_receive_event(protocol_changed),
+ gun:close(Pid).
+
+http1_protocol_changed_connect(Config) ->
+ doc("Confirm that the protocol_changed event callback is called on CONNECT success "
+ "when connecting through a TLS server via a TCP proxy."),
+ OriginPort = config(tcp_origin_port, Config),
+ {ok, _, ProxyPort} = rfc7231_SUITE:do_proxy_start(tcp),
+ {ok, ConnPid} = gun:open("localhost", ProxyPort, #{
+ event_handler => {?MODULE, self()},
+ protocols => [config(name, config(tc_group_properties, Config))],
+ transport => tcp
+ }),
+ {ok, http} = gun:await_up(ConnPid),
+ _ = gun:connect(ConnPid, #{
+ host => "localhost",
+ port => OriginPort,
+ protocols => [http2]
+ }),
+ #{protocol := http2} = do_receive_event(protocol_changed),
+ gun:close(ConnPid).
+
+http1_protocol_changed_connect_over_https_proxy(Config) ->
+ doc("Confirm that the protocol_changed event callback is called on CONNECT success "
+ "when connecting through a TLS server via a TLS proxy."),
+ OriginPort = config(tls_origin_port, Config),
+ {ok, _, ProxyPort} = rfc7231_SUITE:do_proxy_start(tls),
+ {ok, ConnPid} = gun:open("localhost", ProxyPort, #{
+ event_handler => {?MODULE, self()},
+ protocols => [config(name, config(tc_group_properties, Config))],
+ transport => tls
+ }),
+ {ok, http} = gun:await_up(ConnPid),
+ _ = gun:connect(ConnPid, #{
+ host => "localhost",
+ port => OriginPort,
+ transport => tls,
+ protocols => [http2]
+ }),
+ #{protocol := http2} = do_receive_event(protocol_changed),
+ gun:close(ConnPid).
+
+http1_transport_changed_connect(Config) ->
+ doc("Confirm that the transport_changed event callback is called on CONNECT success "
+ "when connecting through a TLS server via a TCP proxy."),
+ OriginPort = config(tls_origin_port, Config),
+ {ok, _, ProxyPort} = rfc7231_SUITE:do_proxy_start(tcp),
+ {ok, ConnPid} = gun:open("localhost", ProxyPort, #{
+ event_handler => {?MODULE, self()},
+ protocols => [config(name, config(tc_group_properties, Config))],
+ transport => tcp
+ }),
+ {ok, http} = gun:await_up(ConnPid),
+ _ = gun:connect(ConnPid, #{
+ host => "localhost",
+ port => OriginPort,
+ transport => tls
+ }),
+ #{
+ socket := Socket,
+ transport := tls
+ } = do_receive_event(transport_changed),
+ true = is_tuple(Socket),
+ gun:close(ConnPid).
+
+http1_transport_changed_connect_over_https_proxy(Config) ->
+ doc("Confirm that the transport_changed event callback is called on CONNECT success "
+ "when connecting through a TLS server via a TLS proxy."),
+ OriginPort = config(tls_origin_port, Config),
+ {ok, _, ProxyPort} = rfc7231_SUITE:do_proxy_start(tls),
+ {ok, ConnPid} = gun:open("localhost", ProxyPort, #{
+ event_handler => {?MODULE, self()},
+ protocols => [config(name, config(tc_group_properties, Config))],
+ transport => tls
+ }),
+ {ok, http} = gun:await_up(ConnPid),
+ _ = gun:connect(ConnPid, #{
+ host => "localhost",
+ port => OriginPort,
+ transport => tls
+ }),
+ #{
+ socket := Socket,
+ transport := tls_proxy
+ } = do_receive_event(transport_changed),
+ true = is_pid(Socket),
+ gun:close(ConnPid).
+
cancel(Config) ->
doc("Confirm that the cancel event callback is called when we cancel a stream."),
{ok, Pid, _} = do_gun_open(Config),
@@ -986,10 +1067,6 @@ ws_upgrade(EventData, Pid) ->
Pid ! {?FUNCTION_NAME, EventData},
Pid.
-protocol_changed(EventData, Pid) ->
- Pid ! {?FUNCTION_NAME, EventData},
- Pid.
-
ws_recv_frame_start(EventData, Pid) ->
Pid ! {?FUNCTION_NAME, EventData},
Pid.
@@ -1010,6 +1087,14 @@ ws_send_frame_end(EventData, Pid) ->
Pid ! {?FUNCTION_NAME, EventData},
Pid.
+protocol_changed(EventData, Pid) ->
+ Pid ! {?FUNCTION_NAME, EventData},
+ Pid.
+
+transport_changed(EventData, Pid) ->
+ Pid ! {?FUNCTION_NAME, EventData},
+ Pid.
+
cancel(EventData, Pid) ->
Pid ! {?FUNCTION_NAME, EventData},
Pid.