aboutsummaryrefslogtreecommitdiffstats
path: root/test/ping_SUITE.erl
blob: 150999914e00f05b27bc232af20aaf6fb8f90ea4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
%% Copyright (c) Loïc Hoguin <[email protected]>
%%
%% Permission to use, copy, modify, and/or distribute this software for any
%% purpose with or without fee is hereby granted, provided that the above
%% copyright notice and this permission notice appear in all copies.
%%
%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

-module(ping_SUITE).
-compile(export_all).
-compile(nowarn_export_all).

-import(ct_helper, [config/2]).
-import(ct_helper, [doc/1]).
-import(gun_test, [init_origin/3]).
-import(gun_test, [receive_from/1]).

all() ->
	ct_helper:all(?MODULE).

%% Tests.

h1_user_ping(Config0) ->
	doc("The PING frame cannot be used to test an HTTP/1.1 connection."),
	Config = gun_test:init_cowboy_tcp(?FUNCTION_NAME, #{}, Config0),
	OriginPort = config(port, Config),
	{ok, ConnPid} = gun:open("localhost", OriginPort, #{
		protocols => [http]
	}),
	{ok, http} = gun:await_up(ConnPid),
	PingRef = gun:ping(ConnPid),
	receive
		{gun_down, ConnPid, http, {error, {ping_unsupported_by_protocol, PingRef}}, []} ->
			gun:close(ConnPid)
	after 1000 ->
		ct:pal("~p", [process_info(self(), messages)]),
		error(timeout)
	end.

h2_user_ping(_) ->
	doc("The PING frame may be used to easily test an HTTP/2 connection."),
	{ok, OriginPid, OriginPort} = init_origin(tcp, http2, fun (_, _, Socket, Transport) ->
		{ok, Data} = Transport:recv(Socket, 9, infinity),
		<<Len:24, 6:8, %% PING
			0:8, %% Flags
			0:1, 0:31>> = Data,
		{ok, Payload} = Transport:recv(Socket, Len, 1000),
		8 = Len = byte_size(Payload),
		Ack = <<8:24, 6:8, %% PING
			1:8, %% Ack flag
			0:1, 0:31, Payload/binary>>,
		ok = Transport:send(Socket, Ack)
	end),
	{ok, ConnPid} = gun:open("localhost", OriginPort, #{
		protocols => [http2]
	}),
	{ok, http2} = gun:await_up(ConnPid),
	handshake_completed = receive_from(OriginPid),
	PingRef = gun:ping(ConnPid),
	{notify, ping_ack, PingRef} = gun:await(ConnPid, undefined),
	gun:close(ConnPid).

h2c_user_ping_via_http(_) ->
	doc("The PING frame may be used to easily test an HTTP/2 connection."),
	do_h2c_user_ping_tunnel(http).

h2c_user_ping_via_https(_) ->
	doc("The PING frame may be used to easily test an HTTP/2 connection."),
	do_h2c_user_ping_tunnel(https).

h2c_user_ping_via_h2c(_) ->
	doc("The PING frame may be used to easily test an HTTP/2 connection."),
	do_h2c_user_ping_tunnel(h2c).

h2c_user_ping_via_h2(_) ->
	doc("The PING frame may be used to easily test an HTTP/2 connection."),
	do_h2c_user_ping_tunnel(h2).

do_h2c_user_ping_tunnel(ProxyType) ->
	{ok, OriginPid, OriginPort} = init_origin(tcp, http2, fun (_, _, Socket, Transport) ->
		{ok, Data} = Transport:recv(Socket, 9, infinity),
		<<Len:24, 6:8, %% PING
			0:8, %% Flags
			0:1, 0:31>> = Data,
		{ok, Payload} = Transport:recv(Socket, Len, 1000),
		8 = Len = byte_size(Payload),
		Ack = <<8:24, 6:8, %% PING
			1:8, %% Ack flag
			0:1, 0:31, Payload/binary>>,
		ok = Transport:send(Socket, Ack)
	end),
	{ok, ProxyPid, ProxyPort} = tunnel_SUITE:do_proxy_start(ProxyType),
	{ProxyTransport, ProxyProtocol} = tunnel_SUITE:do_type(ProxyType),
	{ok, ConnPid} = gun:open("localhost", ProxyPort, #{
		transport => ProxyTransport,
		tls_opts => [{verify, verify_none}, {versions, ['tlsv1.2']}],
		protocols => [ProxyProtocol]
	}),
	{ok, ProxyProtocol} = gun:await_up(ConnPid),
	tunnel_SUITE:do_handshake_completed(ProxyProtocol, ProxyPid),
	StreamRef = gun:connect(ConnPid, #{
		host => "localhost",
		port => OriginPort,
		transport => tcp,
		protocols => [http2]
	}),
	{response, fin, 200, _} = gun:await(ConnPid, StreamRef),
	handshake_completed = receive_from(OriginPid),
	{up, http2} = gun:await(ConnPid, StreamRef),
	PingRef = gun:ping(ConnPid, #{tunnel => StreamRef}),
	{notify, ping_ack, PingRef} = gun:await(ConnPid, undefined),
	gun:close(ConnPid).