<commit_before>%% Copyright (c) 2011-2013, <NAME> <<EMAIL>>
%% Copyright (c) 2011, <NAME> <<EMAIL>>
%%
%% Permission to use, copy, modify, and/or distribute this software for any
%% purpose with or without fee is hereby granted, provided that the above
%% copyright notice and this permission notice appear in all copies.
%%
%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
%% 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 infinity.</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.
-export([start_link/4]).

%% Internal.
-export([init/4]).
-export([parse_request/3]).
-export([resume/6]).

-type onrequest_fun() :: fun((Req) -> Req).
-type onresponse_fun() ::
	fun((cowboy_http:status(), cowboy_http:headers(), iodata(), Req) -> Req).
-export_type([onrequest_fun/0]).
-export_type([onresponse_fun/0]).

-record(state, {
	socket :: inet:socket(),
	transport :: module(),
	middlewares :: [module()],
	compress :: boolean(),
	env :: cowboy_middleware:env(),
	onrequest :: undefined | onrequest_fun(),
	onresponse = undefined :: undefined | onresponse_fun(),
	max_empty_lines :: non_neg_integer(),
	req_keepalive = 1 :: non_neg_integer(),
	max_keepalive :: non_neg_integer(),
	max_request_line_length :: non_neg_integer(),
	max_header_name_length :: non_neg_integer(),
	max_header_value_length :: non_neg_integer(),
	max_headers :: non_neg_integer(),
	timeout :: timeout(),
	until :: non_neg_integer() | infinity
}).

%% API.

%% @doc Start an HTTP protocol process.
-spec start_link(pid(), inet:socket(), module(), any()) -> {ok, pid()}.
start_link(ListenerPid, Socket, Transport, Opts) ->
	Pid = spawn_link(?MODULE, init, [ListenerPid, Socket, Transport, Opts]),
	{ok, Pid}.

%% Internal.

%% @doc Faster alternative to proplists:get_value/3.
%% @private
get_value(Key, Opts, Default) ->
	case lists:keyfind(Key, 1, Opts) of
		{_, Value} -> Value;
		_ -> Default
	end.

%% @private
-spec init(pid(), inet:socket(), module(), any()) -> ok.
init(ListenerPid, Socket, Transport, Opts) ->
	Compress = get_value(compress, Opts, false),
	MaxEmptyLines = get_value(max_empty_lines, Opts, 5),
	MaxHeaderNameLength = get_value(max_header_name_length, Opts, 64),
	MaxHeaderValueLength = get_value(max_header_value_length, Opts, 4096),
	MaxHeaders = get_value(max_headers, Opts, 100),
	MaxKeepalive = get_value(max_keepalive, Opts, infinity),
	MaxRequestLineLength = get_value(max_request_line_length, Opts, 4096),
	Middlewares = get_value(middlewares, Opts, [cowboy_router, cowboy_handler]),
	Env = [{listener, ListenerPid}|get_value(env, Opts, [])],
	OnRequest = get_value(onrequest, Opts, undefined),
	OnResponse = get_value(onresponse, Opts, undefined),
	Timeout = get_value(timeout, Opts, 5000),
	ok = ranch:accept_ack(ListenerPid),
	wait_request(<<>>, #state{socket=Socket, transport=Transport,
		middlewares=Middlewares, compress=Compress, env=Env,
		max_empty_lines=MaxEmptyLines, max_keepalive=MaxKeepalive,
		max_request_line_length=MaxRequestLineLength,
		max_header_name_length=MaxHeaderNameLength,
		max_header_value_length=MaxHeaderValueLength, max_headers=MaxHeaders,
		onrequest=OnRequest, onresponse=OnResponse,
		timeout=Timeout, until=until(Timeout)}, 0).

-spec until(timeout()) -> non_neg_integer() | infinity.
until(infinity) ->
	infinity;<commit_msg>Set max_keepalive default to 100 instead of infinity<commit_after>%% Copyright (c) 2011-2013, <NAME> <<EMAIL>>
