aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2020-07-20 15:01:36 +0200
committerLoïc Hoguin <[email protected]>2020-09-21 15:51:56 +0200
commitf8272a1e8d5fbf3b8021479d142a2002846fe062 (patch)
tree3a67b6548bacab4eb356c39e53375d4f29dc8976 /test
parentd7481d5f593f48327d16c29b48a74e49c7581e0a (diff)
downloadgun-f8272a1e8d5fbf3b8021479d142a2002846fe062.tar.gz
gun-f8272a1e8d5fbf3b8021479d142a2002846fe062.tar.bz2
gun-f8272a1e8d5fbf3b8021479d142a2002846fe062.zip
HTTP/2 over HTTP/2 CONNECT
Diffstat (limited to 'test')
-rw-r--r--test/raw_SUITE.erl114
-rw-r--r--test/rfc7540_SUITE.erl56
2 files changed, 102 insertions, 68 deletions
diff --git a/test/raw_SUITE.erl b/test/raw_SUITE.erl
index 29717e6..3d17357 100644
--- a/test/raw_SUITE.erl
+++ b/test/raw_SUITE.erl
@@ -186,63 +186,6 @@ connect_raw_reply_to(_) ->
gun:data(ConnPid, undefined, nofin, <<"Hello world!">>),
receive {ReplyTo, ok} -> gun:close(ConnPid) after 1000 -> error(timeout) end.
-h2_connect_tcp_raw_tcp(_) ->
- doc("Use CONNECT over clear HTTP/2 to connect to a remote endpoint using the raw protocol over TCP."),
- do_h2_connect_raw(tcp, <<"http">>, tcp).
-
-h2_connect_tls_raw_tcp(_) ->
- doc("Use CONNECT over secure HTTP/2 to connect to a remote endpoint using the raw protocol over TCP."),
- do_h2_connect_raw(tcp, <<"https">>, tls).
-
-do_h2_connect_raw(OriginTransport, ProxyScheme, ProxyTransport) ->
- {ok, OriginPid, OriginPort} = init_origin(OriginTransport, raw, fun do_echo/3),
- {ok, ProxyPid, ProxyPort} = rfc7540_SUITE:do_proxy_start(ProxyTransport, [
- {proxy_stream, 1, 200, [], 0, undefined}
- ]),
- Authority = iolist_to_binary(["localhost:", integer_to_binary(OriginPort)]),
- {ok, ConnPid} = gun:open("localhost", ProxyPort, #{
- transport => ProxyTransport,
- protocols => [http2]
- }),
- {ok, http2} = gun:await_up(ConnPid),
- handshake_completed = receive_from(ProxyPid),
- StreamRef = gun:connect(ConnPid, #{
- host => "localhost",
- port => OriginPort,
- transport => OriginTransport,
- protocols => [raw]
- }),
- {request, #{
- <<":method">> := <<"CONNECT">>,
- <<":authority">> := Authority
- }} = receive_from(ProxyPid),
- {response, nofin, 200, _} = gun:await(ConnPid, StreamRef),
- handshake_completed = receive_from(OriginPid),
- gun:data(ConnPid, StreamRef, nofin, <<"Hello world!">>),
- {data, nofin, <<"Hello world!">>} = gun:await(ConnPid, StreamRef),
- #{
- transport := ProxyTransport,
- protocol := http2,
- origin_scheme := ProxyScheme,
- origin_host := "localhost",
- origin_port := ProxyPort,
- intermediaries := []
- } = gun:info(ConnPid),
- Self = self(),
- {ok, #{
- ref := StreamRef,
- reply_to := Self,
- state := running,
- tunnel := #{
- transport := OriginTransport,
- protocol := raw,
- origin_scheme := _, %% @todo This should be 'undefined'.
- origin_host := "localhost",
- origin_port := OriginPort
- }
- }} = gun:stream_info(ConnPid, StreamRef),
- gun:close(ConnPid).
-
http11_upgrade_raw_tcp(_) ->
doc("Use the HTTP Upgrade mechanism to switch to the raw protocol over TCP."),
do_http11_upgrade_raw(tcp).
@@ -320,6 +263,63 @@ http11_upgrade_raw_reply_to(_) ->
gun:data(ConnPid, undefined, nofin, <<"Hello world!">>),
receive {ReplyTo, ok} -> gun:close(ConnPid) after 1000 -> error(timeout) end.
+http2_connect_tcp_raw_tcp(_) ->
+ doc("Use CONNECT over clear HTTP/2 to connect to a remote endpoint using the raw protocol over TCP."),
+ do_http2_connect_raw(tcp, <<"http">>, tcp).
+
+http2_connect_tls_raw_tcp(_) ->
+ doc("Use CONNECT over secure HTTP/2 to connect to a remote endpoint using the raw protocol over TCP."),
+ do_http2_connect_raw(tcp, <<"https">>, tls).
+
+do_http2_connect_raw(OriginTransport, ProxyScheme, ProxyTransport) ->
+ {ok, OriginPid, OriginPort} = init_origin(OriginTransport, raw, fun do_echo/3),
+ {ok, ProxyPid, ProxyPort} = rfc7540_SUITE:do_proxy_start(ProxyTransport, [
+ {proxy_stream, 1, 200, [], 0, undefined}
+ ]),
+ Authority = iolist_to_binary(["localhost:", integer_to_binary(OriginPort)]),
+ {ok, ConnPid} = gun:open("localhost", ProxyPort, #{
+ transport => ProxyTransport,
+ protocols => [http2]
+ }),
+ {ok, http2} = gun:await_up(ConnPid),
+ handshake_completed = receive_from(ProxyPid),
+ StreamRef = gun:connect(ConnPid, #{
+ host => "localhost",
+ port => OriginPort,
+ transport => OriginTransport,
+ protocols => [raw]
+ }),
+ {request, #{
+ <<":method">> := <<"CONNECT">>,
+ <<":authority">> := Authority
+ }} = receive_from(ProxyPid),
+ {response, nofin, 200, _} = gun:await(ConnPid, StreamRef),
+ handshake_completed = receive_from(OriginPid),
+ gun:data(ConnPid, StreamRef, nofin, <<"Hello world!">>),
+ {data, nofin, <<"Hello world!">>} = gun:await(ConnPid, StreamRef),
+ #{
+ transport := ProxyTransport,
+ protocol := http2,
+ origin_scheme := ProxyScheme,
+ origin_host := "localhost",
+ origin_port := ProxyPort,
+ intermediaries := []
+ } = gun:info(ConnPid),
+ Self = self(),
+ {ok, #{
+ ref := StreamRef,
+ reply_to := Self,
+ state := running,
+ tunnel := #{
+ transport := OriginTransport,
+ protocol := raw,
+ origin_scheme := _, %% @todo This should be 'undefined'.
+ origin_host := "localhost",
+ origin_port := OriginPort
+ }
+ }} = gun:stream_info(ConnPid, StreamRef),
+ gun:close(ConnPid).
+
%% The origin server will echo everything back.
do_echo(Parent, ClientSocket, ClientTransport) ->
diff --git a/test/rfc7540_SUITE.erl b/test/rfc7540_SUITE.erl
index ac36ee6..b171fa2 100644
--- a/test/rfc7540_SUITE.erl
+++ b/test/rfc7540_SUITE.erl
@@ -430,18 +430,53 @@ settings_ack_timeout(_) ->
timer:sleep(6000),
gun:close(ConnPid).
-connect_http(_) ->
+connect_http_via_h2c(_) ->
doc("CONNECT can be used to establish a TCP connection "
"to an HTTP/1.1 server via a TCP HTTP/2 proxy. (RFC7540 8.3)"),
- do_connect_http(<<"http">>, tcp, <<"http">>, tcp).
+ do_connect_http(<<"http">>, tcp, http, <<"http">>, tcp).
-connect_https(_) ->
+connect_http_via_h2(_) ->
doc("CONNECT can be used to establish a TCP connection "
"to an HTTP/1.1 server via a TLS HTTP/2 proxy. (RFC7540 8.3)"),
- do_connect_http(<<"http">>, tcp, <<"https">>, tls).
+ do_connect_http(<<"http">>, tcp, http, <<"https">>, tls).
-do_connect_http(OriginScheme, OriginTransport, ProxyScheme, ProxyTransport) ->
- {ok, OriginPid, OriginPort} = init_origin(OriginTransport, http),
+connect_h2c_via_h2c(_) ->
+ doc("CONNECT can be used to establish a TCP connection "
+ "to an HTTP/2 server via a TCP HTTP/2 proxy. (RFC7540 8.3)"),
+ do_connect_http(<<"http">>, tcp, http2, <<"http">>, tcp).
+
+connect_h2c_via_h2(_) ->
+ doc("CONNECT can be used to establish a TCP connection "
+ "to an HTTP/2 server via a TLS HTTP/2 proxy. (RFC7540 8.3)"),
+ do_connect_http(<<"http">>, tcp, http2, <<"https">>, tls).
+
+do_origin_fun(http) ->
+ fun(Parent, Socket, Transport) ->
+ %% Receive the request-line and headers, parse and send them.
+ {ok, Data} = Transport:recv(Socket, 0, 5000),
+ {Method, Target, 'HTTP/1.1', Rest} = cow_http:parse_request_line(Data),
+ {Headers0, _} = cow_http:parse_headers(Rest),
+ Headers = maps:from_list(Headers0),
+ %% We roughly transform the HTTP/1.1 headers into HTTP/2 format.
+ Parent ! {self(), Headers#{
+ <<":authority">> => maps:get(<<"host">>, Headers, <<>>),
+ <<":method">> => Method,
+ <<":path">> => Target
+ }},
+ gun_test:loop_origin(Parent, Socket, Transport)
+ end;
+do_origin_fun(http2) ->
+ fun(Parent, Socket, Transport) ->
+ %% Receive the HEADERS frame and send the headers decoded.
+ {ok, <<Len:24, 1:8, _:8, 1:32>>} = Transport:recv(Socket, 9, 1000),
+ {ok, ReqHeadersBlock} = Transport:recv(Socket, Len, 1000),
+ {ReqHeaders, _} = cow_hpack:decode(ReqHeadersBlock),
+ Parent ! {self(), maps:from_list(ReqHeaders)},
+ gun_test:loop_origin(Parent, Socket, Transport)
+ end.
+
+do_connect_http(OriginScheme, OriginTransport, OriginProtocol, ProxyScheme, ProxyTransport) ->
+ {ok, OriginPid, OriginPort} = init_origin(OriginTransport, OriginProtocol, do_origin_fun(OriginProtocol)),
{ok, ProxyPid, ProxyPort} = do_proxy_start(ProxyTransport, [
#proxy_stream{id=1, status=200}
]),
@@ -455,7 +490,8 @@ do_connect_http(OriginScheme, OriginTransport, ProxyScheme, ProxyTransport) ->
StreamRef = gun:connect(ConnPid, #{
host => "localhost",
port => OriginPort,
- transport => OriginTransport
+ transport => OriginTransport,
+ protocols => [OriginProtocol]
}),
{request, #{
<<":method">> := <<"CONNECT">>,
@@ -464,9 +500,7 @@ do_connect_http(OriginScheme, OriginTransport, ProxyScheme, ProxyTransport) ->
{response, nofin, 200, _} = gun:await(ConnPid, StreamRef),
handshake_completed = receive_from(OriginPid),
ProxiedStreamRef = gun:get(ConnPid, "/proxied", #{}, #{tunnel => StreamRef}),
- Data = receive_from(OriginPid),
- Lines = binary:split(Data, <<"\r\n">>, [global]),
- [<<"host: ", Authority/bits>>] = [L || <<"host: ", _/bits>> = L <- Lines],
+ #{<<":authority">> := Authority} = receive_from(OriginPid),
#{
transport := ProxyTransport,
protocol := http2,
@@ -481,7 +515,7 @@ do_connect_http(OriginScheme, OriginTransport, ProxyScheme, ProxyTransport) ->
state := running,
tunnel := #{
transport := OriginTransport,
- protocol := http,
+ protocol := OriginProtocol,
origin_scheme := OriginScheme,
origin_host := "localhost",
origin_port := OriginPort