diff options
Diffstat (limited to 'src/cowboy_protocol.erl')
-rw-r--r-- | src/cowboy_protocol.erl | 113 |
1 files changed, 9 insertions, 104 deletions
diff --git a/src/cowboy_protocol.erl b/src/cowboy_protocol.erl index fdc1126..22faf1b 100644 --- a/src/cowboy_protocol.erl +++ b/src/cowboy_protocol.erl @@ -1,4 +1,4 @@ -%% Copyright (c) 2011-2013, Loïc Hoguin <[email protected]> +%% Copyright (c) 2011-2014, Loïc Hoguin <[email protected]> %% Copyright (c) 2011, Anthony Ramine <[email protected]> %% %% Permission to use, copy, modify, and/or distribute this software for any @@ -13,39 +13,6 @@ %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -%% @doc HTTP protocol handler. -%% -%% The available options are: -%% <dl> -%% <dt>compress</dt><dd>Whether to automatically compress the response -%% body when the conditions are met. Disabled by default.</dd> -%% <dt>env</dt><dd>The environment passed and optionally modified -%% by middlewares.</dd> -%% <dt>max_empty_lines</dt><dd>Max number of empty lines before a request. -%% Defaults to 5.</dd> -%% <dt>max_header_name_length</dt><dd>Max length allowed for header names. -%% Defaults to 64.</dd> -%% <dt>max_header_value_length</dt><dd>Max length allowed for header values. -%% Defaults to 4096.</dd> -%% <dt>max_headers</dt><dd>Max number of headers allowed. -%% Defaults to 100.</dd> -%% <dt>max_keepalive</dt><dd>Max number of requests allowed in a single -%% keep-alive session. Defaults to 100.</dd> -%% <dt>max_request_line_length</dt><dd>Max length allowed for the request -%% line. Defaults to 4096.</dd> -%% <dt>middlewares</dt><dd>The list of middlewares to execute when a -%% request is received.</dd> -%% <dt>onrequest</dt><dd>Optional fun that allows Req interaction before -%% any dispatching is done. Host info, path info and bindings are thus -%% not available at this point.</dd> -%% <dt>onresponse</dt><dd>Optional fun that allows replacing a response -%% sent by the application.</dd> -%% <dt>timeout</dt><dd>Time in milliseconds a client has to send the -%% full request line and headers. Defaults to 5000 milliseconds.</dd> -%% </dl> -%% -%% Note that there is no need to monitor these processes when using Cowboy as -%% an application as it already supervises them under the listener supervisor. -module(cowboy_protocol). %% API. @@ -89,9 +56,10 @@ until :: non_neg_integer() | infinity }). +-include_lib("cowlib/include/cow_inline.hrl"). + %% API. -%% @doc Start an HTTP protocol process. -spec start_link(ranch:ref(), inet:socket(), module(), opts()) -> {ok, pid()}. start_link(Ref, Socket, Transport, Opts) -> Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), @@ -99,15 +67,13 @@ start_link(Ref, Socket, Transport, Opts) -> %% Internal. -%% @doc Faster alternative to proplists:get_value/3. -%% @private +%% Faster alternative to proplists:get_value/3. get_value(Key, Opts, Default) -> case lists:keyfind(Key, 1, Opts) of {_, Value} -> Value; _ -> Default end. -%% @private -spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. init(Ref, Socket, Transport, Opts) -> Compress = get_value(compress, Opts, false), @@ -170,7 +136,6 @@ wait_request(Buffer, State=#state{socket=Socket, transport=Transport, terminate(State) end. -%% @private -spec parse_request(binary(), #state{}, non_neg_integer()) -> ok. %% Empty lines must be using \r\n. parse_request(<< $\n, _/binary >>, State, _) -> @@ -292,44 +257,12 @@ match_colon(<< _, Rest/bits >>, N) -> match_colon(_, _) -> nomatch. -%% I know, this isn't exactly pretty. But this is the most critical -%% code path and as such needs to be optimized to death. -%% -%% ... Sorry for your eyes. -%% -%% But let's be honest, that's still pretty readable. parse_hd_name(<< C, Rest/bits >>, S, M, P, Q, V, H, SoFar) -> case C of $: -> parse_hd_before_value(Rest, S, M, P, Q, V, H, SoFar); $\s -> parse_hd_name_ws(Rest, S, M, P, Q, V, H, SoFar); $\t -> parse_hd_name_ws(Rest, S, M, P, Q, V, H, SoFar); - $A -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $a >>); - $B -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $b >>); - $C -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $c >>); - $D -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $d >>); - $E -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $e >>); - $F -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $f >>); - $G -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $g >>); - $H -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $h >>); - $I -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $i >>); - $J -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $j >>); - $K -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $k >>); - $L -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $l >>); - $M -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $m >>); - $N -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $n >>); - $O -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $o >>); - $P -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $p >>); - $Q -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $q >>); - $R -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $r >>); - $S -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $s >>); - $T -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $t >>); - $U -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $u >>); - $V -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $v >>); - $W -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $w >>); - $X -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $x >>); - $Y -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $y >>); - $Z -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, $z >>); - C -> parse_hd_name(Rest, S, M, P, Q, V, H, << SoFar/binary, C >>) + ?INLINE_LOWERCASE(parse_hd_name, Rest, S, M, P, Q, V, H, SoFar) end. parse_hd_name_ws(<< C, Rest/bits >>, S, M, P, Q, V, H, Name) -> @@ -405,7 +338,8 @@ parse_hd_value(<< $\r, Rest/bits >>, S, M, P, Q, V, Headers, Name, SoFar) -> << $\n >> -> wait_hd_value_nl(<<>>, S, M, P, Q, V, Headers, Name, SoFar); << $\n, C, Rest2/bits >> when C =:= $\s; C =:= $\t -> - parse_hd_value(Rest2, S, M, P, Q, V, Headers, Name, SoFar); + parse_hd_value(Rest2, S, M, P, Q, V, Headers, Name, + << SoFar/binary, C >>); << $\n, Rest2/bits >> -> parse_header(Rest2, S, M, P, Q, V, [{Name, SoFar}|Headers]) end; @@ -441,8 +375,6 @@ request(B, State=#state{transport=Transport}, M, P, Q, Version, Headers) -> default_port(ssl) -> 443; default_port(_) -> 80. -%% Another hurtful block of code. :) -%% %% Same code as cow_http:parse_fullhost/1, but inline because we %% really want this to go fast. parse_host(<< $[, Rest/bits >>, false, <<>>) -> @@ -455,33 +387,7 @@ parse_host(<< $], Rest/bits >>, true, Acc) -> parse_host(Rest, false, << Acc/binary, $] >>); parse_host(<< C, Rest/bits >>, E, Acc) -> case C of - $A -> parse_host(Rest, E, << Acc/binary, $a >>); - $B -> parse_host(Rest, E, << Acc/binary, $b >>); - $C -> parse_host(Rest, E, << Acc/binary, $c >>); - $D -> parse_host(Rest, E, << Acc/binary, $d >>); - $E -> parse_host(Rest, E, << Acc/binary, $e >>); - $F -> parse_host(Rest, E, << Acc/binary, $f >>); - $G -> parse_host(Rest, E, << Acc/binary, $g >>); - $H -> parse_host(Rest, E, << Acc/binary, $h >>); - $I -> parse_host(Rest, E, << Acc/binary, $i >>); - $J -> parse_host(Rest, E, << Acc/binary, $j >>); - $K -> parse_host(Rest, E, << Acc/binary, $k >>); - $L -> parse_host(Rest, E, << Acc/binary, $l >>); - $M -> parse_host(Rest, E, << Acc/binary, $m >>); - $N -> parse_host(Rest, E, << Acc/binary, $n >>); - $O -> parse_host(Rest, E, << Acc/binary, $o >>); - $P -> parse_host(Rest, E, << Acc/binary, $p >>); - $Q -> parse_host(Rest, E, << Acc/binary, $q >>); - $R -> parse_host(Rest, E, << Acc/binary, $r >>); - $S -> parse_host(Rest, E, << Acc/binary, $s >>); - $T -> parse_host(Rest, E, << Acc/binary, $t >>); - $U -> parse_host(Rest, E, << Acc/binary, $u >>); - $V -> parse_host(Rest, E, << Acc/binary, $v >>); - $W -> parse_host(Rest, E, << Acc/binary, $w >>); - $X -> parse_host(Rest, E, << Acc/binary, $x >>); - $Y -> parse_host(Rest, E, << Acc/binary, $y >>); - $Z -> parse_host(Rest, E, << Acc/binary, $z >>); - _ -> parse_host(Rest, E, << Acc/binary, C >>) + ?INLINE_LOWERCASE(parse_host, Rest, E, Acc) end. %% End of request parsing. @@ -538,7 +444,6 @@ execute(Req, State, Env, [Middleware|Tail]) -> error_terminate(Code, Req2, State) end. -%% @private -spec resume(#state{}, cowboy_middleware:env(), [module()], module(), module(), [any()]) -> ok. resume(State, Env, Tail, Module, Function, Args) -> @@ -569,8 +474,8 @@ next_request(Req, State=#state{req_keepalive=Keepalive, timeout=Timeout}, _ -> close end, %% Flush the resp_sent message before moving on. - receive {cowboy_req, resp_sent} -> ok after 0 -> ok end, if HandlerRes =:= ok, Buffer =/= close -> + receive {cowboy_req, resp_sent} -> ok after 0 -> ok end, ?MODULE:parse_request(Buffer, State#state{req_keepalive=Keepalive + 1, until=until(Timeout)}, 0); |