0
Fork 0
mirror of https://github.com/ninenines/cowboy.git synced 2025-07-16 05:00:24 +00:00

Simplify the SPDY code by adding child management functions

This commit is contained in:
Loïc Hoguin 2013-09-04 12:29:30 +02:00
parent 9b52ccad03
commit d83205243a

View file

@ -131,7 +131,7 @@ loop(State=#state{parent=Parent, socket=Socket, transport=Transport,
{recv, FromSocket = {Pid, StreamID}, FromPid, Length, _Timeout} {recv, FromSocket = {Pid, StreamID}, FromPid, Length, _Timeout}
when Pid =:= self() -> when Pid =:= self() ->
Child = #child{in_buffer=InBuffer, is_recv=false} Child = #child{in_buffer=InBuffer, is_recv=false}
= lists:keyfind(StreamID, #child.streamid, Children), = get_child(StreamID, State),
if if
Length =:= 0, InBuffer =/= <<>> -> Length =:= 0, InBuffer =/= <<>> ->
FromPid ! {recv, FromSocket, {ok, InBuffer}}, FromPid ! {recv, FromSocket, {ok, InBuffer}},
@ -152,55 +152,40 @@ loop(State=#state{parent=Parent, socket=Socket, transport=Transport,
end; end;
{reply, {Pid, StreamID}, Status, Headers} {reply, {Pid, StreamID}, Status, Headers}
when Pid =:= self() -> when Pid =:= self() ->
Child = #child{output=nofin} = lists:keyfind(StreamID, Child = #child{output=nofin} = get_child(StreamID, State),
#child.streamid, Children),
syn_reply(State, StreamID, true, Status, Headers), syn_reply(State, StreamID, true, Status, Headers),
Children2 = lists:keyreplace(StreamID, loop(out_fin_child(Child, State));
#child.streamid, Children, Child#child{output=fin}),
loop(State#state{children=Children2});
{reply, {Pid, StreamID}, Status, Headers, Body} {reply, {Pid, StreamID}, Status, Headers, Body}
when Pid =:= self() -> when Pid =:= self() ->
Child = #child{output=nofin} = lists:keyfind(StreamID, Child = #child{output=nofin} = get_child(StreamID, State),
#child.streamid, Children),
syn_reply(State, StreamID, false, Status, Headers), syn_reply(State, StreamID, false, Status, Headers),
data(State, StreamID, true, Body), data(State, StreamID, true, Body),
Children2 = lists:keyreplace(StreamID, loop(out_fin_child(Child, State));
#child.streamid, Children, Child#child{output=fin}),
loop(State#state{children=Children2});
{stream_reply, {Pid, StreamID}, Status, Headers} {stream_reply, {Pid, StreamID}, Status, Headers}
when Pid =:= self() -> when Pid =:= self() ->
#child{output=nofin} = lists:keyfind(StreamID, #child{output=nofin} = get_child(StreamID, State),
#child.streamid, Children),
syn_reply(State, StreamID, false, Status, Headers), syn_reply(State, StreamID, false, Status, Headers),
loop(State); loop(State);
{stream_data, {Pid, StreamID}, Data} {stream_data, {Pid, StreamID}, Data}
when Pid =:= self() -> when Pid =:= self() ->
#child{output=nofin} = lists:keyfind(StreamID, #child{output=nofin} = get_child(StreamID, State),
#child.streamid, Children),
data(State, StreamID, false, Data), data(State, StreamID, false, Data),
loop(State); loop(State);
{stream_close, {Pid, StreamID}} {stream_close, {Pid, StreamID}}
when Pid =:= self() -> when Pid =:= self() ->
Child = #child{output=nofin} = lists:keyfind(StreamID, Child = #child{output=nofin} = get_child(StreamID, State),
#child.streamid, Children),
data(State, StreamID, true, <<>>), data(State, StreamID, true, <<>>),
Children2 = lists:keyreplace(StreamID, loop(out_fin_child(Child, State));
#child.streamid, Children, Child#child{output=fin}),
loop(State#state{children=Children2});
{sendfile, {Pid, StreamID}, Filepath} {sendfile, {Pid, StreamID}, Filepath}
when Pid =:= self() -> when Pid =:= self() ->
Child = #child{output=nofin} = lists:keyfind(StreamID, Child = #child{output=nofin} = get_child(StreamID, State),
#child.streamid, Children),
data_from_file(State, StreamID, Filepath), data_from_file(State, StreamID, Filepath),
Children2 = lists:keyreplace(StreamID, loop(out_fin_child(Child, State));
#child.streamid, Children, Child#child{output=fin}),
loop(State#state{children=Children2});
{'EXIT', Parent, Reason} -> {'EXIT', Parent, Reason} ->
exit(Reason); exit(Reason);
{'EXIT', Pid, _} -> {'EXIT', Pid, _} ->
%% @todo Report the error if any. %% @todo Report the error if any.
Children2 = lists:keydelete(Pid, #child.pid, Children), loop(delete_child(Pid, State));
loop(State#state{children=Children2});
{system, From, Request} -> {system, From, Request} ->
sys:handle_system_msg(Request, From, Parent, ?MODULE, [], State); sys:handle_system_msg(Request, From, Parent, ?MODULE, [], State);
%% Calls from the supervisor module. %% Calls from the supervisor module.
@ -248,17 +233,14 @@ handle_frame(State, {syn_stream, StreamID, AssocToStreamID,
%% Erlang does not allow us to control the priority of processes %% Erlang does not allow us to control the priority of processes
%% so we ignore that value entirely. %% so we ignore that value entirely.
handle_frame(State=#state{middlewares=Middlewares, env=Env, handle_frame(State=#state{middlewares=Middlewares, env=Env,
onrequest=OnRequest, onresponse=OnResponse, peer=Peer, onrequest=OnRequest, onresponse=OnResponse, peer=Peer},
children=Children}, {syn_stream, StreamID, _, IsFin, {syn_stream, StreamID, _, IsFin, _, _,
_, _, Method, _, Host, Path, Version, Headers}) -> Method, _, Host, Path, Version, Headers}) ->
Pid = spawn_link(?MODULE, request_init, [ Pid = spawn_link(?MODULE, request_init, [
{self(), StreamID}, Peer, OnRequest, OnResponse, {self(), StreamID}, Peer, OnRequest, OnResponse,
Env, Middlewares, Method, Host, Path, Version, Headers Env, Middlewares, Method, Host, Path, Version, Headers
]), ]),
IsFin2 = if IsFin -> fin; true -> nofin end, loop(new_child(State, StreamID, Pid, IsFin));
loop(State#state{last_streamid=StreamID,
children=[#child{streamid=StreamID, pid=Pid,
input=IsFin2, output=nofin}|Children]});
%% 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",
@ -278,7 +260,7 @@ handle_frame(State=#state{socket=Socket, transport=Transport},
handle_frame(State=#state{children=Children}, handle_frame(State=#state{children=Children},
{data, StreamID, IsFin, Data}) -> {data, StreamID, IsFin, Data}) ->
Child = #child{input=nofin, in_buffer=Buffer, is_recv=IsRecv} Child = #child{input=nofin, in_buffer=Buffer, is_recv=IsRecv}
= lists:keyfind(StreamID, #child.streamid, Children), = get_child(StreamID, State),
Data2 = << Buffer/binary, Data/binary >>, Data2 = << Buffer/binary, Data/binary >>,
IsFin2 = if IsFin -> fin; true -> nofin end, IsFin2 = if IsFin -> fin; true -> nofin end,
Child2 = case IsRecv of Child2 = case IsRecv of
@ -342,6 +324,27 @@ data_from_file(Socket, Transport, StreamID, IoDevice) ->
end end
end. end.
%% Children.
new_child(State=#state{children=Children}, StreamID, Pid, IsFin) ->
IsFin2 = if IsFin -> fin; true -> nofin end,
State#state{last_streamid=StreamID,
children=[#child{streamid=StreamID,
pid=Pid, input=IsFin2}|Children]}.
delete_child(Pid, State=#state{children=Children}) ->
Children2 = lists:keydelete(Pid, #child.pid, Children),
State#state{children=Children2}.
get_child(StreamID, #state{children=Children}) ->
lists:keyfind(StreamID, #child.streamid, Children).
out_fin_child(Child=#child{streamid=StreamID},
State=#state{children=Children}) ->
Children2 = lists:keyreplace(StreamID,
#child.streamid, Children, Child#child{output=fin}),
State#state{children=Children2}.
%% Request process. %% Request process.
request_init(FakeSocket, Peer, OnRequest, OnResponse, request_init(FakeSocket, Peer, OnRequest, OnResponse,