aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2020-09-25 13:52:31 +0200
committerLoïc Hoguin <[email protected]>2020-10-03 17:30:36 +0200
commit2f42047d6cec210186d703e31e5fd970b1ea4e33 (patch)
tree30c529955a79df3cb0cb13021c951ce655617f95 /test
parent3ce70c5d96902e0e2718447383992dc7d6232e3a (diff)
downloadgun-2f42047d6cec210186d703e31e5fd970b1ea4e33.tar.gz
gun-2f42047d6cec210186d703e31e5fd970b1ea4e33.tar.bz2
gun-2f42047d6cec210186d703e31e5fd970b1ea4e33.zip
Add tunnel_SUITE testing all 3-layer combinations
The test suite is 216 tests with a tunnel created via two proxies leading to one origin server. The tests are for example socks5_h2_https where socks5 identifies the first SOCKS5 proxy, h2 the second HTTP/2 CONNECT proxy and https the secure HTTP/1.1 origin server. The test not only sets up the tunnel and does a request (or sends/receives data in the case of raw origin servers) but also confirms that the stream_info and info data is correct.
Diffstat (limited to 'test')
-rw-r--r--test/handlers/proxied_h.erl10
-rw-r--r--test/rfc7540_SUITE.erl2
-rw-r--r--test/tunnel_SUITE.erl1124
3 files changed, 1130 insertions, 6 deletions
diff --git a/test/handlers/proxied_h.erl b/test/handlers/proxied_h.erl
index d5d4690..818823c 100644
--- a/test/handlers/proxied_h.erl
+++ b/test/handlers/proxied_h.erl
@@ -4,8 +4,8 @@
-export([init/2]).
-init(Req, State) ->
- {ok, cowboy_req:reply(200,
- #{<<"content-type">> => <<"text/plain">>},
- <<"TODO">>,
- Req), State}.
+-spec init(cowboy_req:req(), _) -> no_return().
+init(Req, _) ->
+ _ = cowboy_req:stream_reply(200, #{<<"content-type">> => <<"text/plain">>}, Req),
+ %% We never return to allow querying the stream_info.
+ receive after infinity -> ok end.
diff --git a/test/rfc7540_SUITE.erl b/test/rfc7540_SUITE.erl
index 4116ef4..9cb4ca2 100644
--- a/test/rfc7540_SUITE.erl
+++ b/test/rfc7540_SUITE.erl
@@ -632,7 +632,7 @@ do_connect_cowboy(_OriginScheme, OriginTransport, OriginProtocol, _ProxyScheme,
{response, nofin, 200, _} = gun:await(ConnPid, StreamRef),
{up, OriginProtocol} = gun:await(ConnPid, StreamRef),
ProxiedStreamRef = gun:get(ConnPid, "/proxied", #{}, #{tunnel => StreamRef}),
- timer:sleep(1000),
+ timer:sleep(1000), %% @todo Why?
{response, nofin, 200, _} = gun:await(ConnPid, ProxiedStreamRef),
%% We can create more requests on the proxy as well.
ProxyStreamRef = gun:get(ConnPid, "/"),
diff --git a/test/tunnel_SUITE.erl b/test/tunnel_SUITE.erl
new file mode 100644
index 0000000..190eb17
--- /dev/null
+++ b/test/tunnel_SUITE.erl
@@ -0,0 +1,1124 @@
+%% Copyright (c) 2020, 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(tunnel_SUITE).
+-compile(export_all).
+-compile(nowarn_export_all).
+
+-import(ct_helper, [doc/1]).
+-import(gun_test, [receive_from/1]).
+
+all() ->
+ ct_helper:all(?MODULE).
+
+%% Tests.
+%%
+%% Test names list the endpoint in the order the connection
+%% goes through, with proxies first and the origin server last.
+%% Each endpoint is identified by one of the following identifiers:
+%%
+%% Identifier | Protocol | Transport
+%% ---------- |----------|--------
+%% http | HTTP/1.1 | TCP
+%% https | HTTP/1.1 | TLS
+%% h2c | HTTP/2 | TCP
+%% h2 | HTTP/2 | TLS
+%% socks5 | SOCKS5 | TCP
+%% socks5tls | SOCKS5 | TLS
+%% raw | Raw | TCP
+%% rawtls | Raw | TLS
+
+http_http_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_http_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_http_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_http_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_http_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_http_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+http_https_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_https_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_https_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_https_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_https_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_https_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+http_h2c_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_h2c_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_h2c_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_h2c_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_h2c_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_h2c_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+http_h2_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_h2_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_h2_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_h2_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_h2_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_h2_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+http_socks5_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_socks5_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_socks5_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_socks5_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_socks5_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_socks5_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+http_socks5tls_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_socks5tls_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_socks5tls_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_socks5tls_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_socks5tls_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+http_socks5tls_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+https_http_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_http_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_http_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_http_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_http_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_http_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+https_https_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_https_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_https_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_https_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_https_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_https_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+https_h2c_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_h2c_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_h2c_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_h2c_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_h2c_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_h2c_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+https_h2_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_h2_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_h2_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_h2_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_h2_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_h2_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+https_socks5_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_socks5_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_socks5_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_socks5_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_socks5_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_socks5_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+https_socks5tls_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_socks5tls_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_socks5tls_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_socks5tls_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_socks5tls_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+https_socks5tls_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+h2c_http_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_http_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_http_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_http_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_http_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_http_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+h2c_https_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_https_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_https_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_https_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_https_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_https_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+h2c_h2c_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_h2c_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_h2c_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_h2c_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_h2c_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_h2c_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+h2c_h2_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_h2_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_h2_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_h2_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_h2_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_h2_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+h2c_socks5_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_socks5_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_socks5_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_socks5_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_socks5_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_socks5_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+h2c_socks5tls_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_socks5tls_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_socks5tls_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_socks5tls_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_socks5tls_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2c_socks5tls_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+h2_http_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_http_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_http_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_http_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_http_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_http_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+h2_https_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_https_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_https_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_https_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_https_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_https_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+h2_h2c_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_h2c_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_h2c_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_h2c_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_h2c_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_h2c_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+h2_h2_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_h2_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_h2_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_h2_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_h2_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_h2_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+h2_socks5_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_socks5_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_socks5_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_socks5_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_socks5_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_socks5_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+h2_socks5tls_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_socks5tls_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_socks5tls_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_socks5tls_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_socks5tls_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+h2_socks5tls_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+socks5_http_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_http_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_http_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_http_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_http_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_http_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+socks5_https_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_https_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_https_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_https_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_https_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_https_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+socks5_h2c_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_h2c_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_h2c_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_h2c_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_h2c_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_h2c_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+socks5_h2_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_h2_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_h2_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_h2_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_h2_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_h2_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+socks5_socks5_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_socks5_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_socks5_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_socks5_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_socks5_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_socks5_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+socks5_socks5tls_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_socks5tls_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_socks5tls_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_socks5tls_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_socks5tls_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5_socks5tls_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+socks5tls_http_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_http_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_http_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_http_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_http_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_http_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+socks5tls_https_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_https_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_https_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_https_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_https_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_https_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+socks5tls_h2c_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_h2c_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_h2c_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_h2c_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_h2c_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_h2c_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+socks5tls_h2_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_h2_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_h2_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_h2_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_h2_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_h2_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+socks5tls_socks5_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_socks5_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_socks5_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_socks5_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_socks5_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_socks5_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%%
+
+socks5tls_socks5tls_http(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_socks5tls_https(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_socks5tls_h2c(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_socks5tls_h2(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_socks5tls_raw(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+socks5tls_socks5tls_rawtls(_) ->
+ do_tunnel(?FUNCTION_NAME).
+
+%% Common code for all the test cases.
+
+-record(st, {
+ proxy1,
+ proxy1_pid,
+ proxy1_port,
+
+ proxy2,
+ proxy2_pid,
+ proxy2_port,
+
+ origin,
+ origin_pid,
+ origin_port
+}).
+
+do_tunnel(FunctionName) ->
+
+%dbg:tracer(),
+%dbg:tpl(gun, []),
+%dbg:tpl(gun_http, []),
+%dbg:tpl(gun_http2, []),
+%dbg:tpl(gun_tunnel, []),
+%dbg:p(all, c),
+
+%dbg:tracer(),
+%dbg:tpl(?MODULE, []),
+%dbg:p(all, c),
+
+ [Proxy1, Proxy2, Origin] = [list_to_atom(Lex) || Lex <- string:lexemes(atom_to_list(FunctionName), "_")],
+ do_doc(Proxy1, Proxy2, Origin),
+ {ok, OriginPid, OriginPort} = do_origin_start(Origin),
+ {ok, Proxy1Pid, Proxy1Port} = do_proxy_start(Proxy1),
+ {ok, Proxy2Pid, Proxy2Port} = do_proxy_start(Proxy2),
+ State = #st{
+ proxy1=Proxy1, proxy1_pid=Proxy1Pid, proxy1_port=Proxy1Port,
+ proxy2=Proxy2, proxy2_pid=Proxy2Pid, proxy2_port=Proxy2Port,
+ origin=Origin, origin_pid=OriginPid, origin_port=OriginPort
+ },
+ ConnPid = do_proxy1(State),
+ StreamRef1 = do_proxy2(State, ConnPid),
+ StreamRef2 = do_origin(State, ConnPid, StreamRef1),
+ StreamRef3 = do_origin_stream(State, ConnPid, StreamRef2),
+ do_proxy1_stream_info(State, ConnPid, StreamRef1),
+ do_proxy2_stream_info(State, ConnPid, StreamRef2),
+ do_origin_stream_info(State, ConnPid, StreamRef3),
+ do_info(State, ConnPid).
+
+do_doc(Proxy1, Proxy2, Origin) ->
+ doc(do_doc(Proxy1, "proxy") ++ " -> " ++ do_doc(Proxy2, "proxy") ++ " -> " ++ do_doc(Origin, "origin")).
+
+do_doc(Type, Endpoint) ->
+ {Transport, Protocol} = do_type(Type),
+ case Protocol of
+ http -> "HTTP/1.1";
+ http2 -> "HTTP/2";
+ socks -> "SOCKS5";
+ raw -> "Raw"
+ end
+ ++ " " ++ Endpoint ++ " over " ++
+ case Transport of
+ tcp -> "TCP";
+ tls -> "TLS"
+ end.
+
+do_origin_start(Type) when Type =:= raw; Type =:= rawtls ->
+ {Transport, Protocol} = do_type(Type),
+ gun_test:init_origin(Transport, Protocol, fun raw_SUITE:do_echo/3);
+do_origin_start(Type) ->
+ {Transport, Protocol} = do_type(Type),
+ rfc7540_SUITE:do_cowboy_origin(Transport, Protocol).
+
+do_proxy_start(Type) when Type =:= http; Type =:= https ->
+ {Transport, _} = do_type(Type),
+ rfc7231_SUITE:do_proxy_start(Transport);
+do_proxy_start(Type) when Type =:= h2; Type =:= h2c ->
+ {Transport, _} = do_type(Type),
+ rfc7540_SUITE:do_proxy_start(Transport);
+do_proxy_start(Type) when Type =:= socks5; Type =:= socks5tls ->
+ {Transport, _} = do_type(Type),
+ socks_SUITE:do_proxy_start(Transport, none).
+
+do_proxy1(State=#st{proxy1=Type, proxy1_pid=Proxy1Pid, proxy1_port=Port}) ->
+ {Transport, Protocol} = do_type(Type),
+ {ok, ConnPid} = gun:open("localhost", Port, #{
+ transport => Transport,
+ protocols => [case Protocol of
+ socks ->
+ {Protocol, do_proxy2_socks_opts(State)};
+ _ ->
+ Protocol
+ end]
+ }),
+ {ok, Protocol} = gun:await_up(ConnPid),
+ do_handshake_completed(Protocol, Proxy1Pid),
+ ConnPid.
+
+do_proxy2_socks_opts(State=#st{proxy2=Type, proxy2_port=Port}) ->
+ {Transport, Protocol} = do_type(Type),
+ #{
+ host => "localhost",
+ port => Port,
+ transport => Transport,
+ protocols => [case Protocol of
+ socks ->
+ {Protocol, do_origin_socks_opts(State)};
+ _ ->
+ Protocol
+ end]
+ }.
+
+do_origin_socks_opts(#st{origin=Type, origin_port=Port}) ->
+ {Transport, Protocol} = do_type(Type),
+ #{
+ host => "localhost",
+ port => Port,
+ transport => Transport,
+ protocols => [Protocol]
+ }.
+
+%% When the first proxy was socks all we need to do is wait for
+%% the second proxy to be up.
+do_proxy2(#st{proxy1=Proxy1Type, proxy2=Proxy2Type, proxy2_pid=Proxy2Pid}, ConnPid)
+ when Proxy1Type =:= socks5; Proxy1Type =:= socks5tls ->
+ {_, Protocol} = do_type(Proxy2Type),
+ {up, Protocol} = gun:await(ConnPid, undefined),
+ do_handshake_completed(Protocol, Proxy2Pid),
+ undefined;
+do_proxy2(State=#st{proxy2=Type, proxy2_pid=Proxy2Pid, proxy2_port=Port}, ConnPid) ->
+ {Transport, Protocol} = do_type(Type),
+ StreamRef1 = gun:connect(ConnPid, #{
+ host => "localhost",
+ port => Port,
+ transport => Transport,
+ protocols => [case Protocol of
+ socks ->
+ {Protocol, do_origin_socks_opts(State)};
+ _ ->
+ Protocol
+ end]
+ }),
+ %% @todo _IsFin is 'fin' for HTTP and 'nofin' for HTTP/2...
+ {response, _IsFin, 200, _} = gun:await(ConnPid, StreamRef1),
+ {up, Protocol} = gun:await(ConnPid, StreamRef1),
+ do_handshake_completed(Protocol, Proxy2Pid),
+ StreamRef1.
+
+%% When the second proxy was socks all we need to do is wait for
+%% the origin to be up.
+do_origin(#st{proxy2=Proxy2Type, origin=OriginType}, ConnPid, StreamRef)
+ when Proxy2Type =:= socks5; Proxy2Type =:= socks5tls ->
+ {_, Protocol} = do_type(OriginType),
+ {up, Protocol} = gun:await(ConnPid, StreamRef),
+ StreamRef;
+%% We can't have a socks5/socks5tls origin.
+do_origin(#st{origin=Type, origin_port=Port}, ConnPid, StreamRef1) ->
+ {Transport, Protocol} = do_type(Type),
+ StreamRef2 = gun:connect(ConnPid, #{
+ host => "localhost",
+ port => Port,
+ transport => Transport,
+ protocols => [Protocol]
+ }, [], #{tunnel => StreamRef1}),
+ %% @todo _IsFin is 'fin' for HTTP and 'nofin' for HTTP/2...
+ {response, _IsFin, 200, _} = gun:await(ConnPid, StreamRef2),
+ {up, Protocol} = gun:await(ConnPid, StreamRef2),
+ StreamRef2.
+
+do_handshake_completed(http2, ProxyPid) ->
+ handshake_completed = receive_from(ProxyPid),
+ ok;
+do_handshake_completed(_, _) ->
+ ok.
+
+do_origin_stream(#st{origin=Type}, ConnPid, StreamRef2)
+ when Type =:= raw; Type =:= rawtls ->
+ gun:data(ConnPid, StreamRef2, nofin, <<"Hello world!">>),
+ {data, nofin, <<"Hello world!">>} = gun:await(ConnPid, StreamRef2),
+ StreamRef2;
+do_origin_stream(#st{}, ConnPid, StreamRef2) ->
+ StreamRef3 = gun:get(ConnPid, "/proxied", #{}, #{tunnel => StreamRef2}),
+ {response, nofin, 200, _} = gun:await(ConnPid, StreamRef3),
+ StreamRef3.
+
+do_proxy1_stream_info(#st{proxy1=Proxy1}, _, _)
+ when Proxy1 =:= socks5; Proxy1 =:= socks5tls ->
+ ok;
+do_proxy1_stream_info(#st{proxy1=Proxy1, proxy2=Proxy2, proxy2_port=Proxy2Port}, ConnPid, StreamRef1) ->
+ ct:log("1: ~p~n~p", [StreamRef1, gun:stream_info(ConnPid, StreamRef1)]),
+ Self = if
+ %% We do not currently keep reply_to after switch_protocol.
+ Proxy1 =:= http; Proxy1 =:= https ->
+ undefined;
+ true ->
+ self()
+ end,
+ {Proxy2Transport, Proxy2Protocol} = do_type(Proxy2),
+ Proxy2Scheme = case Proxy2Transport of
+ tcp -> <<"http">>;
+ tls -> <<"https">>
+ end,
+ {ok, #{
+ ref := StreamRef1,
+ reply_to := Self,
+ state := running,
+ tunnel := #{
+ transport := Proxy2Transport,
+ protocol := Proxy2Protocol,
+ origin_scheme := Proxy2Scheme,
+ origin_host := "localhost",
+ origin_port := Proxy2Port
+ }
+ }} = gun:stream_info(ConnPid, StreamRef1),
+ ok.
+
+do_proxy2_stream_info(#st{proxy2=Proxy2}, _, _)
+ when Proxy2 =:= socks5; Proxy2 =:= socks5tls ->
+ ok;
+do_proxy2_stream_info(#st{proxy1=Proxy1, proxy1_port=Proxy1Port, proxy2=Proxy2,
+ origin=Origin, origin_port=OriginPort}, ConnPid, StreamRef2) ->
+ ct:log("2: ~p~n~p", [StreamRef2, gun:stream_info(ConnPid, StreamRef2)]),
+ Self = if
+ %% We do not currently keep reply_to after switch_protocol.
+ Proxy1 =/= h2, Proxy1 =/= h2c, (Proxy2 =:= http) orelse (Proxy2 =:= https) ->
+ undefined;
+ true ->
+ self()
+ end,
+ {Proxy1Transport, Proxy1Protocol} = do_type(Proxy1),
+ Proxy1Type = case Proxy1 of
+ socks5 -> socks5;
+ socks5tls -> socks5;
+ _ -> connect
+ end,
+ {OriginTransport, OriginProtocol} = do_type(Origin),
+ OriginScheme = case OriginTransport of
+ tcp -> <<"http">>;
+ tls -> <<"https">>
+ end,
+ {ok, #{
+ ref := StreamRef2,
+ reply_to := Self,
+ state := running,
+ intermediaries := [#{
+ type := Proxy1Type,
+ host := "localhost",
+ port := Proxy1Port,
+ transport := Proxy1Transport,
+ protocol := Proxy1Protocol
+ }],
+ tunnel := #{
+ transport := OriginTransport,
+ protocol := OriginProtocol,
+ origin_scheme := OriginScheme,
+ origin_host := "localhost",
+ origin_port := OriginPort
+ }
+ }} = gun:stream_info(ConnPid, StreamRef2),
+ ok.
+
+do_origin_stream_info(#st{origin=Type}, _, _)
+ when Type =:= raw; Type =:= rawtls ->
+ ok;
+do_origin_stream_info(#st{proxy1=Proxy1, proxy1_port=Proxy1Port,
+ proxy2=Proxy2, proxy2_port=Proxy2Port}, ConnPid, StreamRef3) ->
+ ct:log("3: ~p~n~p", [StreamRef3, gun:stream_info(ConnPid, StreamRef3)]),
+ {Proxy1Transport, Proxy1Protocol} = do_type(Proxy1),
+ Proxy1Type = case Proxy1 of
+ socks5 -> socks5;
+ socks5tls -> socks5;
+ _ -> connect
+ end,
+ {Proxy2Transport, Proxy2Protocol} = do_type(Proxy2),
+ Proxy2Type = case Proxy2 of
+ socks5 -> socks5;
+ socks5tls -> socks5;
+ _ -> connect
+ end,
+ {ok, #{
+ ref := StreamRef3,
+ reply_to := _, %% @todo
+ state := running,
+ intermediaries := [#{
+ type := Proxy1Type,
+ host := "localhost",
+ port := Proxy1Port,
+ transport := Proxy1Transport,
+ protocol := Proxy1Protocol
+ }, #{
+ type := Proxy2Type,
+ host := "localhost",
+ port := Proxy2Port,
+ transport := Proxy2Transport,
+ protocol := Proxy2Protocol
+ }]
+ }} = gun:stream_info(ConnPid, StreamRef3),
+ ok.
+
+do_info(#st{
+ proxy1=Proxy1, proxy1_port=Proxy1Port,
+ proxy2=Proxy2, proxy2_port=Proxy2Port,
+ origin=Origin, origin_port=OriginPort
+ }, ConnPid) ->
+ {Proxy1Transport, Proxy1Protocol} = do_type(Proxy1),
+ Proxy1Type = case Proxy1Protocol of
+ socks -> socks5;
+ _ -> connect
+ end,
+ {Proxy2Transport, Proxy2Protocol} = do_type(Proxy2),
+ Proxy2Type = case Proxy2Protocol of
+ socks -> socks5;
+ _ -> connect
+ end,
+ Intermediary1 = #{
+ type => Proxy1Type,
+ host => "localhost",
+ port => Proxy1Port,
+ transport => Proxy1Transport,
+ protocol => Proxy1Protocol
+ },
+ Intermediary2 = #{
+ type => Proxy2Type,
+ host => "localhost",
+ port => Proxy2Port,
+ transport => Proxy2Transport,
+ protocol => Proxy2Protocol
+ },
+ %% There are no connection-wide intermediaries for HTTP/2.
+ Intermediaries = case {Proxy1Protocol, Proxy2Protocol} of
+ {http2, _} -> [];
+ {_, http2} -> [Intermediary1];
+ _ -> [Intermediary1, Intermediary2]
+ end,
+ %% The transport, protocol, scheme and port of the origin
+ %% will also vary depending on where we started using HTTP/2 CONNECT.
+ %% In that case the connection-wide origin is the first HTTP/2 endpoint.
+ {OriginTransport, OriginProtocol} = do_type(Origin),
+ {InfoTransport, InfoProtocol, InfoPort} = case {Proxy1Protocol, Proxy2Protocol} of
+ {http2, _} -> {Proxy1Transport, Proxy1Protocol, Proxy1Port};
+ {_, http2} -> {Proxy2Transport, Proxy2Protocol, Proxy2Port};
+ _ -> {OriginTransport, OriginProtocol, OriginPort}
+ end,
+ InfoScheme = case {InfoTransport, InfoProtocol} of
+ {_, raw} -> undefined;
+ {tcp, _} -> <<"http">>;
+ {tls, _} -> <<"https">>
+ end,
+ #{
+ transport := InfoTransport,
+ protocol := InfoProtocol,
+ origin_scheme := InfoScheme,
+ origin_host := "localhost",
+ origin_port := InfoPort,
+ intermediaries := Intermediaries
+ } = gun:info(ConnPid),
+ ok.
+
+do_type(http) -> {tcp, http};
+do_type(https) -> {tls, http};
+do_type(h2c) -> {tcp, http2};
+do_type(h2) -> {tls, http2};
+do_type(socks5) -> {tcp, socks};
+do_type(socks5tls) -> {tls, socks};
+do_type(raw) -> {tcp, raw};
+do_type(rawtls) -> {tls, raw}.