aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2019-09-20 17:14:35 +0200
committerLoïc Hoguin <[email protected]>2019-09-22 16:46:44 +0200
commit4664da8703d4a1d5225fd71e1fc3164f9441ff36 (patch)
tree56a15d5a41e7435086f69760e90dc4ce69de735a
parent07e79aa3a70546fe4419b94cbf41c38a6eb039a1 (diff)
downloadgun-4664da8703d4a1d5225fd71e1fc3164f9441ff36.tar.gz
gun-4664da8703d4a1d5225fd71e1fc3164f9441ff36.tar.bz2
gun-4664da8703d4a1d5225fd71e1fc3164f9441ff36.zip
Add more tests with two Socks5 proxies
We now properly support TCP across two TLS proxies, and TLS across two TCP/TLS proxies.
-rw-r--r--src/gun.erl27
-rw-r--r--src/gun_http.erl2
-rw-r--r--test/socks_SUITE.erl46
3 files changed, 52 insertions, 23 deletions
diff --git a/src/gun.erl b/src/gun.erl
index 93a8d40..c1a8be5 100644
--- a/src/gun.erl
+++ b/src/gun.erl
@@ -892,13 +892,14 @@ connecting(_, {retries, Retries, LookupInfo}, State=#state{opts=Opts,
EvHandlerState1 = EvHandler:connect_start(ConnectEvent, EvHandlerState0),
case gun_tcp:connect(LookupInfo, ConnectTimeout) of
{ok, Socket} when Transport =:= gun_tcp ->
- Protocol = case maps:get(protocols, Opts, [http]) of
- [{P, _}] -> P;
- [P] -> P
+ [Protocol] = maps:get(protocols, Opts, [http]),
+ ProtocolName = case Protocol of
+ {P, _} -> P;
+ P -> P
end,
EvHandlerState = EvHandler:connect_end(ConnectEvent#{
socket => Socket,
- protocol => Protocol
+ protocol => ProtocolName
}, EvHandlerState1),
{next_state, connected, State#state{event_handler_state=EvHandlerState},
{next_event, internal, {connected, Socket, Protocol}}};
@@ -943,7 +944,7 @@ ensure_alpn(Protocols0, TransOpts) ->
%% Normal TLS handshake.
tls_handshake(internal, {tls_handshake, HandshakeEvent, Protocols},
- State0=#state{socket=Socket, transport=gun_tcp, protocol=CurrentProtocol}) ->
+ State0=#state{socket=Socket, transport=gun_tcp}) ->
case normal_tls_handshake(Socket, State0, HandshakeEvent, Protocols) of
{ok, TLSSocket, NewProtocol, State} ->
commands([
@@ -971,9 +972,7 @@ tls_handshake(internal, {tls_handshake,
%% When using gun_tls_proxy we need a separate message to know whether
%% the handshake succeeded and whether we need to switch to a different protocol.
tls_handshake(info, {gun_tls_proxy, Socket, {ok, Negotiated}, {HandshakeEvent, Protocols}},
- State0=#state{socket=Socket, transport=Transport,
- protocol=CurrentProtocol, protocol_state=ProtoState0,
- event_handler=EvHandler, event_handler_state=EvHandlerState0}) ->
+ State0=#state{socket=Socket, event_handler=EvHandler, event_handler_state=EvHandlerState0}) ->
NewProtocol = protocol_negotiated(Negotiated, Protocols),
EvHandlerState = EvHandler:tls_handshake_end(HandshakeEvent#{
socket => Socket,
@@ -1014,7 +1013,7 @@ normal_tls_handshake(Socket, State=#state{event_handler=EvHandler, event_handler
protocol_negotiated({ok, <<"h2">>}, _) -> http2;
protocol_negotiated({ok, <<"http/1.1">>}, _) -> http;
-protocol_negotiated({error, protocol_not_negotiated}, [{socks, _}]) -> socks;
+protocol_negotiated({error, protocol_not_negotiated}, [Protocol]) -> Protocol;
protocol_negotiated({error, protocol_not_negotiated}, _) -> http.
connected_no_input(Type, Event, State) ->
@@ -1022,11 +1021,13 @@ connected_no_input(Type, Event, State) ->
connected(internal, {connected, Socket, Protocol0},
State0=#state{owner=Owner, opts=Opts, transport=Transport}) ->
- Protocol = protocol_handler(Protocol0),
%% Protocol options may have been given along the protocol name.
- ProtoOpts = case lists:keyfind(Protocol0, 1, maps:get(protocols, Opts, [http])) of
- {_, PO} -> PO;
- false -> maps:get(Protocol:opts_name(), Opts, #{})
+ {Protocol, ProtoOpts} = case Protocol0 of
+ {P, PO} ->
+ {protocol_handler(P), PO};
+ _ ->
+ P = protocol_handler(Protocol0),
+ {P, maps:get(P:opts_name(), Opts, #{})}
end,
{StateName, ProtoState} = Protocol:init(Owner, Socket, Transport, ProtoOpts),
Owner ! {gun_up, self(), Protocol:name()},
diff --git a/src/gun_http.erl b/src/gun_http.erl
index 44575bf..ce174ce 100644
--- a/src/gun_http.erl
+++ b/src/gun_http.erl
@@ -298,7 +298,7 @@ handle_head(Data, State=#http_state{version=ClientVersion, content_handlers=Hand
}, EvHandlerState0),
%% We expect there to be no additional data after the CONNECT response.
<<>> = Rest2,
- State2 = end_stream(State#http_state{streams=[Stream|Tail]}),
+ _ = end_stream(State#http_state{streams=[Stream|Tail]}),
NewHost = maps:get(host, Destination),
NewPort = maps:get(port, Destination),
Protocols = maps:get(protocols, Destination, [http]),
diff --git a/test/socks_SUITE.erl b/test/socks_SUITE.erl
index e565017..80a2796 100644
--- a/test/socks_SUITE.erl
+++ b/test/socks_SUITE.erl
@@ -258,21 +258,45 @@ do_socks5(OriginScheme, OriginTransport, OriginProtocol, ProxyTransport, SocksAu
}]} = gun:info(ConnPid),
gun:close(ConnPid).
-socks5_through_multiple_proxies(_) ->
+socks5_tcp_through_multiple_tcp_proxies(_) ->
doc("Gun can be used to establish a TCP connection "
"to an HTTP/1.1 server via a tunnel going through "
- "two separate Socks5 proxies."),
- {ok, OriginPid, OriginPort} = init_origin(tcp, http),
- {ok, Proxy1Pid, Proxy1Port} = do_proxy_start(tcp, none),
- {ok, Proxy2Pid, Proxy2Port} = do_proxy_start(tcp, none),
+ "two separate TCP Socks5 proxies."),
+ do_socks5_through_multiple_proxies(tcp, tcp).
+
+socks5_tcp_through_multiple_tls_proxies(_) ->
+ doc("Gun can be used to establish a TCP connection "
+ "to an HTTP/1.1 server via a tunnel going through "
+ "two separate TLS Socks5 proxies."),
+ do_socks5_through_multiple_proxies(tcp, tls).
+
+socks5_tls_through_multiple_tcp_proxies(_) ->
+ doc("Gun can be used to establish a TLS connection "
+ "to an HTTP/1.1 server via a tunnel going through "
+ "two separate TCP Socks5 proxies."),
+ do_socks5_through_multiple_proxies(tcp, tcp).
+
+socks5_tls_through_multiple_tls_proxies(_) ->
+ doc("Gun can be used to establish a TLS connection "
+ "to an HTTP/1.1 server via a tunnel going through "
+ "two separate TLS Socks5 proxies."),
+ do_socks5_through_multiple_proxies(tcp, tls).
+
+do_socks5_through_multiple_proxies(OriginTransport, ProxyTransport) ->
+ {ok, OriginPid, OriginPort} = init_origin(OriginTransport, http),
+ {ok, Proxy1Pid, Proxy1Port} = do_proxy_start(ProxyTransport, none),
+ {ok, Proxy2Pid, Proxy2Port} = do_proxy_start(ProxyTransport, none),
Authority = iolist_to_binary(["localhost:", integer_to_binary(OriginPort)]),
{ok, ConnPid} = gun:open("localhost", Proxy1Port, #{
+ transport => ProxyTransport,
protocols => [{socks, #{
host => "localhost",
port => Proxy2Port,
+ transport => ProxyTransport,
protocols => [{socks, #{
host => "localhost",
- port => OriginPort
+ port => OriginPort,
+ transport => OriginTransport
}}]
}}]
}),
@@ -291,8 +315,12 @@ socks5_through_multiple_proxies(_) ->
Data = receive_from(OriginPid),
Lines = binary:split(Data, <<"\r\n">>, [global]),
[<<"host: ", Authority/bits>>] = [L || <<"host: ", _/bits>> = L <- Lines],
+ Proxy2Transport = case ProxyTransport of
+ tcp -> tcp;
+ tls -> tls_proxy
+ end,
#{
- transport := tcp,
+ transport := OriginTransport,
protocol := http,
origin_scheme := <<"http">>,
origin_host := "localhost",
@@ -301,13 +329,13 @@ socks5_through_multiple_proxies(_) ->
type := socks5,
host := "localhost",
port := Proxy1Port,
- transport := tcp,
+ transport := ProxyTransport,
protocol := socks
}, #{
type := socks5,
host := "localhost",
port := Proxy2Port,
- transport := tcp,
+ transport := Proxy2Transport,
protocol := socks
}]} = gun:info(ConnPid),
gun:close(ConnPid).