aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2019-04-22 13:40:07 +0200
committerLoïc Hoguin <[email protected]>2019-04-22 13:40:07 +0200
commit5e3a5337a34dcb09418d4f412b11ede4510e3ddc (patch)
tree294fde46b7b0775ce62c854892ddcf1c4a73ead2
parentb2aed85a2a8794f0cc23755d1a10c602ab289ff4 (diff)
downloadgun-5e3a5337a34dcb09418d4f412b11ede4510e3ddc.tar.gz
gun-5e3a5337a34dcb09418d4f412b11ede4510e3ddc.tar.bz2
gun-5e3a5337a34dcb09418d4f412b11ede4510e3ddc.zip
Make gun_tls_proxy work for HTTP/2 connections
-rw-r--r--src/gun.erl6
-rw-r--r--src/gun_http.erl6
-rw-r--r--src/gun_http2.erl1
-rw-r--r--src/gun_tls_proxy.erl7
-rw-r--r--test/rfc7231_SUITE.erl28
5 files changed, 35 insertions, 13 deletions
diff --git a/src/gun.erl b/src/gun.erl
index 2f023e1..e86d73e 100644
--- a/src/gun.erl
+++ b/src/gun.erl
@@ -821,6 +821,12 @@ connected(cast, {connect, ReplyTo, StreamRef, Destination0, Headers},
end,
ProtoState2 = Protocol:connect(ProtoState, StreamRef, ReplyTo, Destination, Headers),
{keep_state, State#state{protocol_state=ProtoState2}};
+%% When using gun_tls_proxy we need a separate message to know whether
+%% we need to switch to a different protocol.
+connected(info, {connect_protocol, Protocol}, #state{protocol=Protocol}) ->
+ keep_state_and_data;
+connected(info, {connect_protocol, Protocol}, State=#state{protocol_state=ProtoState}) ->
+ commands([{switch_protocol, Protocol, ProtoState}], State);
connected(cast, {cancel, ReplyTo, StreamRef},
State=#state{protocol=Protocol, protocol_state=ProtoState}) ->
ProtoState2 = Protocol:cancel(ProtoState, StreamRef, ReplyTo),
diff --git a/src/gun_http.erl b/src/gun_http.erl
index efcea35..02344ee 100644
--- a/src/gun_http.erl
+++ b/src/gun_http.erl
@@ -231,12 +231,12 @@ handle_head(Data, State=#http_state{socket=Socket, transport=Transport,
TLSTimeout = maps:get(tls_handshake_timeout, Destination, infinity),
{ok, ProxyPid} = gun_tls_proxy:start_link(NewHost, NewPort,
TLSOpts, TLSTimeout, Socket, gun_tls),
+ %% In this case the switch_protocol is delayed and is handled by
+ %% a message sent from gun_tls_proxy once the connection is established,
+ %% and handled by the gun module directly.
[{state, State2#http_state{socket=ProxyPid, transport=gun_tls_proxy}},
{origin, <<"https">>, NewHost, NewPort, connect},
{switch_transport, gun_tls_proxy, ProxyPid}];
- %% @todo Might also need to switch protocol, but gotta wait
- %% @todo for the TLS connection to be established first.
- %% @todo Should have a gun_tls_proxy event indicating connection success.
#{transport := tls} ->
TLSOpts = maps:get(tls_opts, Destination, []),
TLSTimeout = maps:get(tls_handshake_timeout, Destination, infinity),
diff --git a/src/gun_http2.erl b/src/gun_http2.erl
index 8072a00..1dd2a75 100644
--- a/src/gun_http2.erl
+++ b/src/gun_http2.erl
@@ -285,6 +285,7 @@ prepare_headers(#http2_state{transport=Transport}, Method, Host0, Port, Path, He
method => Method,
scheme => case Transport of
gun_tls -> <<"https">>;
+ gun_tls_proxy -> <<"https">>;
gun_tcp -> <<"http">>
end,
authority => Authority,
diff --git a/src/gun_tls_proxy.erl b/src/gun_tls_proxy.erl
index 8adb5b6..123a156 100644
--- a/src/gun_tls_proxy.erl
+++ b/src/gun_tls_proxy.erl
@@ -222,8 +222,13 @@ not_connected({call, _}, Msg={send, _}, State) ->
not_connected(cast, Msg={setopts, _}, State) ->
?DEBUG_LOG("postpone ~0p state ~0p", [Msg, State]),
{keep_state_and_data, postpone};
-not_connected(cast, Msg={connect_proc, {ok, Socket}}, State) ->
+not_connected(cast, Msg={connect_proc, {ok, Socket}}, State=#state{owner_pid=OwnerPid}) ->
?DEBUG_LOG("msg ~0p state ~0p", [Msg, State]),
+ Protocol = case ssl:negotiated_protocol(Socket) of
+ {ok, <<"h2">>} -> gun_http2;
+ _ -> gun_http
+ end,
+ OwnerPid ! {connect_protocol, Protocol},
ok = ssl:setopts(Socket, [{active, true}]),
{next_state, connected, State#state{proxy_socket=Socket}};
not_connected(cast, Msg={connect_proc, Error}, State) ->
diff --git a/test/rfc7231_SUITE.erl b/test/rfc7231_SUITE.erl
index cbace9b..c9bd3b4 100644
--- a/test/rfc7231_SUITE.erl
+++ b/test/rfc7231_SUITE.erl
@@ -176,23 +176,33 @@ do_connect_http(OriginTransport, ProxyTransport) ->
connect_h2c(_) ->
doc("CONNECT can be used to establish a TCP connection "
"to an HTTP/2 server via an HTTP proxy. (RFC7231 4.3.6)"),
- do_connect_h2(tcp).
+ do_connect_h2(tcp, tcp).
connect_h2(_) ->
doc("CONNECT can be used to establish a TLS connection "
"to an HTTP/2 server via an HTTP proxy. (RFC7231 4.3.6)"),
- do_connect_h2(tls).
+ do_connect_h2(tls, tcp).
-do_connect_h2(Transport) ->
- {ok, OriginPid, OriginPort} = init_origin(Transport, http2),
- {ok, ProxyPid, ProxyPort} = do_proxy_start(tcp),
+connect_h2c_over_https_proxy(_) ->
+ doc("CONNECT can be used to establish a TCP connection "
+ "to an HTTP/2 server via an HTTPS proxy. (RFC7231 4.3.6)"),
+ do_connect_h2(tcp, tls).
+
+connect_h2_over_https_proxy(_) ->
+ doc("CONNECT can be used to establish a TLS connection "
+ "to an HTTP/2 server via an HTTPS proxy. (RFC7231 4.3.6)"),
+ do_connect_h2(tls, tls).
+
+do_connect_h2(OriginTransport, ProxyTransport) ->
+ {ok, OriginPid, OriginPort} = init_origin(OriginTransport, http2),
+ {ok, ProxyPid, ProxyPort} = do_proxy_start(ProxyTransport),
Authority = iolist_to_binary(["localhost:", integer_to_binary(OriginPort)]),
- {ok, ConnPid} = gun:open("localhost", ProxyPort),
+ {ok, ConnPid} = gun:open("localhost", ProxyPort, #{transport => ProxyTransport}),
{ok, http} = gun:await_up(ConnPid),
StreamRef = gun:connect(ConnPid, #{
host => "localhost",
port => OriginPort,
- transport => Transport,
+ transport => OriginTransport,
protocols => [http2]
}),
{request, <<"CONNECT">>, Authority, 'HTTP/1.1', _} = receive_from(ProxyPid),
@@ -201,7 +211,7 @@ do_connect_h2(Transport) ->
_ = gun:get(ConnPid, "/proxied"),
<<_:24, 1:8, _/bits>> = receive_from(OriginPid),
#{
- transport := Transport,
+ transport := OriginTransport,
protocol := http2,
origin_host := "localhost",
origin_port := OriginPort,
@@ -209,7 +219,7 @@ do_connect_h2(Transport) ->
type := connect,
host := "localhost",
port := ProxyPort,
- transport := tcp,
+ transport := ProxyTransport,
protocol := http
}]} = gun:info(ConnPid),
gun:close(ConnPid).