aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cowboy_acceptors_sup.erl2
-rw-r--r--src/cowboy_http.erl307
-rw-r--r--src/cowboy_http_protocol.erl2
-rw-r--r--src/cowboy_http_req.erl79
-rw-r--r--src/cowboy_http_websocket.erl6
-rw-r--r--src/cowboy_listener.erl8
-rw-r--r--src/cowboy_listener_sup.erl2
-rw-r--r--src/cowboy_sup.erl2
8 files changed, 340 insertions, 68 deletions
diff --git a/src/cowboy_acceptors_sup.erl b/src/cowboy_acceptors_sup.erl
index 3d57610..17849a6 100644
--- a/src/cowboy_acceptors_sup.erl
+++ b/src/cowboy_acceptors_sup.erl
@@ -38,6 +38,6 @@ init([NbAcceptors, Transport, TransOpts,
Procs = [{{acceptor, self(), N}, {cowboy_acceptor, start_link, [
LSocket, Transport, Protocol, ProtoOpts,
MaxConns, ListenerPid, ReqsPid
- ]}, permanent, brutal_kill, worker, dynamic}
+ ]}, permanent, brutal_kill, worker, []}
|| N <- lists:seq(1, NbAcceptors)],
{ok, {{one_for_one, 10, 10}, Procs}}.
diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl
index b05611b..9b8a178 100644
--- a/src/cowboy_http.erl
+++ b/src/cowboy_http.erl
@@ -16,7 +16,9 @@
-module(cowboy_http).
%% Parsing.
--export([list/2, nonempty_list/2, token/2, token_ci/2]).
+-export([list/2, nonempty_list/2,
+ media_range/2, charset/2,
+ token/2, token_ci/2, quoted_string/2]).
%% Interpretation.
-export([connection_to_atom/1]).
@@ -44,53 +46,211 @@ list(Data, Fun) ->
end.
-spec list(binary(), fun(), [binary()]) -> [any()] | {error, badarg}.
-list(<<>>, _Fun, Acc) ->
- Acc;
%% From the RFC:
%% <blockquote>Wherever this construct is used, null elements are allowed,
%% but do not contribute to the count of elements present.
%% That is, "(element), , (element) " is permitted, but counts
%% as only two elements. Therefore, where at least one element is required,
%% at least one non-null element MUST be present.</blockquote>
-list(<< $,, Rest/bits >>, Fun, Acc) ->
- list(Rest, Fun, Acc);
list(Data, Fun, Acc) ->
- Fun(Data,
- fun (R, <<>>) -> list_separator(R,
- fun (D) -> list(D, Fun, Acc) end);
- (R, I) -> list_separator(R,
- fun (D) -> list(D, Fun, [I|Acc]) end)
+ whitespace(Data,
+ fun (<<>>) -> Acc;
+ (<< $,, Rest/bits >>) -> list(Rest, Fun, Acc);
+ (Rest) -> Fun(Rest,
+ fun (D, I) -> whitespace(D,
+ fun (<<>>) -> [I|Acc];
+ (<< $,, R/bits >>) -> list(R, Fun, [I|Acc]);
+ (_Any) -> {error, badarg}
+ end)
+ end)
end).
--spec list_separator(binary(), fun()) -> any().
-list_separator(<<>>, Fun) ->
- Fun(<<>>);
-list_separator(<< $,, Rest/bits >>, Fun) ->
- Fun(Rest);
-list_separator(<< C, Rest/bits >>, Fun)
+%% @doc Parse a media range.
+-spec media_range(binary(), fun()) -> any().
+media_range(Data, Fun) ->
+ token_ci(Data,
+ fun (_Rest, <<>>) -> {error, badarg};
+ (Rest, Type) -> whitespace(Rest,
+ fun (<< $/, Rest2/bits >>) -> whitespace(Rest2,
+ fun (<<>>) -> {error, badarg};
+ (Rest3) -> media_range_subtype(Rest3, Fun, Type)
+ end);
+ (_Rest2) -> {error, badarg}
+ end)
+ end).
+
+-spec media_range_subtype(binary(), fun(), binary()) -> any().
+media_range_subtype(Data, Fun, Type) ->
+ token_ci(Data,
+ fun (_Rest, <<>>) -> {error, badarg};
+ (Rest, SubType) -> media_range_params(Rest, Fun, Type, SubType, [])
+ end).
+
+-spec media_range_params(binary(), fun(), binary(), binary(),
+ [{binary(), binary()}]) -> any().
+media_range_params(Data, Fun, Type, SubType, Acc) ->
+ whitespace(Data,
+ fun (<< $;, Rest/bits >>) ->
+ whitespace(Rest,
+ fun (Rest2) ->
+ media_range_param_attr(Rest2, Fun, Type, SubType, Acc)
+ end);
+ (Rest) -> Fun(Rest, {{Type, SubType, lists:reverse(Acc)}, 1000, []})
+ end).
+
+-spec media_range_param_attr(binary(), fun(), binary(), binary(),
+ [{binary(), binary()}]) -> any().
+media_range_param_attr(Data, Fun, Type, SubType, Acc) ->
+ token_ci(Data,
+ fun (_Rest, <<>>) -> {error, badarg};
+ (Rest, Attr) ->
+ whitespace(Rest,
+ fun (<< $=, Rest2/bits >>) ->
+ whitespace(Rest2,
+ fun (<<>>) -> {error, badarg};
+ (Rest3) ->
+ media_range_param_value(Rest3, Fun,
+ Type, SubType, Acc, Attr)
+ end);
+ (_Rest2) ->
+ {error, badarg}
+ end)
+ end).
+
+-spec media_range_param_value(binary(), fun(), binary(), binary(),
+ [{binary(), binary()}], binary()) -> any().
+media_range_param_value(Data, Fun, Type, SubType, Acc, <<"q">>) ->
+ qvalue(Data,
+ fun (Rest, Quality) ->
+ accept_ext(Rest, Fun, Type, SubType, Acc, Quality, [])
+ end);
+media_range_param_value(Data = << $", _/bits >>, Fun,
+ Type, SubType, Acc, Attr) ->
+ quoted_string(Data,
+ fun (Rest, Value) ->
+ media_range_params(Rest, Fun,
+ Type, SubType, [{Attr, Value}|Acc])
+ end);
+media_range_param_value(Data, Fun, Type, SubType, Acc, Attr) ->
+ token(Data,
+ fun (_Rest, <<>>) -> {error, badarg};
+ (Rest, Value) ->
+ media_range_params(Rest, Fun,
+ Type, SubType, [{Attr, Value}|Acc])
+ end).
+
+-spec accept_ext(binary(), fun(), binary(), binary(),
+ [{binary(), binary()}], 0..1000,
+ [{binary(), binary()} | binary()]) -> any().
+accept_ext(Data, Fun, Type, SubType, Params, Quality, Acc) ->
+ whitespace(Data,
+ fun (<< $;, Rest/bits >>) ->
+ whitespace(Rest,
+ fun (Rest2) ->
+ accept_ext_attr(Rest2, Fun,
+ Type, SubType, Params, Quality, Acc)
+ end);
+ (Rest) ->
+ Fun(Rest, {{Type, SubType, lists:reverse(Params)},
+ Quality, lists:reverse(Acc)})
+ end).
+
+-spec accept_ext_attr(binary(), fun(), binary(), binary(),
+ [{binary(), binary()}], 0..1000,
+ [{binary(), binary()} | binary()]) -> any().
+accept_ext_attr(Data, Fun, Type, SubType, Params, Quality, Acc) ->
+ token_ci(Data,
+ fun (_Rest, <<>>) -> {error, badarg};
+ (Rest, Attr) ->
+ whitespace(Rest,
+ fun (<< $=, Rest2/bits >>) ->
+ whitespace(Rest2,
+ fun (<<>>) -> {error, badarg};
+ (Rest3) ->
+ accept_ext_value(Rest3, Fun,
+ Type, SubType, Params,
+ Quality, Acc, Attr)
+ end);
+ (Rest2) ->
+ accept_ext(Rest2, Fun,
+ Type, SubType, Params,
+ Quality, [Attr|Acc])
+ end)
+ end).
+
+-spec accept_ext_value(binary(), fun(), binary(), binary(),
+ [{binary(), binary()}], 0..1000,
+ [{binary(), binary()} | binary()], binary()) -> any().
+accept_ext_value(Data = << $", _/bits >>, Fun,
+ Type, SubType, Params, Quality, Acc, Attr) ->
+ quoted_string(Data,
+ fun (Rest, Value) ->
+ accept_ext(Rest, Fun,
+ Type, SubType, Params, Quality, [{Attr, Value}|Acc])
+ end);
+accept_ext_value(Data, Fun, Type, SubType, Params, Quality, Acc, Attr) ->
+ token(Data,
+ fun (_Rest, <<>>) -> {error, badarg};
+ (Rest, Value) ->
+ accept_ext(Rest, Fun,
+ Type, SubType, Params, Quality, [{Attr, Value}|Acc])
+ end).
+
+%% @doc Parse a charset, followed by an optional quality value.
+-spec charset(binary(), fun()) -> any().
+charset(Data, Fun) ->
+ token_ci(Data,
+ fun (_Rest, <<>>) -> {error, badarg};
+ (Rest, Charset) ->
+ whitespace(Rest,
+ fun (<< $;, Rest2/bits >>) ->
+ whitespace(Rest2,
+ fun (Rest3) ->
+ qparam(Rest3,
+ fun (Rest4, Quality) ->
+ Fun(Rest4, {Charset, Quality})
+ end)
+ end);
+ (Rest2) ->
+ Fun(Rest2, {Charset, 1000})
+ end)
+ end).
+
+%% Parse a quality parameter string (for example q=0.500).
+-spec qparam(binary(), fun()) -> any().
+qparam(<< $q, Rest/bits >>, Fun) ->
+ whitespace(Rest,
+ fun (<< $=, Rest2/bits >>) ->
+ whitespace(Rest2,
+ fun (Rest3) ->
+ qvalue(Rest3,
+ fun (Rest4, Quality) ->
+ Fun(Rest4, Quality)
+ end)
+ end);
+ (_Rest2) ->
+ {error, badarg}
+ end).
+
+%% @doc Skip whitespace.
+-spec whitespace(binary(), fun()) -> any().
+whitespace(<< C, Rest/bits >>, Fun)
when C =:= $\s; C =:= $\t ->
- list_separator(Rest, Fun);
-list_separator(_Data, _Fun) ->
- {error, badarg}.
+ whitespace(Rest, Fun);
+whitespace(Data, Fun) ->
+ Fun(Data).
%% @doc Parse a case-insensitive token.
%%
%% Changes all characters to lowercase.
-spec token_ci(binary(), fun()) -> any().
token_ci(Data, Fun) ->
- token(Data, Fun, ci).
+ token(Data, Fun, ci, <<>>).
%% @doc Parse a token.
-spec token(binary(), fun()) -> any().
token(Data, Fun) ->
- token(Data, Fun, cs).
-
--spec token(binary(), fun(), ci | cs) -> any().
-token(<< C, Rest/bits >>, Fun, Case)
- when C =:= $\s; C =:= $\t ->
- token(Rest, Fun, Case);
-token(Data, Fun, Case) ->
- token(Data, Fun, Case, <<>>).
+ token(Data, Fun, cs, <<>>).
-spec token(binary(), fun(), ci | cs, binary()) -> any().
token(<<>>, Fun, _Case, Acc) ->
@@ -108,6 +268,48 @@ token(<< C, Rest/bits >>, Fun, Case = ci, Acc) ->
token(<< C, Rest/bits >>, Fun, Case, Acc) ->
token(Rest, Fun, Case, << Acc/binary, C >>).
+%% @doc Parse a quoted string.
+-spec quoted_string(binary(), fun()) -> any().
+quoted_string(<< $", Rest/bits >>, Fun) ->
+ quoted_string(Rest, Fun, <<>>).
+
+-spec quoted_string(binary(), fun(), binary()) -> any().
+quoted_string(<<>>, _Fun, _Acc) ->
+ {error, badarg};
+quoted_string(<< $", Rest/bits >>, Fun, Acc) ->
+ Fun(Rest, Acc);
+quoted_string(<< $\\, C, Rest/bits >>, Fun, Acc) ->
+ quoted_string(Rest, Fun, << Acc/binary, C >>);
+quoted_string(<< C, Rest/bits >>, Fun, Acc) ->
+ quoted_string(Rest, Fun, << Acc/binary, C >>).
+
+%% @doc Parse a quality value.
+-spec qvalue(binary(), fun()) -> any().
+qvalue(<< $0, $., Rest/bits >>, Fun) ->
+ qvalue(Rest, Fun, 0, 100);
+qvalue(<< $0, Rest/bits >>, Fun) ->
+ Fun(Rest, 0);
+qvalue(<< $1, $., $0, $0, $0, Rest/bits >>, Fun) ->
+ Fun(Rest, 1000);
+qvalue(<< $1, $., $0, $0, Rest/bits >>, Fun) ->
+ Fun(Rest, 1000);
+qvalue(<< $1, $., $0, Rest/bits >>, Fun) ->
+ Fun(Rest, 1000);
+qvalue(<< $1, Rest/bits >>, Fun) ->
+ Fun(Rest, 1000);
+qvalue(_Data, _Fun) ->
+ {error, badarg}.
+
+-spec qvalue(binary(), fun(), integer(), 1 | 10 | 100) -> any().
+qvalue(Data, Fun, Q, 0) ->
+ Fun(Data, Q);
+qvalue(<< C, Rest/bits >>, Fun, Q, M)
+ when C =:= $0; C =:= $1; C =:= $2; C =:= $3; C =:= $4;
+ C =:= $5; C =:= $6; C =:= $7; C =:= $8; C =:= $9 ->
+ qvalue(Rest, Fun, Q + (C - $0) * M, M div 10);
+qvalue(Data, Fun, Q, _M) ->
+ Fun(Data, Q).
+
%% Interpretation.
%% @doc Walk through a tokens list and return whether
@@ -128,6 +330,17 @@ connection_to_atom([_Any|Tail]) ->
-ifdef(TEST).
+nonempty_charset_list_test_() ->
+ %% {Value, Result}
+ Tests = [
+ {<<>>, {error, badarg}},
+ {<<"iso-8859-5, unicode-1-1;q=0.8">>, [
+ {<<"iso-8859-5">>, 1000},
+ {<<"unicode-1-1">>, 800}
+ ]}
+ ],
+ [{V, fun() -> R = nonempty_list(V, fun charset/2) end} || {V, R} <- Tests].
+
nonempty_token_list_test_() ->
%% {Value, Result}
Tests = [
@@ -144,6 +357,44 @@ nonempty_token_list_test_() ->
],
[{V, fun() -> R = nonempty_list(V, fun token/2) end} || {V, R} <- Tests].
+media_range_list_test_() ->
+ %% {Tokens, Result}
+ Tests = [
+ {<<"audio/*; q=0.2, audio/basic">>, [
+ {{<<"audio">>, <<"*">>, []}, 200, []},
+ {{<<"audio">>, <<"basic">>, []}, 1000, []}
+ ]},
+ {<<"text/plain; q=0.5, text/html, "
+ "text/x-dvi; q=0.8, text/x-c">>, [
+ {{<<"text">>, <<"plain">>, []}, 500, []},
+ {{<<"text">>, <<"html">>, []}, 1000, []},
+ {{<<"text">>, <<"x-dvi">>, []}, 800, []},
+ {{<<"text">>, <<"x-c">>, []}, 1000, []}
+ ]},
+ {<<"text/*, text/html, text/html;level=1, */*">>, [
+ {{<<"text">>, <<"*">>, []}, 1000, []},
+ {{<<"text">>, <<"html">>, []}, 1000, []},
+ {{<<"text">>, <<"html">>, [{<<"level">>, <<"1">>}]}, 1000, []},
+ {{<<"*">>, <<"*">>, []}, 1000, []}
+ ]},
+ {<<"text/*;q=0.3, text/html;q=0.7, text/html;level=1, "
+ "text/html;level=2;q=0.4, */*;q=0.5">>, [
+ {{<<"text">>, <<"*">>, []}, 300, []},
+ {{<<"text">>, <<"html">>, []}, 700, []},
+ {{<<"text">>, <<"html">>, [{<<"level">>, <<"1">>}]}, 1000, []},
+ {{<<"text">>, <<"html">>, [{<<"level">>, <<"2">>}]}, 400, []},
+ {{<<"*">>, <<"*">>, []}, 500, []}
+ ]},
+ {<<"text/html;level=1;quoted=\"hi hi hi\";"
+ "q=0.123;standalone;complex=gits, text/plain">>, [
+ {{<<"text">>, <<"html">>,
+ [{<<"level">>, <<"1">>}, {<<"quoted">>, <<"hi hi hi">>}]}, 123,
+ [<<"standalone">>, {<<"complex">>, <<"gits">>}]},
+ {{<<"text">>, <<"plain">>, []}, 1000, []}
+ ]}
+ ],
+ [{V, fun() -> R = list(V, fun media_range/2) end} || {V, R} <- Tests].
+
connection_to_atom_test_() ->
%% {Tokens, Result}
Tests = [
diff --git a/src/cowboy_http_protocol.erl b/src/cowboy_http_protocol.erl
index b91101a..b0ee590 100644
--- a/src/cowboy_http_protocol.erl
+++ b/src/cowboy_http_protocol.erl
@@ -172,7 +172,7 @@ header({http_header, _I, 'Host', _R, _V}, Req, State) ->
header({http_header, _I, 'Connection', _R, Connection},
Req=#http_req{headers=Headers}, State) ->
Req2 = Req#http_req{headers=[{'Connection', Connection}|Headers]},
- {tokens, ConnTokens, Req3}
+ {ConnTokens, Req3}
= cowboy_http_req:parse_header('Connection', Req2),
ConnAtom = cowboy_http:connection_to_atom(ConnTokens),
parse_header(Req3#http_req{connection=ConnAtom}, State);
diff --git a/src/cowboy_http_req.erl b/src/cowboy_http_req.erl
index 539c7f0..3a3dd2f 100644
--- a/src/cowboy_http_req.erl
+++ b/src/cowboy_http_req.erl
@@ -191,47 +191,62 @@ headers(Req) ->
%% returned is used as a return value.
%% @see parse_header/3
-spec parse_header(http_header(), #http_req{})
- -> {tokens, [binary()], #http_req{}}
- | {undefined, binary(), #http_req{}}
- | {error, badarg}.
-parse_header('Connection', Req) ->
- parse_header('Connection', Req, []);
-parse_header(Name, Req) ->
- parse_header(Name, Req, undefined).
+ -> {any(), #http_req{}} | {error, badarg}.
+parse_header(Name, Req=#http_req{p_headers=PHeaders}) ->
+ case lists:keyfind(Name, 1, PHeaders) of
+ false -> parse_header(Name, Req, parse_header_default(Name));
+ {Name, Value} -> {Value, Req}
+ end.
+
+%% @doc Default values for semantic header parsing.
+-spec parse_header_default(http_header()) -> any().
+parse_header_default('Accept') -> [];
+parse_header_default('Accept-Charset') -> [];
+parse_header_default('Accept-Encoding') -> [];
+parse_header_default('Connection') -> [];
+parse_header_default(_Name) -> undefined.
%% @doc Semantically parse headers.
%%
-%% When the header is known, a named tuple is returned containing
-%% {Type, P, Req} with Type being the type of value found in P.
-%% For example, the header 'Connection' is a list of tokens, therefore
-%% the value returned will be a list of binary values and Type will be
-%% 'tokens'.
-%%
-%% When the header is known but not found, the tuple {Type, Default, Req}
-%% is returned instead.
-%%
-%% When the header is unknown, the value is returned directly as an
-%% 'undefined' tagged tuple.
+%% When the header is unknown, the value is returned directly without parsing.
-spec parse_header(http_header(), #http_req{}, any())
- -> {tokens, [binary()], #http_req{}}
- | {undefined, binary(), #http_req{}}
- | {error, badarg}.
-parse_header(Name, Req=#http_req{p_headers=PHeaders}, Default)
- when Name =:= 'Connection' ->
+ -> {any(), #http_req{}} | {error, badarg}.
+parse_header(Name, Req, Default) when Name =:= 'Accept' ->
+ parse_header(Name, Req, Default,
+ fun (Value) ->
+ cowboy_http:list(Value, fun cowboy_http:media_range/2)
+ end);
+parse_header(Name, Req, Default) when Name =:= 'Accept-Charset' ->
+ parse_header(Name, Req, Default,
+ fun (Value) ->
+ cowboy_http:nonempty_list(Value, fun cowboy_http:charset/2)
+ end);
+parse_header(Name, Req, Default) when Name =:= 'Accept-Encoding' ->
+ parse_header(Name, Req, Default,
+ fun (Value) ->
+ cowboy_http:list(Value, fun cowboy_http:token_ci/2)
+ end);
+parse_header(Name, Req, Default) when Name =:= 'Connection' ->
+ parse_header(Name, Req, Default,
+ fun (Value) ->
+ cowboy_http:nonempty_list(Value, fun cowboy_http:token_ci/2)
+ end);
+parse_header(Name, Req, Default) ->
+ {Value, Req2} = header(Name, Req, Default),
+ {undefined, Value, Req2}.
+
+parse_header(Name, Req=#http_req{p_headers=PHeaders}, Default, Fun) ->
case header(Name, Req) of
- {undefined, Req2} -> {tokens, Default, Req2};
+ {undefined, Req2} ->
+ {Default, Req2#http_req{p_headers=[{Name, Default}|PHeaders]}};
{Value, Req2} ->
- case cowboy_http:nonempty_list(Value, fun cowboy_http:token_ci/2) of
+ case Fun(Value) of
{error, badarg} ->
{error, badarg};
P ->
- {tokens, P, Req2#http_req{
- p_headers=[{Name, P}|PHeaders]}}
+ {P, Req2#http_req{p_headers=[{Name, P}|PHeaders]}}
end
- end;
-parse_header(Name, Req, Default) ->
- {Value, Req2} = header(Name, Req, Default),
- {undefined, Value, Req2}.
+ end.
%% @equiv cookie(Name, Req, undefined)
-spec cookie(binary(), #http_req{})
@@ -368,7 +383,7 @@ chunked_reply(Status, Headers, Req=#http_req{socket=Socket, transport=Transport,
%% @doc Send a chunk of data.
%%
%% A chunked reply must have been initiated before calling this function.
--spec chunk(iodata(), #http_req{}) -> ok.
+-spec chunk(iodata(), #http_req{}) -> ok | {error, atom()}.
chunk(_Data, #http_req{socket=_Socket, transport=_Transport, method='HEAD'}) ->
ok;
chunk(Data, #http_req{socket=Socket, transport=Transport, resp_state=chunks}) ->
diff --git a/src/cowboy_http_websocket.erl b/src/cowboy_http_websocket.erl
index d378a2a..08a0c90 100644
--- a/src/cowboy_http_websocket.erl
+++ b/src/cowboy_http_websocket.erl
@@ -77,7 +77,7 @@ upgrade(ListenerPid, Handler, Opts, Req) ->
%% @todo Upgrade is a list of products and should be parsed as such.
-spec websocket_upgrade(#state{}, #http_req{}) -> {ok, #state{}, #http_req{}}.
websocket_upgrade(State, Req) ->
- {tokens, ConnTokens, Req2}
+ {ConnTokens, Req2}
= cowboy_http_req:parse_header('Connection', Req),
true = lists:member(<<"upgrade">>, ConnTokens),
{WS, Req3} = cowboy_http_req:header('Upgrade', Req2),
@@ -378,11 +378,11 @@ handler_call(State=#state{handler=Handler, opts=Opts}, Req, HandlerState,
websocket_close(State, Req2, HandlerState2, {normal, shutdown})
catch Class:Reason ->
error_logger:error_msg(
- "** Handler ~p terminating in websocket_handle/3~n"
+ "** Handler ~p terminating in ~p/3~n"
" for the reason ~p:~p~n** Message was ~p~n"
"** Options were ~p~n** Handler state was ~p~n"
"** Request was ~p~n** Stacktrace: ~p~n~n",
- [Handler, Class, Reason, Message, Opts,
+ [Handler, Callback, Class, Reason, Message, Opts,
HandlerState, Req, erlang:get_stacktrace()]),
websocket_close(State, Req, HandlerState, {error, handler})
end.
diff --git a/src/cowboy_listener.erl b/src/cowboy_listener.erl
index 8b656ba..c19d079 100644
--- a/src/cowboy_listener.erl
+++ b/src/cowboy_listener.erl
@@ -30,9 +30,15 @@
%% API.
%% @private
+%%
+%% We set the process priority to high because cowboy_listener is the central
+%% gen_server in Cowboy and is used to manage all the incoming connections.
+%% Setting the process priority to high ensures the connection-related code
+%% will always be executed when a connection needs it, allowing Cowboy to
+%% scale far beyond what it would with a normal priority.
-spec start_link() -> {ok, pid()}.
start_link() ->
- gen_server:start_link(?MODULE, [], []).
+ gen_server:start_link(?MODULE, [], [{spawn_opt, [{priority, high}]}]).
%% @private
-spec stop(pid()) -> stopped.
diff --git a/src/cowboy_listener_sup.erl b/src/cowboy_listener_sup.erl
index adf5262..aca2b0b 100644
--- a/src/cowboy_listener_sup.erl
+++ b/src/cowboy_listener_sup.erl
@@ -27,7 +27,7 @@ start_link(NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts) ->
{ok, SupPid} = supervisor:start_link(?MODULE, []),
{ok, ListenerPid} = supervisor:start_child(SupPid,
{cowboy_listener, {cowboy_listener, start_link, []},
- permanent, 5000, worker, dynamic}),
+ permanent, 5000, worker, [cowboy_listener]}),
{ok, ReqsPid} = supervisor:start_child(SupPid,
{cowboy_requests_sup, {cowboy_requests_sup, start_link, []},
permanent, 5000, supervisor, [cowboy_requests_sup]}),
diff --git a/src/cowboy_sup.erl b/src/cowboy_sup.erl
index 9c52486..34591bc 100644
--- a/src/cowboy_sup.erl
+++ b/src/cowboy_sup.erl
@@ -32,5 +32,5 @@ start_link() ->
-spec init([]) -> {ok, {{one_for_one, 10, 10}, [{_, _, _, _, _, _}, ...]}}.
init([]) ->
Procs = [{cowboy_clock, {cowboy_clock, start_link, []},
- permanent, 5000, worker, dynamic}],
+ permanent, 5000, worker, [cowboy_clock]}],
{ok, {{one_for_one, 10, 10}, Procs}}.