0
Fork 0
mirror of https://github.com/ninenines/cowboy.git synced 2025-07-15 12:40:25 +00:00

Merge branch 'fix-spdy-parse-frame' of git://github.com/voluntas/cowboy

A fix for a possible bug has been made to the original patch.
This commit is contained in:
Loïc Hoguin 2014-07-07 17:19:01 +02:00
commit fd423eb170

View file

@ -107,19 +107,12 @@ init(Parent, Ref, Socket, Transport, Opts) ->
onresponse=OnResponse, peer=Peer, zdef=Zdef, zinf=Zinf}). onresponse=OnResponse, peer=Peer, zdef=Zdef, zinf=Zinf}).
loop(State=#state{parent=Parent, socket=Socket, transport=Transport, loop(State=#state{parent=Parent, socket=Socket, transport=Transport,
buffer=Buffer, zinf=Zinf, children=Children}) -> buffer=Buffer, children=Children}) ->
{OK, Closed, Error} = Transport:messages(), {OK, Closed, Error} = Transport:messages(),
Transport:setopts(Socket, [{active, once}]), Transport:setopts(Socket, [{active, once}]),
receive receive
{OK, Socket, Data} -> {OK, Socket, Data} ->
Data2 = << Buffer/binary, Data/binary >>, parse_frame(State, << Buffer/binary, Data/binary >>);
case cow_spdy:split(Data2) of
{true, Frame, Rest} ->
P = cow_spdy:parse(Frame, Zinf),
handle_frame(State#state{buffer=Rest}, P);
false ->
loop(State#state{buffer=Data2})
end;
{Closed, Socket} -> {Closed, Socket} ->
terminate(State); terminate(State);
{Error, Socket, _Reason} -> {Error, Socket, _Reason} ->
@ -235,16 +228,30 @@ system_terminate(Reason, _, _, _) ->
system_code_change(Misc, _, _, _) -> system_code_change(Misc, _, _, _) ->
{ok, Misc}. {ok, Misc}.
parse_frame(State=#state{zinf=Zinf}, Data) ->
case cow_spdy:split(Data) of
{true, Frame, Rest} ->
P = cow_spdy:parse(Frame, Zinf),
case handle_frame(State#state{buffer = Rest}, P) of
error ->
terminate(State);
State2 ->
parse_frame(State2, Rest)
end;
false ->
loop(State#state{buffer=Data})
end.
%% FLAG_UNIDIRECTIONAL can only be set by the server. %% FLAG_UNIDIRECTIONAL can only be set by the server.
handle_frame(State, {syn_stream, StreamID, _, _, true, handle_frame(State, {syn_stream, StreamID, _, _, true,
_, _, _, _, _, _, _}) -> _, _, _, _, _, _, _}) ->
rst_stream(State, StreamID, protocol_error), rst_stream(State, StreamID, protocol_error),
loop(State); State;
%% We do not support Associated-To-Stream-ID. %% We do not support Associated-To-Stream-ID.
handle_frame(State, {syn_stream, StreamID, AssocToStreamID, handle_frame(State, {syn_stream, StreamID, AssocToStreamID,
_, _, _, _, _, _, _, _, _}) when AssocToStreamID =/= 0 -> _, _, _, _, _, _, _, _, _}) when AssocToStreamID =/= 0 ->
rst_stream(State, StreamID, internal_error), rst_stream(State, StreamID, internal_error),
loop(State); State;
%% SYN_STREAM. %% SYN_STREAM.
%% %%
%% Erlang does not allow us to control the priority of processes %% Erlang does not allow us to control the priority of processes
@ -257,22 +264,22 @@ handle_frame(State=#state{middlewares=Middlewares, env=Env,
{self(), StreamID}, Peer, OnRequest, OnResponse, {self(), StreamID}, Peer, OnRequest, OnResponse,
Env, Middlewares, Method, Host, Path, Version, Headers Env, Middlewares, Method, Host, Path, Version, Headers
]), ]),
loop(new_child(State, StreamID, Pid, IsFin)); new_child(State, StreamID, Pid, IsFin);
%% RST_STREAM. %% RST_STREAM.
handle_frame(State, {rst_stream, StreamID, Status}) -> handle_frame(State, {rst_stream, StreamID, Status}) ->
error_logger:error_msg("Received RST_STREAM frame ~p ~p", error_logger:error_msg("Received RST_STREAM frame ~p ~p",
[StreamID, Status]), [StreamID, Status]),
%% @todo Stop StreamID. %% @todo Stop StreamID.
loop(State); State;
%% PING initiated by the server; ignore, we don't send any. %% PING initiated by the server; ignore, we don't send any.
handle_frame(State, {ping, PingID}) when PingID rem 2 =:= 0 -> handle_frame(State, {ping, PingID}) when PingID rem 2 =:= 0 ->
error_logger:error_msg("Ignored PING control frame: ~p~n", [PingID]), error_logger:error_msg("Ignored PING control frame: ~p~n", [PingID]),
loop(State); State;
%% PING initiated by the client; send it back. %% PING initiated by the client; send it back.
handle_frame(State=#state{socket=Socket, transport=Transport}, handle_frame(State=#state{socket=Socket, transport=Transport},
{ping, PingID}) -> {ping, PingID}) ->
Transport:send(Socket, cow_spdy:ping(PingID)), Transport:send(Socket, cow_spdy:ping(PingID)),
loop(State); State;
%% Data received for a stream. %% Data received for a stream.
handle_frame(State, {data, StreamID, IsFin, Data}) -> handle_frame(State, {data, StreamID, IsFin, Data}) ->
Child = #child{input=nofin, in_buffer=Buffer, is_recv=IsRecv} Child = #child{input=nofin, in_buffer=Buffer, is_recv=IsRecv}
@ -296,15 +303,15 @@ handle_frame(State, {data, StreamID, IsFin, Data}) ->
_ -> _ ->
Child#child{input=IsFin2, in_buffer=Data2} Child#child{input=IsFin2, in_buffer=Data2}
end, end,
loop(replace_child(Child2, State)); replace_child(Child2, State);
%% General error, can't recover. %% General error, can't recover.
handle_frame(State, {error, badprotocol}) -> handle_frame(State, {error, badprotocol}) ->
goaway(State, protocol_error), goaway(State, protocol_error),
terminate(State); error;
%% Ignore all other frames for now. %% Ignore all other frames for now.
handle_frame(State, Frame) -> handle_frame(State, Frame) ->
error_logger:error_msg("Ignored frame ~p", [Frame]), error_logger:error_msg("Ignored frame ~p", [Frame]),
loop(State). State.
cancel_recv_timeout(StreamID, TRef) -> cancel_recv_timeout(StreamID, TRef) ->
_ = erlang:cancel_timer(TRef), _ = erlang:cancel_timer(TRef),