Просмотр исходного кода

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.
Loïc Hoguin 11 лет назад
Родитель
Сommit
fd423eb170
1 измененных файлов с 25 добавлено и 18 удалено
  1. 25 18
      src/cowboy_spdy.erl

+ 25 - 18
src/cowboy_spdy.erl

@@ -107,19 +107,12 @@ init(Parent, Ref, Socket, Transport, Opts) ->
 		onresponse=OnResponse, peer=Peer, zdef=Zdef, zinf=Zinf}).
 
 loop(State=#state{parent=Parent, socket=Socket, transport=Transport,
-		buffer=Buffer, zinf=Zinf, children=Children}) ->
+		buffer=Buffer, children=Children}) ->
 	{OK, Closed, Error} = Transport:messages(),
 	Transport:setopts(Socket, [{active, once}]),
 	receive
 		{OK, Socket, Data} ->
-			Data2 = << 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;
+			parse_frame(State, << Buffer/binary, Data/binary >>);
 		{Closed, Socket} ->
 			terminate(State);
 		{Error, Socket, _Reason} ->
@@ -235,16 +228,30 @@ system_terminate(Reason, _, _, _) ->
 system_code_change(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.
 handle_frame(State, {syn_stream, StreamID, _, _, true,
 		_, _, _, _, _, _, _}) ->
 	rst_stream(State, StreamID, protocol_error),
-	loop(State);
+	State;
 %% We do not support Associated-To-Stream-ID.
 handle_frame(State, {syn_stream, StreamID, AssocToStreamID,
 		_, _, _, _, _, _, _, _, _}) when AssocToStreamID =/= 0 ->
 	rst_stream(State, StreamID, internal_error),
-	loop(State);
+	State;
 %% SYN_STREAM.
 %%
 %% 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,
 		Env, Middlewares, Method, Host, Path, Version, Headers
 	]),
-	loop(new_child(State, StreamID, Pid, IsFin));
+	new_child(State, StreamID, Pid, IsFin);
 %% RST_STREAM.
 handle_frame(State, {rst_stream, StreamID, Status}) ->
 	error_logger:error_msg("Received RST_STREAM frame ~p ~p",
 		[StreamID, Status]),
 	%% @todo Stop StreamID.
-	loop(State);
+	State;
 %% PING initiated by the server; ignore, we don't send any.
 handle_frame(State, {ping, PingID}) when PingID rem 2 =:= 0 ->
 	error_logger:error_msg("Ignored PING control frame: ~p~n", [PingID]),
-	loop(State);
+	State;
 %% PING initiated by the client; send it back.
 handle_frame(State=#state{socket=Socket, transport=Transport},
 		{ping, PingID}) ->
 	Transport:send(Socket, cow_spdy:ping(PingID)),
-	loop(State);
+	State;
 %% Data received for a stream.
 handle_frame(State, {data, StreamID, IsFin, Data}) ->
 	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}
 	end,
-	loop(replace_child(Child2, State));
+	replace_child(Child2, State);
 %% General error, can't recover.
 handle_frame(State, {error, badprotocol}) ->
 	goaway(State, protocol_error),
-	terminate(State);
+	error;
 %% Ignore all other frames for now.
 handle_frame(State, Frame) ->
 	error_logger:error_msg("Ignored frame ~p", [Frame]),
-	loop(State).
+	State.
 
 cancel_recv_timeout(StreamID, TRef) ->
 	_ = erlang:cancel_timer(TRef),