aboutsummaryrefslogtreecommitdiffstats
path: root/src/gun.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/gun.erl')
-rw-r--r--src/gun.erl109
1 files changed, 61 insertions, 48 deletions
diff --git a/src/gun.erl b/src/gun.erl
index 73779c2..177d395 100644
--- a/src/gun.erl
+++ b/src/gun.erl
@@ -1242,10 +1242,14 @@ connected(internal, {connected, Socket, NewProtocol},
{Protocol, ProtoOpts} = gun_protocols:handler_and_opts(NewProtocol, Opts),
{StateName, ProtoState} = Protocol:init(Owner, Socket, Transport, ProtoOpts),
Owner ! {gun_up, self(), Protocol:name()},
- State = active(State0#state{socket=Socket, protocol=Protocol, protocol_state=ProtoState}),
- case Protocol:has_keepalive() of
- true -> {next_state, StateName, keepalive_timeout(State)};
- false -> {next_state, StateName, State}
+ case active(State0#state{socket=Socket, protocol=Protocol, protocol_state=ProtoState}) of
+ {ok, State} ->
+ case Protocol:has_keepalive() of
+ true -> {next_state, StateName, keepalive_timeout(State)};
+ false -> {next_state, StateName, State}
+ end;
+ Disconnect ->
+ Disconnect
end;
%% Public HTTP interface.
%%
@@ -1380,14 +1384,7 @@ handle_common_connected_no_input(info, {OK, Socket, Data}, _,
protocol=Protocol, protocol_state=ProtoState,
event_handler=EvHandler, event_handler_state=EvHandlerState0}) ->
{Commands, EvHandlerState} = Protocol:handle(Data, ProtoState, EvHandler, EvHandlerState0),
- case commands(Commands, State0#state{event_handler_state=EvHandlerState}) of
- {keep_state, State} ->
- {keep_state, active(State)};
- {next_state, closing, State, Actions} ->
- {next_state, closing, active(State), Actions};
- Res ->
- Res
- end;
+ maybe_active(commands(Commands, State0#state{event_handler_state=EvHandlerState}));
handle_common_connected_no_input(info, {Closed, Socket}, _,
State=#state{socket=Socket, messages={_, Closed, _}}) ->
disconnect(State, closed);
@@ -1403,28 +1400,14 @@ handle_common_connected_no_input(info,
{Commands, EvHandlerState} = Protocol:handle_continue(
dereference_stream_ref(StreamRef, State0),
Msg, ProtoState, EvHandler, EvHandlerState0),
- case commands(Commands, State0#state{event_handler_state=EvHandlerState}) of
- {keep_state, State} ->
- {keep_state, active(State)};
- {next_state, closing, State, Actions} ->
- {next_state, closing, active(State), Actions};
- Res ->
- Res
- end;
+ maybe_active(commands(Commands, State0#state{event_handler_state=EvHandlerState}));
handle_common_connected_no_input(info, {handle_continue, StreamRef, Msg}, _,
State0=#state{protocol=Protocol, protocol_state=ProtoState,
event_handler=EvHandler, event_handler_state=EvHandlerState0}) ->
{Commands, EvHandlerState} = Protocol:handle_continue(
dereference_stream_ref(StreamRef, State0),
Msg, ProtoState, EvHandler, EvHandlerState0),
- case commands(Commands, State0#state{event_handler_state=EvHandlerState}) of
- {keep_state, State} ->
- {keep_state, active(State)};
- {next_state, closing, State, Actions} ->
- {next_state, closing, active(State), Actions};
- Res ->
- Res
- end;
+ maybe_active(commands(Commands, State0#state{event_handler_state=EvHandlerState}));
%% Timeouts.
%% @todo HTTP/2 requires more timeouts than just the keepalive timeout.
%% We should have a timeout function in protocols that deal with
@@ -1438,12 +1421,7 @@ handle_common_connected_no_input(info, keepalive, _,
handle_common_connected_no_input(cast, {update_flow, ReplyTo, StreamRef, Flow}, _,
State0=#state{protocol=Protocol, protocol_state=ProtoState}) ->
Commands = Protocol:update_flow(ProtoState, ReplyTo, StreamRef, Flow),
- case commands(Commands, State0) of
- {keep_state, State} ->
- {keep_state, active(State)};
- Res ->
- Res
- end;
+ maybe_active(commands(Commands, State0));
handle_common_connected_no_input(cast, {cancel, ReplyTo, StreamRef}, _,
State=#state{protocol=Protocol, protocol_state=ProtoState,
event_handler=EvHandler, event_handler_state=EvHandlerState0}) ->
@@ -1504,6 +1482,35 @@ handle_common_connected_no_input({call, From}, {stream_info, StreamRef}, _,
handle_common_connected_no_input(Type, Event, StateName, State) ->
handle_common(Type, Event, StateName, State).
+maybe_active({keep_state, State0}) ->
+ case active(State0) of
+ {ok, State} ->
+ {keep_state, State};
+ Disconnect ->
+ Disconnect
+ end;
+maybe_active({next_state, closing, State0, Actions}) ->
+ case active(State0) of
+ {ok, State} ->
+ {next_state, closing, State, Actions};
+ Disconnect ->
+ Disconnect
+ end;
+maybe_active(Other) ->
+ Other.
+
+active(State=#state{active=false}) ->
+ {ok, State};
+active(State=#state{socket=Socket, transport=Transport}) ->
+ case Transport:setopts(Socket, [{active, once}]) of
+ ok ->
+ {ok, State};
+ {error, closed} ->
+ disconnect(State, closed);
+ Error = {error, _} ->
+ disconnect(State, Error)
+ end.
+
tunnel_info_from_intermediaries(State, Tail) ->
case Tail of
%% If the next endpoint is an intermediary take its infos.
@@ -1679,11 +1686,17 @@ commands([{origin, Scheme, Host, Port, Type}|Tail],
commands(Tail, State#state{origin_scheme=Scheme,
origin_host=Host, origin_port=Port, intermediaries=[Info|Intermediaries],
event_handler_state=EvHandlerState});
-commands([{switch_transport, Transport, Socket}|Tail], State=#state{
+commands([{switch_transport, Transport, Socket}|Tail], State0=#state{
protocol=Protocol, protocol_state=ProtoState0}) ->
ProtoState = Protocol:switch_transport(Transport, Socket, ProtoState0),
- commands(Tail, active(State#state{socket=Socket, transport=Transport,
- messages=Transport:messages(), protocol_state=ProtoState}));
+ State1 = State0#state{socket=Socket, transport=Transport,
+ messages=Transport:messages(), protocol_state=ProtoState},
+ case active(State1) of
+ {ok, State} ->
+ commands(Tail, State);
+ Disconnect ->
+ Disconnect
+ end;
commands([{switch_protocol, NewProtocol, ReplyTo}], State0=#state{
opts=Opts, socket=Socket, transport=Transport,
event_handler=EvHandler, event_handler_state=EvHandlerState0}) ->
@@ -1702,11 +1715,17 @@ commands([{switch_protocol, NewProtocol, ReplyTo}], State0=#state{
EvHandlerState = EvHandler:protocol_changed(ProtocolChangedEvent, EvHandlerState0),
%% We cancel the existing keepalive and, depending on the protocol,
%% we enable keepalive again, effectively resetting the timer.
- State = keepalive_cancel(active(State0#state{protocol=Protocol, protocol_state=ProtoState,
- event_handler_state=EvHandlerState})),
- case Protocol:has_keepalive() of
- true -> {next_state, StateName, keepalive_timeout(State)};
- false -> {next_state, StateName, State}
+ State1 = State0#state{protocol=Protocol, protocol_state=ProtoState,
+ event_handler_state=EvHandlerState},
+ case active(State1) of
+ {ok, State2} ->
+ State = keepalive_cancel(State2),
+ case Protocol:has_keepalive() of
+ true -> {next_state, StateName, keepalive_timeout(State)};
+ false -> {next_state, StateName, State}
+ end;
+ Disconnect ->
+ Disconnect
end;
%% Perform a TLS handshake.
commands([TLSHandshake={tls_handshake, _, _, _}], State) ->
@@ -1750,12 +1769,6 @@ disconnect_flush(State=#state{socket=Socket, messages={OK, Closed, Error}}) ->
ok
end.
-active(State=#state{active=false}) ->
- State;
-active(State=#state{socket=Socket, transport=Transport}) ->
- Transport:setopts(Socket, [{active, once}]),
- State.
-
status(State=#state{status={up, OwnerRef}}, NewStatus) ->
demonitor(OwnerRef, [flush]),
State#state{status=NewStatus};