diff options
author | Loïc Hoguin <[email protected]> | 2020-08-20 15:29:38 +0200 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2020-09-21 15:51:57 +0200 |
commit | e1de84585490e85166926416e4eb5cea95e0e604 (patch) | |
tree | ac01fc5c8d98818eb82fa4d3415db472857c4990 /src | |
parent | ca68d184abbf7bd1030b2f2035cc66c13d08dd5d (diff) | |
download | gun-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.erl | 3 | ||||
-rw-r--r-- | src/gun_http2.erl | 89 | ||||
-rw-r--r-- | src/gun_tls_proxy.erl | 1 | ||||
-rw-r--r-- | src/gun_tls_proxy_http2_connect.erl | 10 |
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(). |