aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2020-10-22 18:48:06 +0200
committerLoïc Hoguin <[email protected]>2020-11-02 17:16:57 +0100
commitd5f1a47e9ab758a51b23440eb72a0251527f3f7b (patch)
treee7c27355da10d89483394314a25cd5307ccc7da6 /test
parent465d072abf4a76104d4562ed15345b27fe9a0cff (diff)
downloadgun-d5f1a47e9ab758a51b23440eb72a0251527f3f7b.tar.gz
gun-d5f1a47e9ab758a51b23440eb72a0251527f3f7b.tar.bz2
gun-d5f1a47e9ab758a51b23440eb72a0251527f3f7b.zip
Initial implementation of Websocket over HTTP/2http2-websocket
Diffstat (limited to 'test')
-rw-r--r--test/event_SUITE.erl183
-rw-r--r--test/ws_SUITE.erl139
2 files changed, 230 insertions, 92 deletions
diff --git a/test/event_SUITE.erl b/test/event_SUITE.erl
index d883dc5..8be10b1 100644
--- a/test/event_SUITE.erl
+++ b/test/event_SUITE.erl
@@ -34,25 +34,25 @@ groups() ->
HTTP1Tests = [T || T <- Tests, lists:sublist(atom_to_list(T), 6) =:= "http1_"],
%% Push is not possible over HTTP/1.1.
PushTests = [T || T <- Tests, lists:sublist(atom_to_list(T), 5) =:= "push_"],
- %% We currently do not support Websocket over HTTP/2.
- WsTests = [T || T <- Tests, lists:sublist(atom_to_list(T), 3) =:= "ws_"],
[
{http, [parallel], Tests -- [cancel_remote, cancel_remote_connect|PushTests]},
- {http2, [parallel], (Tests -- WsTests) -- HTTP1Tests}
+ {http2, [parallel], Tests -- HTTP1Tests}
].
init_per_suite(Config) ->
- ProtoOpts = #{env => #{
- dispatch => cowboy_router:compile([{'_', [
- {"/", hello_h, []},
- {"/empty", empty_h, []},
- {"/inform", inform_h, []},
- {"/push", push_h, []},
- {"/stream", stream_h, []},
- {"/trailers", trailers_h, []},
- {"/ws", ws_echo_h, []}
- ]}])
- }},
+ Routes = [
+ {"/", hello_h, []},
+ {"/empty", empty_h, []},
+ {"/inform", inform_h, []},
+ {"/push", push_h, []},
+ {"/stream", stream_h, []},
+ {"/trailers", trailers_h, []},
+ {"/ws", ws_echo_h, []}
+ ],
+ ProtoOpts = #{
+ enable_connect_protocol => true,
+ env => #{dispatch => cowboy_router:compile([{'_', Routes}])}
+ },
{ok, _} = cowboy:start_clear({?MODULE, tcp}, [], ProtoOpts),
TCPOriginPort = ranch:get_port({?MODULE, tcp}),
{ok, _} = cowboy:start_tls({?MODULE, tls}, ct_helper:get_certs_from_ets(), ProtoOpts),
@@ -1227,8 +1227,10 @@ http1_response_end_body_close(Config) ->
ws_upgrade(Config) ->
doc("Confirm that the ws_upgrade event callback is called."),
+ Protocol = config(name, config(tc_group_properties, Config)),
{ok, Pid, _} = do_gun_open(Config),
- {ok, _} = gun:await_up(Pid),
+ {ok, Protocol} = gun:await_up(Pid),
+ ws_SUITE:do_await_enable_connect_protocol(Protocol, Pid),
StreamRef = gun:ws_upgrade(Pid, "/ws"),
ReplyTo = self(),
#{
@@ -1258,11 +1260,15 @@ do_ws_upgrade_connect(Config, ProxyProtocol) ->
StreamRef1 = gun:connect(ConnPid, #{
host => "localhost",
port => OriginPort,
- protocols => [OriginProtocol]
+ protocols => [case OriginProtocol of
+ http -> http;
+ http2 -> {http2, #{notify_settings_changed => true}}
+ end]
}, []),
%% @todo _IsFin is 'fin' for HTTP and 'nofin' for HTTP/2...
{response, _IsFin, 200, _} = gun:await(ConnPid, StreamRef1),
{up, OriginProtocol} = gun:await(ConnPid, StreamRef1),
+ ws_SUITE:do_await_enable_connect_protocol(OriginProtocol, ConnPid),
StreamRef2 = gun:ws_upgrade(ConnPid, "/ws", [], #{tunnel => StreamRef1}),
#{
stream_ref := StreamRef2,
@@ -1273,8 +1279,10 @@ do_ws_upgrade_connect(Config, ProxyProtocol) ->
ws_upgrade_all_events(Config) ->
doc("Confirm that a Websocket upgrade triggers all relevant events."),
+ Protocol = config(name, config(tc_group_properties, Config)),
{ok, Pid, OriginPort} = do_gun_open(Config),
- {ok, _} = gun:await_up(Pid),
+ {ok, Protocol} = gun:await_up(Pid),
+ ws_SUITE:do_await_enable_connect_protocol(Protocol, Pid),
StreamRef = gun:ws_upgrade(Pid, "/ws"),
ReplyTo = self(),
#{
@@ -1283,11 +1291,15 @@ ws_upgrade_all_events(Config) ->
opts := #{}
} = do_receive_event(ws_upgrade),
Authority = iolist_to_binary([<<"localhost:">>, integer_to_list(OriginPort)]),
+ Method = case Protocol of
+ http -> <<"GET">>;
+ http2 -> <<"CONNECT">>
+ end,
#{
stream_ref := StreamRef,
reply_to := ReplyTo,
function := ws_upgrade,
- method := <<"GET">>,
+ method := Method,
authority := EventAuthority1,
path := "/ws",
headers := [_|_]
@@ -1297,7 +1309,7 @@ ws_upgrade_all_events(Config) ->
stream_ref := StreamRef,
reply_to := ReplyTo,
function := ws_upgrade,
- method := <<"GET">>,
+ method := Method,
authority := EventAuthority2,
path := "/ws",
headers := [_|_]
@@ -1311,12 +1323,26 @@ ws_upgrade_all_events(Config) ->
stream_ref := StreamRef,
reply_to := ReplyTo
} = do_receive_event(response_start),
- #{
- stream_ref := StreamRef,
- reply_to := ReplyTo,
- status := 101,
- headers := [_|_]
- } = do_receive_event(response_inform),
+ _ = case Protocol of
+ http ->
+ #{
+ stream_ref := StreamRef,
+ reply_to := ReplyTo,
+ status := 101,
+ headers := [_|_]
+ } = do_receive_event(response_inform);
+ http2 ->
+ #{
+ stream_ref := StreamRef,
+ reply_to := ReplyTo,
+ status := 200,
+ headers := [_|_]
+ } = do_receive_event(response_headers),
+ #{
+ stream_ref := StreamRef,
+ reply_to := ReplyTo
+ } = do_receive_event(response_end)
+ end,
#{
stream_ref := StreamRef,
protocol := ws
@@ -1343,16 +1369,27 @@ do_ws_upgrade_all_events_connect(Config, ProxyProtocol) ->
StreamRef1 = gun:connect(ConnPid, #{
host => "localhost",
port => OriginPort,
- protocols => [OriginProtocol]
+ protocols => [case OriginProtocol of
+ http -> http;
+ http2 -> {http2, #{notify_settings_changed => true}}
+ end]
}, []),
%% @todo _IsFin is 'fin' for HTTP and 'nofin' for HTTP/2...
{response, _IsFin, 200, _} = gun:await(ConnPid, StreamRef1),
{up, OriginProtocol} = gun:await(ConnPid, StreamRef1),
+ ws_SUITE:do_await_enable_connect_protocol(OriginProtocol, ConnPid),
%% Skip all CONNECT-related events that may conflict.
_ = do_receive_event(request_start),
_ = do_receive_event(request_headers),
_ = do_receive_event(request_end),
_ = do_receive_event(response_start),
+ case OriginProtocol of
+ http -> ok;
+ http2 ->
+ _ = do_receive_event(response_headers),
+% _ = do_receive_event(response_end), @todo Probably should response_end CONNECT responses for both protocols.
+ ok
+ end,
_ = do_receive_event(protocol_changed),
%% Check the Websocket events.
StreamRef2 = gun:ws_upgrade(ConnPid, "/ws", [], #{tunnel => StreamRef1}),
@@ -1362,11 +1399,15 @@ do_ws_upgrade_all_events_connect(Config, ProxyProtocol) ->
opts := #{}
} = do_receive_event(ws_upgrade),
Authority = iolist_to_binary([<<"localhost:">>, integer_to_list(OriginPort)]),
+ Method = case OriginProtocol of
+ http -> <<"GET">>;
+ http2 -> <<"CONNECT">>
+ end,
#{
stream_ref := StreamRef2,
reply_to := ReplyTo,
function := ws_upgrade,
- method := <<"GET">>,
+ method := Method,
authority := EventAuthority1,
path := "/ws",
headers := [_|_]
@@ -1376,7 +1417,7 @@ do_ws_upgrade_all_events_connect(Config, ProxyProtocol) ->
stream_ref := StreamRef2,
reply_to := ReplyTo,
function := ws_upgrade,
- method := <<"GET">>,
+ method := Method,
authority := EventAuthority2,
path := "/ws",
headers := [_|_]
@@ -1390,12 +1431,26 @@ do_ws_upgrade_all_events_connect(Config, ProxyProtocol) ->
stream_ref := StreamRef2,
reply_to := ReplyTo
} = do_receive_event(response_start),
- #{
- stream_ref := StreamRef2,
- reply_to := ReplyTo,
- status := 101,
- headers := [_|_]
- } = do_receive_event(response_inform),
+ _ = case OriginProtocol of
+ http ->
+ #{
+ stream_ref := StreamRef2,
+ reply_to := ReplyTo,
+ status := 101,
+ headers := [_|_]
+ } = do_receive_event(response_inform);
+ http2 ->
+ #{
+ stream_ref := StreamRef2,
+ reply_to := ReplyTo,
+ status := 200,
+ headers := [_|_]
+ } = do_receive_event(response_headers),
+ #{
+ stream_ref := StreamRef2,
+ reply_to := ReplyTo
+ } = do_receive_event(response_end)
+ end,
#{
stream_ref := StreamRef2,
protocol := ws
@@ -1406,11 +1461,13 @@ do_ws_upgrade_all_events_connect(Config, ProxyProtocol) ->
ws_recv_frame_start(Config) ->
doc("Confirm that the ws_recv_frame_start event callback is called."),
+ Protocol = config(name, config(tc_group_properties, Config)),
{ok, Pid, _} = do_gun_open(Config),
- {ok, _} = gun:await_up(Pid),
+ {ok, Protocol} = gun:await_up(Pid),
+ ws_SUITE:do_await_enable_connect_protocol(Protocol, Pid),
StreamRef = gun:ws_upgrade(Pid, "/ws"),
{upgrade, [<<"websocket">>], _} = gun:await(Pid, StreamRef),
- gun:ws_send(Pid, {text, <<"Hello!">>}),
+ gun:ws_send(Pid, StreamRef, {text, <<"Hello!">>}),
ReplyTo = self(),
#{
stream_ref := StreamRef,
@@ -1440,11 +1497,15 @@ do_ws_recv_frame_start_connect(Config, ProxyProtocol) ->
StreamRef1 = gun:connect(ConnPid, #{
host => "localhost",
port => OriginPort,
- protocols => [OriginProtocol]
+ protocols => [case OriginProtocol of
+ http -> http;
+ http2 -> {http2, #{notify_settings_changed => true}}
+ end]
}, []),
%% @todo _IsFin is 'fin' for HTTP and 'nofin' for HTTP/2...
{response, _IsFin, 200, _} = gun:await(ConnPid, StreamRef1),
{up, OriginProtocol} = gun:await(ConnPid, StreamRef1),
+ ws_SUITE:do_await_enable_connect_protocol(OriginProtocol, ConnPid),
StreamRef2 = gun:ws_upgrade(ConnPid, "/ws", [], #{tunnel => StreamRef1}),
{upgrade, [<<"websocket">>], _} = gun:await(ConnPid, StreamRef2),
gun:ws_send(ConnPid, StreamRef2, {text, <<"Hello!">>}),
@@ -1458,11 +1519,13 @@ do_ws_recv_frame_start_connect(Config, ProxyProtocol) ->
ws_recv_frame_header(Config) ->
doc("Confirm that the ws_recv_frame_header event callback is called."),
+ Protocol = config(name, config(tc_group_properties, Config)),
{ok, Pid, _} = do_gun_open(Config),
- {ok, _} = gun:await_up(Pid),
+ {ok, Protocol} = gun:await_up(Pid),
+ ws_SUITE:do_await_enable_connect_protocol(Protocol, Pid),
StreamRef = gun:ws_upgrade(Pid, "/ws"),
{upgrade, [<<"websocket">>], _} = gun:await(Pid, StreamRef),
- gun:ws_send(Pid, {text, <<"Hello!">>}),
+ gun:ws_send(Pid, StreamRef, {text, <<"Hello!">>}),
ReplyTo = self(),
#{
stream_ref := StreamRef,
@@ -1496,11 +1559,15 @@ do_ws_recv_frame_header_connect(Config, ProxyProtocol) ->
StreamRef1 = gun:connect(ConnPid, #{
host => "localhost",
port => OriginPort,
- protocols => [OriginProtocol]
+ protocols => [case OriginProtocol of
+ http -> http;
+ http2 -> {http2, #{notify_settings_changed => true}}
+ end]
}, []),
%% @todo _IsFin is 'fin' for HTTP and 'nofin' for HTTP/2...
{response, _IsFin, 200, _} = gun:await(ConnPid, StreamRef1),
{up, OriginProtocol} = gun:await(ConnPid, StreamRef1),
+ ws_SUITE:do_await_enable_connect_protocol(OriginProtocol, ConnPid),
StreamRef2 = gun:ws_upgrade(ConnPid, "/ws", [], #{tunnel => StreamRef1}),
{upgrade, [<<"websocket">>], _} = gun:await(ConnPid, StreamRef2),
gun:ws_send(ConnPid, StreamRef2, {text, <<"Hello!">>}),
@@ -1518,11 +1585,13 @@ do_ws_recv_frame_header_connect(Config, ProxyProtocol) ->
ws_recv_frame_end(Config) ->
doc("Confirm that the ws_recv_frame_end event callback is called."),
+ Protocol = config(name, config(tc_group_properties, Config)),
{ok, Pid, _} = do_gun_open(Config),
- {ok, _} = gun:await_up(Pid),
+ {ok, Protocol} = gun:await_up(Pid),
+ ws_SUITE:do_await_enable_connect_protocol(Protocol, Pid),
StreamRef = gun:ws_upgrade(Pid, "/ws"),
{upgrade, [<<"websocket">>], _} = gun:await(Pid, StreamRef),
- gun:ws_send(Pid, {text, <<"Hello!">>}),
+ gun:ws_send(Pid, StreamRef, {text, <<"Hello!">>}),
ReplyTo = self(),
#{
stream_ref := StreamRef,
@@ -1553,11 +1622,15 @@ do_ws_recv_frame_end_connect(Config, ProxyProtocol) ->
StreamRef1 = gun:connect(ConnPid, #{
host => "localhost",
port => OriginPort,
- protocols => [OriginProtocol]
+ protocols => [case OriginProtocol of
+ http -> http;
+ http2 -> {http2, #{notify_settings_changed => true}}
+ end]
}, []),
%% @todo _IsFin is 'fin' for HTTP and 'nofin' for HTTP/2...
{response, _IsFin, 200, _} = gun:await(ConnPid, StreamRef1),
{up, OriginProtocol} = gun:await(ConnPid, StreamRef1),
+ ws_SUITE:do_await_enable_connect_protocol(OriginProtocol, ConnPid),
StreamRef2 = gun:ws_upgrade(ConnPid, "/ws", [], #{tunnel => StreamRef1}),
{upgrade, [<<"websocket">>], _} = gun:await(ConnPid, StreamRef2),
gun:ws_send(ConnPid, StreamRef2, {text, <<"Hello!">>}),
@@ -1581,11 +1654,13 @@ ws_send_frame_end(Config) ->
do_ws_send_frame(Config, ?FUNCTION_NAME).
do_ws_send_frame(Config, EventName) ->
+ Protocol = config(name, config(tc_group_properties, Config)),
{ok, Pid, _} = do_gun_open(Config),
- {ok, _} = gun:await_up(Pid),
+ {ok, Protocol} = gun:await_up(Pid),
+ ws_SUITE:do_await_enable_connect_protocol(Protocol, Pid),
StreamRef = gun:ws_upgrade(Pid, "/ws"),
{upgrade, [<<"websocket">>], _} = gun:await(Pid, StreamRef),
- gun:ws_send(Pid, {text, <<"Hello!">>}),
+ gun:ws_send(Pid, StreamRef, {text, <<"Hello!">>}),
ReplyTo = self(),
#{
stream_ref := StreamRef,
@@ -1621,11 +1696,15 @@ do_ws_send_frame_connect(Config, ProxyProtocol, EventName) ->
StreamRef1 = gun:connect(ConnPid, #{
host => "localhost",
port => OriginPort,
- protocols => [OriginProtocol]
+ protocols => [case OriginProtocol of
+ http -> http;
+ http2 -> {http2, #{notify_settings_changed => true}}
+ end]
}, []),
%% @todo _IsFin is 'fin' for HTTP and 'nofin' for HTTP/2...
{response, _IsFin, 200, _} = gun:await(ConnPid, StreamRef1),
{up, OriginProtocol} = gun:await(ConnPid, StreamRef1),
+ ws_SUITE:do_await_enable_connect_protocol(OriginProtocol, ConnPid),
StreamRef2 = gun:ws_upgrade(ConnPid, "/ws", [], #{tunnel => StreamRef1}),
{upgrade, [<<"websocket">>], _} = gun:await(ConnPid, StreamRef2),
gun:ws_send(ConnPid, StreamRef2, {text, <<"Hello!">>}),
@@ -1641,8 +1720,10 @@ do_ws_send_frame_connect(Config, ProxyProtocol, EventName) ->
ws_protocol_changed(Config) ->
doc("Confirm that the protocol_changed event callback is called on Websocket upgrade success."),
+ Protocol = config(name, config(tc_group_properties, Config)),
{ok, Pid, _} = do_gun_open(Config),
- {ok, _} = gun:await_up(Pid),
+ {ok, Protocol} = gun:await_up(Pid),
+ ws_SUITE:do_await_enable_connect_protocol(Protocol, Pid),
_ = gun:ws_upgrade(Pid, "/ws"),
#{
protocol := ws
@@ -1668,11 +1749,15 @@ do_ws_protocol_changed_connect(Config, ProxyProtocol) ->
StreamRef1 = gun:connect(ConnPid, #{
host => "localhost",
port => OriginPort,
- protocols => [OriginProtocol]
+ protocols => [case OriginProtocol of
+ http -> http;
+ http2 -> {http2, #{notify_settings_changed => true}}
+ end]
}, []),
%% @todo _IsFin is 'fin' for HTTP and 'nofin' for HTTP/2...
{response, _IsFin, 200, _} = gun:await(ConnPid, StreamRef1),
{up, OriginProtocol} = gun:await(ConnPid, StreamRef1),
+ ws_SUITE:do_await_enable_connect_protocol(OriginProtocol, ConnPid),
#{
stream_ref := StreamRef1,
protocol := OriginProtocol
@@ -1951,6 +2036,7 @@ do_gun_open(Config) ->
do_gun_open(OriginPort, Config) ->
Opts = #{
event_handler => {?MODULE, self()},
+ http2_opts => #{notify_settings_changed => true},
protocols => [config(name, config(tc_group_properties, Config))]
},
{ok, Pid} = gun:open("localhost", OriginPort, Opts),
@@ -1960,6 +2046,7 @@ do_gun_open_tls(Config) ->
OriginPort = config(tls_origin_port, Config),
Opts = #{
event_handler => {?MODULE, self()},
+ http2_opts => #{notify_settings_changed => true},
protocols => [config(name, config(tc_group_properties, Config))],
transport => tls
},
diff --git a/test/ws_SUITE.erl b/test/ws_SUITE.erl
index c04acc2..201403e 100644
--- a/test/ws_SUITE.erl
+++ b/test/ws_SUITE.erl
@@ -22,19 +22,30 @@
%% ct.
all() ->
- [{group, ws}].
+ [{group, http}, {group, http2}].
groups() ->
- [{ws, [], ct_helper:all(?MODULE)}].
+ Tests = ct_helper:all(?MODULE),
+ HTTP1Tests = [
+ http10_upgrade_error,
+ http11_request_error,
+ http11_keepalive,
+ http11_keepalive_default_silence_pings
+ ],
+ [
+ {http, [], Tests},
+ {http2, [], Tests -- HTTP1Tests}
+ ].
init_per_suite(Config) ->
Routes = [
{"/", ws_echo_h, []},
{"/reject", ws_reject_h, []}
],
- {ok, _} = cowboy:start_clear(ws, [], #{env => #{
- dispatch => cowboy_router:compile([{'_', Routes}])
- }}),
+ {ok, _} = cowboy:start_clear(ws, [], #{
+ enable_connect_protocol => true,
+ env => #{dispatch => cowboy_router:compile([{'_', Routes}])}
+ }),
Port = ranch:get_port(ws),
[{port, Port}|Config].
@@ -45,16 +56,37 @@ end_per_suite(_) ->
await(Config) ->
doc("Ensure gun:await/2 can be used to receive Websocket frames."),
- {ok, ConnPid} = gun:open("localhost", config(port, Config)),
- {ok, _} = gun:await_up(ConnPid),
+ Protocol = config(name, config(tc_group_properties, Config)),
+ {ok, ConnPid} = gun:open("localhost", config(port, Config), #{
+ protocols => [Protocol],
+ http2_opts => #{notify_settings_changed => true}
+ }),
+ {ok, Protocol} = gun:await_up(ConnPid),
+ do_await_enable_connect_protocol(Protocol, ConnPid),
StreamRef = gun:ws_upgrade(ConnPid, "/", []),
{upgrade, [<<"websocket">>], _} = gun:await(ConnPid, StreamRef),
Frame = {text, <<"Hello!">>},
- gun:ws_send(ConnPid, Frame),
+ gun:ws_send(ConnPid, StreamRef, Frame),
{ws, Frame} = gun:await(ConnPid, StreamRef),
gun:close(ConnPid).
-error_http10_upgrade(Config) ->
+headers_normalized_upgrade(Config) ->
+ doc("Headers passed to ws_upgrade are normalized before being used."),
+ Protocol = config(name, config(tc_group_properties, Config)),
+ {ok, ConnPid} = gun:open("localhost", config(port, Config), #{
+ protocols => [Protocol],
+ http2_opts => #{notify_settings_changed => true}
+ }),
+ {ok, Protocol} = gun:await_up(ConnPid),
+ do_await_enable_connect_protocol(Protocol, ConnPid),
+ StreamRef = gun:ws_upgrade(ConnPid, "/", #{
+ atom_header_name => <<"value">>,
+ "string_header_name" => <<"value">>
+ }),
+ {upgrade, [<<"websocket">>], _} = gun:await(ConnPid, StreamRef),
+ gun:close(ConnPid).
+
+http10_upgrade_error(Config) ->
doc("Attempting to upgrade HTTP/1.0 to Websocket produces an error."),
{ok, ConnPid} = gun:open("localhost", config(port, Config), #{
http_opts => #{version => 'HTTP/1.0'}
@@ -70,28 +102,7 @@ error_http10_upgrade(Config) ->
error(timeout)
end.
-headers_normalized_upgrade(Config) ->
- doc("Headers passed to ws_upgrade are normalized before being used."),
- {ok, ConnPid} = gun:open("localhost", config(port, Config)),
- {ok, _} = gun:await_up(ConnPid),
- StreamRef = gun:ws_upgrade(ConnPid, "/", #{
- atom_header_name => <<"value">>,
- "string_header_name" => <<"value">>
- }),
- {upgrade, [<<"websocket">>], _} = gun:await(ConnPid, StreamRef),
- gun:close(ConnPid).
-
-error_http_request(Config) ->
- doc("Ensure that requests are rejected while using Websocket."),
- {ok, ConnPid} = gun:open("localhost", config(port, Config)),
- {ok, _} = gun:await_up(ConnPid),
- StreamRef1 = gun:ws_upgrade(ConnPid, "/", []),
- {upgrade, [<<"websocket">>], _} = gun:await(ConnPid, StreamRef1),
- StreamRef2 = gun:get(ConnPid, "/"),
- {error, {connection_error, {badstate, _}}} = gun:await(ConnPid, StreamRef2),
- gun:close(ConnPid).
-
-keepalive(Config) ->
+http11_keepalive(Config) ->
doc("Ensure that Gun automatically sends ping frames."),
{ok, ConnPid} = gun:open("localhost", config(port, Config), #{
ws_opts => #{
@@ -106,7 +117,7 @@ keepalive(Config) ->
{ws, pong} = gun:await(ConnPid, StreamRef),
gun:close(ConnPid).
-keepalive_default_silence_pings(Config) ->
+http11_keepalive_default_silence_pings(Config) ->
doc("Ensure that Gun does not forward ping/pong by default."),
{ok, ConnPid} = gun:open("localhost", config(port, Config), #{
ws_opts => #{keepalive => 100}
@@ -118,10 +129,25 @@ keepalive_default_silence_pings(Config) ->
{error, timeout} = gun:await(ConnPid, StreamRef, 1000),
gun:close(ConnPid).
-reject_upgrade(Config) ->
- doc("Ensure Websocket connections can be rejected."),
+http11_request_error(Config) ->
+ doc("Ensure that HTTP/1.1 requests are rejected while using Websocket."),
{ok, ConnPid} = gun:open("localhost", config(port, Config)),
{ok, _} = gun:await_up(ConnPid),
+ StreamRef1 = gun:ws_upgrade(ConnPid, "/", []),
+ {upgrade, [<<"websocket">>], _} = gun:await(ConnPid, StreamRef1),
+ StreamRef2 = gun:get(ConnPid, "/"),
+ {error, {connection_error, {badstate, _}}} = gun:await(ConnPid, StreamRef2),
+ gun:close(ConnPid).
+
+reject_upgrade(Config) ->
+ doc("Ensure Websocket connections can be rejected."),
+ Protocol = config(name, config(tc_group_properties, Config)),
+ {ok, ConnPid} = gun:open("localhost", config(port, Config), #{
+ protocols => [Protocol],
+ http2_opts => #{notify_settings_changed => true}
+ }),
+ {ok, Protocol} = gun:await_up(ConnPid),
+ do_await_enable_connect_protocol(Protocol, ConnPid),
StreamRef = gun:ws_upgrade(ConnPid, "/reject", []),
receive
{gun_response, ConnPid, StreamRef, nofin, 400, _} ->
@@ -134,7 +160,7 @@ reject_upgrade(Config) ->
end.
reply_to(Config) ->
- doc("Ensure we can send a list of frames in one gun:ws_send call."),
+ doc("Ensure the reply_to request option is respected."),
Self = self(),
Frame = {text, <<"Hello!">>},
ReplyTo = spawn(fun() ->
@@ -144,36 +170,61 @@ reply_to(Config) ->
{ws, Frame} = gun:await(ConnPid, StreamRef),
Self ! {self(), ok}
end),
- {ok, ConnPid} = gun:open("localhost", config(port, Config)),
- {ok, _} = gun:await_up(ConnPid),
+ Protocol = config(name, config(tc_group_properties, Config)),
+ {ok, ConnPid} = gun:open("localhost", config(port, Config), #{
+ protocols => [Protocol],
+ http2_opts => #{notify_settings_changed => true}
+ }),
+ {ok, Protocol} = gun:await_up(ConnPid),
+ do_await_enable_connect_protocol(Protocol, ConnPid),
StreamRef = gun:ws_upgrade(ConnPid, "/", [], #{reply_to => ReplyTo}),
ReplyTo ! {ConnPid, StreamRef},
- receive {ReplyTo, ready} -> gun:ws_send(ConnPid, Frame) after 1000 -> error(timeout) end,
+ receive {ReplyTo, ready} -> gun:ws_send(ConnPid, StreamRef, Frame) after 1000 -> error(timeout) end,
receive {ReplyTo, ok} -> gun:close(ConnPid) after 1000 -> error(timeout) end.
send_many(Config) ->
doc("Ensure we can send a list of frames in one gun:ws_send call."),
- {ok, ConnPid} = gun:open("localhost", config(port, Config)),
- {ok, _} = gun:await_up(ConnPid),
+ Protocol = config(name, config(tc_group_properties, Config)),
+ {ok, ConnPid} = gun:open("localhost", config(port, Config), #{
+ protocols => [Protocol],
+ http2_opts => #{notify_settings_changed => true}
+ }),
+ {ok, Protocol} = gun:await_up(ConnPid),
+ do_await_enable_connect_protocol(Protocol, ConnPid),
StreamRef = gun:ws_upgrade(ConnPid, "/", []),
{upgrade, [<<"websocket">>], _} = gun:await(ConnPid, StreamRef),
Frame1 = {text, <<"Hello!">>},
Frame2 = {binary, <<"World!">>},
- gun:ws_send(ConnPid, [Frame1, Frame2]),
+ gun:ws_send(ConnPid, StreamRef, [Frame1, Frame2]),
{ws, Frame1} = gun:await(ConnPid, StreamRef),
{ws, Frame2} = gun:await(ConnPid, StreamRef),
gun:close(ConnPid).
send_many_close(Config) ->
doc("Ensure we can send a list of frames in one gun:ws_send call, including a close frame."),
- {ok, ConnPid} = gun:open("localhost", config(port, Config)),
- {ok, _} = gun:await_up(ConnPid),
+ Protocol = config(name, config(tc_group_properties, Config)),
+ {ok, ConnPid} = gun:open("localhost", config(port, Config), #{
+ protocols => [Protocol],
+ http2_opts => #{notify_settings_changed => true}
+ }),
+ {ok, Protocol} = gun:await_up(ConnPid),
+ do_await_enable_connect_protocol(Protocol, ConnPid),
StreamRef = gun:ws_upgrade(ConnPid, "/", []),
{upgrade, [<<"websocket">>], _} = gun:await(ConnPid, StreamRef),
Frame1 = {text, <<"Hello!">>},
Frame2 = {binary, <<"World!">>},
- gun:ws_send(ConnPid, [Frame1, Frame2, close]),
+ gun:ws_send(ConnPid, StreamRef, [Frame1, Frame2, close]),
{ws, Frame1} = gun:await(ConnPid, StreamRef),
{ws, Frame2} = gun:await(ConnPid, StreamRef),
{ws, close} = gun:await(ConnPid, StreamRef),
gun:close(ConnPid).
+
+%% Internal.
+
+do_await_enable_connect_protocol(http, _) ->
+ ok;
+%% We cannot do a CONNECT :protocol request until the server tells us we can.
+do_await_enable_connect_protocol(http2, ConnPid) ->
+ {notify, settings_changed, #{enable_connect_protocol := true}}
+ = gun:await(ConnPid, undefined), %% @todo Maybe have a gun:await/1?
+ ok.