Loïc Hoguin 9 лет назад
Родитель
Сommit
0193538dba
4 измененных файлов с 18 добавлено и 164 удалено
  1. 3 3
      src/cowboy_http.erl
  2. 1 33
      src/cowboy_loop.erl
  3. 1 123
      src/cowboy_req.erl
  4. 13 5
      src/cowboy_websocket.erl

+ 3 - 3
src/cowboy_http.erl

@@ -201,13 +201,13 @@ loop(State=#state{parent=Parent, socket=Socket, transport=Transport,
 		terminate(State, {internal_error, timeout, 'No message or data received before timeout.'})
 	end.
 
-set_request_timeout(State0=#state{timer=TimerRef0, opts=Opts}) ->
+set_request_timeout(State0=#state{opts=Opts}) ->
 	State = cancel_request_timeout(State0),
 	Timeout = maps:get(request_timeout, Opts, 5000),
 	TimerRef = erlang:start_timer(Timeout, self(), request_timeout),
 	State#state{timer=TimerRef}.
 
-cancel_request_timeout(State=#state{timer=TimerRef, opts=Opts}) ->
+cancel_request_timeout(State=#state{timer=TimerRef}) ->
 	ok = case TimerRef of
 		undefined -> ok;
 		_ -> erlang:cancel_timer(TimerRef, [{async, true}, {info, false}])
@@ -779,7 +779,7 @@ commands(State0=#state{socket=Socket, transport=Transport, streams=Streams}, Str
 commands(State=#state{socket=Socket, transport=Transport, streams=Streams}, StreamID,
 		[{data, IsFin, Data}|Tail]) ->
 	%% @todo Same as above.
-	Headers1 = case lists:keyfind(StreamID, #stream.id, Streams) of
+	case lists:keyfind(StreamID, #stream.id, Streams) of
 		#stream{version='HTTP/1.1'} ->
 			Size = iolist_size(Data),
 			Transport:send(Socket, [integer_to_list(Size, 16), <<"\r\n">>, Data, <<"\r\n">>]);

+ 1 - 33
src/cowboy_loop.erl

@@ -121,45 +121,13 @@ timeout(State=#state{timeout=Timeout,
 -spec loop(Req, #state{}, module(), any())
 	-> {ok, Req, cowboy_middleware:env()} | {suspend, module(), atom(), [any()]}
 	when Req::cowboy_req:req().
-loop(Req, State=#state{buffer_size=NbBytes,
-		max_buffer=Threshold, timeout_ref=TRef,
-		resp_sent=RespSent}, Handler, HandlerState) ->
-%	[Socket, Transport] = cowboy_req:get([socket, transport], Req),
-%	{OK, Closed, Error} = Transport:messages(),
+loop(Req, State=#state{timeout_ref=TRef}, Handler, HandlerState) ->
 	receive
-%		{OK, Socket, Data} ->
-%			NbBytes2 = NbBytes + byte_size(Data),
-%			if	NbBytes2 > Threshold ->
-%					_ = if RespSent -> ok; true ->
-%						cowboy_req:reply(500, Req)
-%					end,
-%					cowboy_handler:terminate({error, overflow}, Req, HandlerState, Handler),
-%					exit(normal);
-%				true ->
-%					Req2 = cowboy_req:append_buffer(Data, Req),
-%					State2 = timeout(State#state{buffer_size=NbBytes2}),
-%					before_loop(Req2, State2, Handler, HandlerState)
-%			end;
-%		{Closed, Socket} ->
-%			terminate(Req, State, Handler, HandlerState, {error, closed});
-%		{Error, Socket, Reason} ->
-%			terminate(Req, State, Handler, HandlerState, {error, Reason});
 		{timeout, TRef, ?MODULE} ->
 			after_loop(Req, State, Handler, HandlerState, timeout);
 		{timeout, OlderTRef, ?MODULE} when is_reference(OlderTRef) ->
 			loop(Req, State, Handler, HandlerState);
 		Message ->
-			%% We set the socket back to {active, false} mode in case
-			%% the handler is going to call recv. We also flush any
-			%% data received after that and put it into the buffer.
-			%% We do not check the size here, if data keeps coming
-			%% we'll error out on the next packet received.
-%			Transport:setopts(Socket, [{active, false}]),
-%			Req2 = receive {OK, Socket, Data} ->
-%				cowboy_req:append_buffer(Data, Req)
-%			after 0 ->
-%				Req
-%			end,
 			call(Req, State, Handler, HandlerState, Message)
 	end.
 

+ 1 - 123
src/cowboy_req.erl

@@ -747,6 +747,7 @@ do_reply(Status, Headers, Body, Req=#{pid := Pid, streamid := StreamID}) ->
 	Pid ! {{Pid, StreamID}, {response, Status, response_headers(Headers, Req), Body}},
 	ok.
 
+-spec send_body(iodata(), fin | nofin, req()) -> ok.
 send_body(Data, IsFin, #{pid := Pid, streamid := StreamID}) ->
 	Pid ! {{Pid, StreamID}, {data, IsFin, Data}},
 	ok.
@@ -1017,129 +1018,6 @@ to_list(Req) ->
 
 %% Internal.
 
-%-spec chunked_response(cowboy:http_status(), cowboy:http_headers(), Req) ->
-%	{normal | hook, Req} when Req::req().
-%chunked_response(Status, Headers, Req=#http_req{
-%		version=Version, connection=Connection,
-%		resp_state=RespState, resp_headers=RespHeaders})
-%		when RespState =:= waiting; RespState =:= waiting_stream ->
-%	RespConn = response_connection(Headers, Connection),
-%	HTTP11Headers = if
-%		Version =:= 'HTTP/1.0', Connection =:= keepalive ->
-%			[{<<"connection">>, atom_to_connection(Connection)}];
-%		Version =:= 'HTTP/1.0' -> [];
-%		true ->
-%			MaybeTE = if
-%				RespState =:= waiting_stream -> [];
-%				true -> [{<<"transfer-encoding">>, <<"chunked">>}]
-%			end,
-%			if
-%				Connection =:= close ->
-%					[{<<"connection">>, atom_to_connection(Connection)}|MaybeTE];
-%				true ->
-%					MaybeTE
-%			end
-%	end,
-%	RespState2 = if
-%		Version =:= 'HTTP/1.1', RespState =:= 'waiting' -> chunks;
-%		true -> stream
-%	end,
-%	{RespType, Req2} = response(Status, Headers, RespHeaders, [
-%		{<<"date">>, cowboy_clock:rfc1123()},
-%		{<<"server">>, <<"Cowboy">>}
-%	|HTTP11Headers], <<>>, Req),
-%	{RespType, Req2#http_req{connection=RespConn, resp_state=RespState2,
-%			resp_headers=[], resp_body= <<>>}}.
-%
--spec response(cowboy:http_status(), cowboy:http_headers(),
-	cowboy:http_headers(), cowboy:http_headers(), stream | iodata(), Req)
-	-> {normal | hook, Req} when Req::req().
-response(Status, Headers, RespHeaders, DefaultHeaders, Body, Req=#http_req{
-		socket=Socket, transport=Transport, version=Version,
-		pid=ReqPid, onresponse=OnResponse}) ->
-	FullHeaders = case OnResponse of
-		already_called -> Headers;
-		_ -> response_merge_headers(Headers, RespHeaders, DefaultHeaders)
-	end,
-	Body2 = case Body of stream -> <<>>; _ -> Body end,
-	{Status2, FullHeaders2, Req2} = case OnResponse of
-		already_called -> {Status, FullHeaders, Req};
-		undefined -> {Status, FullHeaders, Req};
-		OnResponse ->
-			case OnResponse(Status, FullHeaders, Body2,
-					%% Don't call 'onresponse' from the hook itself.
-					Req#http_req{resp_headers=[], resp_body= <<>>,
-						onresponse=already_called}) of
-				StHdReq = {_, _, _} ->
-					StHdReq;
-				Req1 ->
-					{Status, FullHeaders, Req1}
-			end
-	end,
-	ReplyType = case Req2#http_req.resp_state of
-		RespState when RespState =:= waiting; RespState =:= waiting_stream ->
-			HTTPVer = atom_to_binary(Version, latin1),
-			StatusLine = << HTTPVer/binary, " ",
-				(status(Status2))/binary, "\r\n" >>,
-			HeaderLines = [[Key, <<": ">>, Value, <<"\r\n">>]
-				|| {Key, Value} <- FullHeaders2],
-			ok = Transport:send(Socket, [StatusLine, HeaderLines, <<"\r\n">>, Body2]),
-			ReqPid ! {?MODULE, resp_sent},
-			normal;
-		_ ->
-			hook
-	end,
-	{ReplyType, Req2}.
-%
-%-spec response_connection(cowboy:http_headers(), keepalive | close)
-%	-> keepalive | close.
-%response_connection([], Connection) ->
-%	Connection;
-%response_connection([{Name, Value}|Tail], Connection) ->
-%	case Name of
-%		<<"connection">> ->
-%			Tokens = cow_http_hd:parse_connection(Value),
-%			connection_to_atom(Tokens);
-%		_ ->
-%			response_connection(Tail, Connection)
-%	end.
-%
--spec response_merge_headers(cowboy:http_headers(), cowboy:http_headers(),
-	cowboy:http_headers()) -> cowboy:http_headers().
-response_merge_headers(Headers, RespHeaders, DefaultHeaders) ->
-	Headers2 = [{Key, Value} || {Key, Value} <- Headers],
-	merge_headers(
-		merge_headers(Headers2, RespHeaders),
-		DefaultHeaders).
-
--spec merge_headers(cowboy:http_headers(), cowboy:http_headers())
-	-> cowboy:http_headers().
-
-%% Merge headers by prepending the tuples in the second list to the
-%% first list. It also handles Set-Cookie properly, which supports
-%% duplicated entries. Notice that, while the RFC2109 does allow more
-%% than one cookie to be set per Set-Cookie header, we are following
-%% the implementation of common web servers and applications which
-%% return many distinct headers per each Set-Cookie entry to avoid
-%% issues with clients/browser which may not support it.
-merge_headers(Headers, []) ->
-	Headers;
-merge_headers(Headers, [{<<"set-cookie">>, Value}|Tail]) ->
-	merge_headers([{<<"set-cookie">>, Value}|Headers], Tail);
-merge_headers(Headers, [{Name, Value}|Tail]) ->
-	Headers2 = case lists:keymember(Name, 1, Headers) of
-		true -> Headers;
-		false -> [{Name, Value}|Headers]
-	end,
-	merge_headers(Headers2, Tail).
-%
-%-spec atom_to_connection(keepalive) -> <<_:80>>;
-%						(close) -> <<_:40>>.
-%atom_to_connection(keepalive) ->
-%	<<"keep-alive">>;
-%atom_to_connection(close) ->
-%	<<"close">>.
-
 %% We don't match on "keep-alive" since it is the default value.
 -spec connection_to_atom([binary()]) -> keepalive | close.
 connection_to_atom([]) ->

+ 13 - 5
src/cowboy_websocket.erl

@@ -101,9 +101,13 @@ websocket_upgrade(State, Req) ->
 -spec websocket_extensions(#state{}, Req)
 	-> {ok, #state{}, Req} when Req::cowboy_req:req().
 websocket_extensions(State, Req) ->
-	%% @todo Proper options for this.
-%	[Compress] = cowboy_req:get([resp_compress], Req),
-	Compress = false,
+	%% @todo We want different options for this. For example
+	%% * compress everything auto
+	%% * compress only text auto
+	%% * compress only binary auto
+	%% * compress nothing auto (but still enabled it)
+	%% * disable compression
+	Compress = maps:get(websocket_compress, Req, false),
 	Req2 = Req#{websocket_compress => false},
 	case {Compress, cowboy_req:parse_header(<<"sec-websocket-extensions">>, Req2)} of
 		{true, Extensions} when Extensions =/= undefined ->
@@ -144,7 +148,7 @@ websocket_extensions(State, Req, [_|Tail], RespHeader) ->
 -spec websocket_handshake(#state{}, Req, any(), Env)
 	-> {ok, Req, Env}
 	when Req::cowboy_req:req(), Env::cowboy_middleware:env().
-websocket_handshake(State=#state{transport=Transport, key=Key},
+websocket_handshake(State=#state{key=Key},
 		Req=#{pid := Pid, streamid := StreamID}, HandlerState, Env) ->
 	Challenge = base64:encode(crypto:hash(sha,
 		<< Key/binary, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" >>)),
@@ -159,7 +163,11 @@ websocket_handshake(State=#state{transport=Transport, key=Key},
 
 %% Connection process.
 
-takeover(Parent, Ref, Socket, Transport, Opts, Buffer, {Req0, State=#state{handler=Handler}, HandlerState0}) ->
+%% @todo Keep parent and handle system messages.
+-spec takeover(pid(), ranch:ref(), inet:socket(), module(), any(), binary(),
+	{cowboy_req:req(), #state{}, any()}) -> ok.
+takeover(_Parent, Ref, Socket, Transport, _Opts, Buffer,
+		{Req0, State=#state{handler=Handler}, HandlerState0}) ->
 	ranch:remove_connection(Ref),
 	%% @todo Remove Req from Websocket callbacks.
 	%% @todo Allow sending a reply from websocket_init.