aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2020-08-20 15:29:38 +0200
committerLoïc Hoguin <[email protected]>2020-09-21 15:51:57 +0200
commite1de84585490e85166926416e4eb5cea95e0e604 (patch)
treeac01fc5c8d98818eb82fa4d3415db472857c4990 /src
parentca68d184abbf7bd1030b2f2035cc66c13d08dd5d (diff)
downloadgun-e1de84585490e85166926416e4eb5cea95e0e604.tar.gz
gun-e1de84585490e85166926416e4eb5cea95e0e604.tar.bz2
gun-e1de84585490e85166926416e4eb5cea95e0e604.zip
Add gun_tunnel_up message to HTTP/2 CONNECT
Diffstat (limited to 'src')
-rw-r--r--src/gun.erl3
-rw-r--r--src/gun_http2.erl89
-rw-r--r--src/gun_tls_proxy.erl1
-rw-r--r--src/gun_tls_proxy_http2_connect.erl10
4 files changed, 14 insertions, 89 deletions
diff --git a/src/gun.erl b/src/gun.erl
index 24ec9c0..e83c709 100644
--- a/src/gun.erl
+++ b/src/gun.erl
@@ -724,7 +724,7 @@ await(ServerPid, StreamRef, Timeout, MRef) ->
{upgrade, Protocols, Headers};
{gun_ws, ServerPid, StreamRef, Frame} ->
{ws, Frame};
- {gun_socks_up, ServerPid, StreamRef, Protocol} ->
+ {gun_tunnel_up, ServerPid, StreamRef, Protocol} ->
{up, Protocol};
{gun_error, ServerPid, StreamRef, Reason} ->
{error, {stream_error, Reason}};
@@ -808,6 +808,7 @@ await_up(ServerPid, Timeout, MRef) ->
receive
{gun_up, ServerPid, Protocol} ->
{ok, Protocol};
+ %% @todo Maybe name it gun_tunnel_up. And send it for HTTP/1.1 CONNECT and HTTP/2 CONNECT and SOCKS.
{gun_socks_up, ServerPid, Protocol} ->
{ok, Protocol};
{'DOWN', MRef, process, ServerPid, Reason} ->
diff --git a/src/gun_http2.erl b/src/gun_http2.erl
index bd74957..da6747b 100644
--- a/src/gun_http2.erl
+++ b/src/gun_http2.erl
@@ -326,29 +326,9 @@ data_frame(State, StreamID, IsFin, Data, EvHandler, EvHandlerState0) ->
stream_ref => stream_ref(State, StreamRef)
},
ProxyPid ! {tls_proxy_http2_connect, OriginSocket, Data},
-io:format(user, "(~p) ~p:~p/~p: data ~p~n",
- [self(), ?MODULE, ?FUNCTION_NAME, ?FUNCTION_ARITY, Data]),
%% @todo What about IsFin?
{State, EvHandlerState0};
Stream=#stream{tunnel={Protocol, ProtoState0, TunnelInfo}} ->
- %% @todo Can't call Protocol:handle directly, may need to unwrap TLS first...
-
- %% in this case we know Transport is either gun_tcp_proxy or gun_tls_proxy
- %% if gun_tcp_proxy we can dispatch to Protocol:handle directly;
- %% otherwise we must pass the data to gun_tls_proxy
- %% -> send {ssl, Socket, Data}
- %% -> eventually Gun process receives {Tag, Socket, Data}
- %% -> somehow it needs to call this stream to resume processing and call Protocol:handle
-
- %% maybe {Tag, Socket, Data, Info} instead and Info is used to dispatch
- %% maybe {stream_Tag, StreamRef, Data}
- %% -> StreamRef to know which stream is the connect stream (potentially recursive)
- %% -> Protocol:resume_handle(Data, StreamRef, State, EvHandler, EvHandlerState)
- %% -> if reference() then we do Protocol:handle/4
- %% -> otherwise we pass to the next stream onward
-
- %% This means that #stream{} must contain both the user-facing StreamRef and the reference.
-
{Commands, EvHandlerState} = Protocol:handle(Data, ProtoState0, EvHandler, EvHandlerState0),
{tunnel_commands(Commands, Stream, Protocol, TunnelInfo, State), EvHandlerState}
end.
@@ -388,7 +368,7 @@ tunnel_commands([{switch_protocol, Protocol0, ReplyTo}|Tail], Stream=#stream{ref
end,
%% When we switch_protocol from socks we must send a gun_socks_up message.
_ = case CurrentProtocol of
- gun_socks -> ReplyTo ! {gun_socks_up, self(), stream_ref(State, StreamRef), Protocol:name()};
+ gun_socks -> ReplyTo ! {gun_tunnel_up, self(), stream_ref(State, StreamRef), Protocol:name()};
_ -> ok
end,
OriginSocket = #{
@@ -524,6 +504,7 @@ headers_frame(State0=#http2_state{content_handlers=Handlers0, commands_queue=Com
{_, ProtoState} = Protocol:init(ReplyTo, OriginSocket, gun_tcp_proxy, ProtoOpts#{stream_ref => RealStreamRef}),
%% @todo EvHandlerState = EvHandler:protocol_changed(#{protocol => Protocol:name()}, EvHandlerState0),
%% @todo What about keepalive?
+ ReplyTo ! {gun_tunnel_up, self(), RealStreamRef, Protocol:name()},
{store_stream(State, Stream#stream{tunnel={Protocol, ProtoState,
TunnelInfo#{origin_host => DestHost, origin_port => DestPort}}}),
EvHandlerState}
@@ -653,6 +634,7 @@ handle_continue(StreamRef, Msg, State, EvHandler, EvHandlerState0)
end,
{_, ProtoState} = Protocol:init(ReplyTo, OriginSocket, gun_tcp_proxy,
ProtoOpts#{stream_ref => RealStreamRef}),
+ ReplyTo ! {gun_tunnel_up, self(), RealStreamRef, Protocol:name()},
{{state, store_stream(State, Stream#stream{tunnel={Protocol, ProtoState,
TunnelInfo#{origin_host => DestHost, origin_port => DestPort}}})},
EvHandlerState0};
@@ -681,8 +663,6 @@ handle_continue(StreamRef, Msg, State, EvHandler, EvHandlerState0)
case Msg of
%% Data that was received and decrypted.
{tls_proxy, ProxyPid, Data} ->
-io:format(user, "(~p) ~p:~p/~p: data ~p~n",
- [self(), ?MODULE, ?FUNCTION_NAME, ?FUNCTION_ARITY, Data]),
{Commands, EvHandlerState} = Protocol:handle(Data, ProtoState0, EvHandler, EvHandlerState0),
{tunnel_commands(Commands, Stream, Protocol, TunnelInfo, State), EvHandlerState};
%% @todo What to do about those?
@@ -691,38 +671,14 @@ io:format(user, "(~p) ~p:~p/~p: data ~p~n",
{tls_proxy_error, ProxyPid, _Reason} ->
todo;
%% Data that must be sent as a DATA frame.
- {data, ReplyTo, _, IsFin, Data} ->
+ {data, _, _, IsFin, Data} ->
{State1, EvHandlerState} = maybe_send_data(State, StreamID, IsFin, Data, EvHandler, EvHandlerState0),
{{state, State1}, EvHandlerState}
end
-
-
-% {store_stream(State, Stream#stream{tunnel={Proto, ProtoState, TunnelInfo}}), EvHandlerState}%;
- %% The stream may have ended while TLS was being decoded. @todo What should we do?
+%% @todo Is this possible?
% error ->
% {error_stream_not_found(State, StreamRef, ReplyTo), EvHandlerState0}
end;
-
-
-
-% [Protocol0] = maps:get(protocols, Destination, [http]),
-% %% Options are either passed directly or #{} is used. Since the
-% %% protocol only applies to a stream we cannot use connection-wide options.
-% {Protocol, ProtoOpts} = case Protocol0 of
-% {P, PO} -> {gun:protocol_handler(P), PO};
-% P -> {gun:protocol_handler(P), #{}}
-% end,
-% %% @todo What about the StateName returned?
-% {_, ProtoState} = Protocol:init(ReplyTo, OriginSocket, gun_tcp_proxy,
-% ProtoOpts#{stream_ref => RealStreamRef}),
-% %% @todo EvHandlerState = EvHandler:protocol_changed(#{protocol => Protocol:name()}, EvHandlerState0),
-% %% @todo What about keepalive?
-% {store_stream(State, Stream#stream{tunnel={Protocol, ProtoState,
-% TunnelInfo#{origin_host => DestHost, origin_port => DestPort}}}),
-% EvHandlerState}
-%
-%
-% todo;
%% Tunneled data.
handle_continue([StreamRef|Tail], Msg, State, EvHandler, EvHandlerState0) ->
case get_stream_by_ref(State, StreamRef) of
@@ -735,31 +691,6 @@ handle_continue([StreamRef|Tail], Msg, State, EvHandler, EvHandlerState0) ->
% {error_stream_not_found(State, StreamRef, ReplyTo), EvHandlerState0}
end.
-
-
-
-%data(State=#http2_state{http2_machine=HTTP2Machine}, StreamRef, ReplyTo, IsFin, Data,
-% EvHandler, EvHandlerState) when is_reference(StreamRef) ->
-% case get_stream_by_ref(State, StreamRef) of
-% #stream{id=StreamID} ->
-% case cow_http2_machine:get_stream_local_state(StreamID, HTTP2Machine) of
-% {ok, fin, _} ->
-% {error_stream_closed(State, StreamRef, ReplyTo), EvHandlerState};
-% {ok, _, fin} ->
-% {error_stream_closed(State, StreamRef, ReplyTo), EvHandlerState};
-% {ok, _, _} ->
-% maybe_send_data(State, StreamID, IsFin, Data, EvHandler, EvHandlerState)
-% end;
-% error ->
-% {error_stream_not_found(State, StreamRef, ReplyTo), EvHandlerState}
-% end;
-%%% Tunneled data.
-%data(State, [StreamRef|Tail], ReplyTo, IsFin, Data, EvHandler, EvHandlerState0) ->
-
-
-
-
-
update_flow(State, _ReplyTo, StreamRef, Inc) ->
case get_stream_by_ref(State, StreamRef) of
Stream=#stream{id=StreamID, flow=Flow0} ->
@@ -1030,16 +961,6 @@ data(State=#http2_state{http2_machine=HTTP2Machine}, StreamRef, ReplyTo, IsFin,
{ok, _, fin} ->
{error_stream_closed(State, StreamRef, ReplyTo), EvHandlerState};
{ok, _, _} ->
-io:format(user, "(~p) ~p:~p/~p: data ~p~n",
- [self(), ?MODULE, ?FUNCTION_NAME, ?FUNCTION_ARITY, Data]),
-
-%% @todo The data to be sent on the tunnel neeeds to be encrypted as well! So we need
-%% to have a different clause when we have a tunnel AND it has a tls_proxy_pid in TunnelInfo.
-%% But we would need to differentiate between the incoming data and the encrypted data so
-%% that we do not encrypt it in a loop.
-%%
-%% So I guess we need an handle_continue.
-
case Tunnel of
%% We need to encrypt the data before we can send it. We send it
%% directly to the gun_tls_proxy process and then
diff --git a/src/gun_tls_proxy.erl b/src/gun_tls_proxy.erl
index 35e83b1..ab394bd 100644
--- a/src/gun_tls_proxy.erl
+++ b/src/gun_tls_proxy.erl
@@ -95,7 +95,6 @@
extra :: any()
}).
--define(DEBUG_PROXY, 1).
-ifdef(DEBUG_PROXY).
-define(DEBUG_LOG(Format, Args),
io:format(user, "(~p) ~p:~p/~p:" ++ Format ++ "~n",
diff --git a/src/gun_tls_proxy_http2_connect.erl b/src/gun_tls_proxy_http2_connect.erl
index e70454a..c423571 100644
--- a/src/gun_tls_proxy_http2_connect.erl
+++ b/src/gun_tls_proxy_http2_connect.erl
@@ -24,14 +24,18 @@
-export([close/1]).
-type socket() :: #{
+ %% The pid of the Gun connection.
+ gun_pid := pid(),
+
+ %% The pid of the process that gets replies for this tunnel.
reply_to := pid(),
+
+ %% The full stream reference for this tunnel.
stream_ref := reference() | [reference()]
}.
name() -> tls_proxy_http2_connect.
-%% We need different message tags because the messages
-%% must be propagated to the right stream.
messages() -> {tls_proxy_http2_connect, tls_proxy_http2_connect_closed, tls_proxy_http2_connect_error}.
-spec connect(_, _, _) -> no_return().
@@ -49,7 +53,7 @@ send(#{gun_pid := GunPid, reply_to := ReplyTo, stream_ref := StreamRef}, Data) -
-spec setopts(_, _) -> no_return().
setopts(_, _) ->
-% error(not_implemented).
+ %% We send messages automatically regardless of active mode.
ok.
-spec sockname(_) -> no_return().