diff options
author | Loïc Hoguin <[email protected]> | 2020-07-20 15:01:36 +0200 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2020-09-21 15:51:56 +0200 |
commit | f8272a1e8d5fbf3b8021479d142a2002846fe062 (patch) | |
tree | 3a67b6548bacab4eb356c39e53375d4f29dc8976 /test | |
parent | d7481d5f593f48327d16c29b48a74e49c7581e0a (diff) | |
download | gun-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.erl | 114 | ||||
-rw-r--r-- | test/rfc7540_SUITE.erl | 56 |
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 |