diff options
author | Viktor Söderqvist <[email protected]> | 2020-10-21 16:58:22 +0200 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2020-11-12 14:21:57 +0100 |
commit | 30a971a039c2725726080ce6d50ce90e1108cb5a (patch) | |
tree | 772af8cfd71eb420ba53ee7c56cce00ad69140f7 /src | |
parent | 7dabafe7a93582c71cdabc3c41a609f582afd7d1 (diff) | |
download | gun-30a971a039c2725726080ce6d50ce90e1108cb5a.tar.gz gun-30a971a039c2725726080ce6d50ce90e1108cb5a.tar.bz2 gun-30a971a039c2725726080ce6d50ce90e1108cb5a.zip |
Fail fast while closing if reconnect is off
If a request/headers/connect/ws_upgrade is created when a connection is in state
'closing', such as after receiving an HTTP/2 GOAWAY frame or an HTTP/1.1
"Connection: close" header, an error message is sent back to the caller
immediately, if reconnect is off (that is if the option retry is set to 0).
This allows an application to retry the request on another connection without
waiting for all streams on the current connection to complete.
Diffstat (limited to 'src')
-rw-r--r-- | src/gun.erl | 21 | ||||
-rw-r--r-- | src/gun_http.erl | 22 |
2 files changed, 39 insertions, 4 deletions
diff --git a/src/gun.erl b/src/gun.erl index ac643e0..ddb5007 100644 --- a/src/gun.erl +++ b/src/gun.erl @@ -1332,6 +1332,27 @@ closing(state_timeout, closing_timeout, State=#state{status=Status}) -> _ -> normal end, disconnect(State, Reason); +%% When reconnect is disabled, fail HTTP/Websocket operations immediately. +closing(cast, {headers, ReplyTo, StreamRef, _Method, _Path, _Headers, _InitialFlow}, + State=#state{opts=#{retry := 0}}) -> + ReplyTo ! {gun_error, self(), StreamRef, closing}, + {keep_state, State}; +closing(cast, {request, ReplyTo, StreamRef, _Method, _Path, _Headers, _Body, _InitialFlow}, + State=#state{opts=#{retry := 0}}) -> + ReplyTo ! {gun_error, self(), StreamRef, closing}, + {keep_state, State}; +closing(cast, {connect, ReplyTo, StreamRef, _Destination, _Headers, _InitialFlow}, + State=#state{opts=#{retry := 0}}) -> + ReplyTo ! {gun_error, self(), StreamRef, closing}, + {keep_state, State}; +closing(cast, {ws_upgrade, ReplyTo, StreamRef, _Path, _Headers}, + State=#state{opts=#{retry := 0}}) -> + ReplyTo ! {gun_error, self(), StreamRef, closing}, + {keep_state, State}; +closing(cast, {ws_upgrade, ReplyTo, StreamRef, _Path, _Headers, _WsOpts}, + State=#state{opts=#{retry := 0}}) -> + ReplyTo ! {gun_error, self(), StreamRef, closing}, + {keep_state, State}; closing(Type, Event, State) -> handle_common_connected(Type, Event, ?FUNCTION_NAME, State). diff --git a/src/gun_http.erl b/src/gun_http.erl index 8cbeada..9c52f2d 100644 --- a/src/gun_http.erl +++ b/src/gun_http.erl @@ -418,7 +418,7 @@ handle_response(Rest, State=#http_state{version=ClientVersion, opts=Opts, connec Status, Headers, Handlers0), EvHandlerState1} end end, - EvHandlerState = case IsFin of + EvHandlerState3 = case IsFin of nofin -> EvHandlerState2; fin -> @@ -436,17 +436,31 @@ handle_response(Rest, State=#http_state{version=ClientVersion, opts=Opts, connec %% We always reset in_state even if not chunked. if IsFin =:= fin, Conn2 =:= close -> - {close, CookieStore, EvHandlerState}; + {close, CookieStore, EvHandlerState3}; IsFin =:= fin -> handle(Rest, end_stream(State#http_state{in=In, in_state={0, 0}, connection=Conn2, streams=[Stream#stream{handler_state=Handlers}|Tail]}), - CookieStore, EvHandler, EvHandlerState); + CookieStore, EvHandler, EvHandlerState3); + Conn2 =:= close -> + close_streams(State, Tail, closing), + {CommandOrCommands, CookieStore1, EvHandlerState4} = + handle(Rest, State#http_state{in=In, + in_state={0, 0}, connection=Conn2, + streams=[Stream#stream{handler_state=Handlers}]}, + CookieStore, EvHandler, EvHandlerState3), + Commands = if + is_list(CommandOrCommands) -> + CommandOrCommands ++ [closing(State)]; + true -> + [CommandOrCommands, closing(State)] + end, + {Commands, CookieStore1, EvHandlerState4}; true -> handle(Rest, State#http_state{in=In, in_state={0, 0}, connection=Conn2, streams=[Stream#stream{handler_state=Handlers}|Tail]}, - CookieStore, EvHandler, EvHandlerState) + CookieStore, EvHandler, EvHandlerState3) end. %% The state must be first in order to retrieve it when the stream ended. |