%% Copyright (c) 2011, <NAME> <<EMAIL>>
%%
%% Permission to use, copy, modify, and/or distribute this software for any
%% purpose with or without fee is hereby granted, provided that the above
%% copyright notice and this permission notice appear in all copies.
%%
%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
%% 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.
-export([start_link/4]).

%% Internal.
-export([init/4]).
-export([parse_request/3]).
-export([resume/6]).

-type onrequest_fun() :: fun((Req) -> Req).
-type onresponse_fun() ::
	fun((cowboy_http:status(), cowboy_http:headers(), iodata(), Req) -> Req).
-export_type([onrequest_fun/0]).
-export_type([onresponse_fun/0]).

-record(state, {
	socket :: inet:socket(),
	transport :: module(),
	middlewares :: [module()],
	compress :: boolean(),
	env :: cowboy_middleware:env(),
	onrequest :: undefined | onrequest_fun(),
	onresponse = undefined :: undefined | onresponse_fun(),
	max_empty_lines :: non_neg_integer(),
	req_keepalive = 1 :: non_neg_integer(),
	max_keepalive :: non_neg_integer(),
	max_request_line_length :: non_neg_integer(),
	max_header_name_length :: non_neg_integer(),
	max_header_value_length :: non_neg_integer(),
	max_headers :: non_neg_integer(),
	timeout :: timeout(),
	until :: non_neg_integer() | infinity
}).

%% API.

%% @doc Start an HTTP protocol process.
-spec start_link(pid(), inet:socket(), module(), any()) -> {ok, pid()}.
start_link(ListenerPid, Socket, Transport, Opts) ->
	Pid = spawn_link(?MODULE, init, [ListenerPid, Socket, Transport, Opts]),
	{ok, Pid}.

%% Internal.

%% @doc Faster alternative to proplists:get_value/3.
%% @private
get_value(Key, Opts, Default) ->
	case lists:keyfind(Key, 1, Opts) of
		{_, Value} -> Value;
		_ -> Default
	end.

%% @private
-spec init(pid(), inet:socket(), module(), any()) -> ok.
init(ListenerPid, Socket, Transport, Opts) ->
	Compress = get_value(compress, Opts, false),
	MaxEmptyLines = get_value(max_empty_lines, Opts, 5),
	MaxHeaderNameLength = get_value(max_header_name_length, Opts, 64),
	MaxHeaderValueLength = get_value(max_header_value_length, Opts, 4096),
	MaxHeaders = get_value(max_headers, Opts, 100),
	MaxKeepalive = get_value(max_keepalive, Opts, 100),
	MaxRequestLineLength = get_value(max_request_line_length, Opts, 4096),
	Middlewares = get_value(middlewares, Opts, [cowboy_router, cowboy_handler]),
	Env = [{listener, ListenerPid}|get_value(env, Opts, [])],
	OnRequest = get_value(onrequest, Opts, undefined),
	OnResponse = get_value(onresponse, Opts, undefined),
	Timeout = get_value(timeout, Opts, 5000),
	ok = ranch:accept_ack(ListenerPid),
	wait_request(<<>>, #state{socket=Socket, transport=Transport,
		middlewares=Middlewares, compress=Compress, env=Env,
		max_empty_lines=MaxEmptyLines, max_keepalive=MaxKeepalive,
		max_request_line_length=MaxRequestLineLength,
		max_header_name_length=MaxHeaderNameLength,
		max_header_value_length=MaxHeaderValueLength, max_headers=MaxHeaders,
		onrequest=OnRequest, onresponse=OnResponse,
		timeout=Timeout, until=until(Timeout)}, 0).

-spec until(timeout()) -> non_neg_integer() | infinity.
until(infinity) ->
	infinity;
{'fraction_non_alphanumeric': 0.13723454459650777, 'fraction_numerical': 0.011798017932987258, 'mean_word_length': 5.5085995085995085, 'pattern_counts': {'":': 0, '<': 119, '<?xml version=': 0, '>': 141, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3272416', 'n_tokens_mistral': 3554, 'n_tokens_neox': 3358, 'n_words': 992}