From 56b7fdd6eb15564ad821885937b03516a03dce4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Fri, 26 Jul 2019 14:25:59 +0200 Subject: Add the transport_changed event Also test protocol_changed over CONNECT. --- src/gun.erl | 11 ++-- src/gun_default_event_h.erl | 12 +++-- src/gun_event.erl | 48 +++++++++++------ test/event_SUITE.erl | 123 +++++++++++++++++++++++++++++++++++++------- 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. -- cgit v1.2.3