You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by rn...@apache.org on 2015/07/29 17:54:50 UTC
[21/50] mochiweb commit: updated refs/heads/upstream to b66b68d
Add recbuf config option.
Project: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/commit/ae0b9aad
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/tree/ae0b9aad
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/diff/ae0b9aad
Branch: refs/heads/upstream
Commit: ae0b9aadead08b87a59e83bd8cce62ea40ab5bb2
Parents: 66a6535
Author: Churikov Daniil <dd...@gmail.com>
Authored: Fri Sep 5 18:20:31 2014 +0400
Committer: Daniil Churikov <dc...@alertlogic.com>
Committed: Tue Nov 18 14:01:59 2014 +0300
----------------------------------------------------------------------
src/mochiweb.erl | 7 +-
src/mochiweb_acceptor.erl | 29 ++++---
src/mochiweb_http.erl | 54 ++++++------
src/mochiweb_multipart.erl | 18 ++--
src/mochiweb_request.erl | 133 +++++++++++++++--------------
src/mochiweb_socket.erl | 7 +-
src/mochiweb_socket_server.erl | 40 +++++++--
test/mochiweb_socket_server_tests.erl | 2 +-
8 files changed, 169 insertions(+), 121 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/ae0b9aad/src/mochiweb.erl
----------------------------------------------------------------------
diff --git a/src/mochiweb.erl b/src/mochiweb.erl
index 927322d..5c4201c 100644
--- a/src/mochiweb.erl
+++ b/src/mochiweb.erl
@@ -51,10 +51,15 @@ uri({scheme, Hostname, Port}) ->
uri(HttpString) when is_list(HttpString) ->
HttpString.
-%% @spec new_request({Socket, Request, Headers}) -> MochiWebRequest
+%% @spec new_request( {Socket, Request, Headers}
+%% | {Socket, Opts, Request, Headers} ) -> MochiWebRequest
%% @doc Return a mochiweb_request data structure.
new_request({Socket, {Method, HttpUri, Version}, Headers}) ->
+ new_request({Socket, [], {Method, HttpUri, Version}, Headers});
+
+new_request({Socket, Opts, {Method, HttpUri, Version}, Headers}) ->
mochiweb_request:new(Socket,
+ Opts,
Method,
uri(HttpUri),
Version,
http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/ae0b9aad/src/mochiweb_acceptor.erl
----------------------------------------------------------------------
diff --git a/src/mochiweb_acceptor.erl b/src/mochiweb_acceptor.erl
index ebbaf45..208f861 100644
--- a/src/mochiweb_acceptor.erl
+++ b/src/mochiweb_acceptor.erl
@@ -8,21 +8,24 @@
-include("internal.hrl").
--export([start_link/3, init/3]).
+-export([start_link/3, start_link/4, init/4]).
start_link(Server, Listen, Loop) ->
- proc_lib:spawn_link(?MODULE, init, [Server, Listen, Loop]).
+ start_link(Server, Listen, Loop, []).
-init(Server, Listen, Loop) ->
+start_link(Server, Listen, Loop, Opts) ->
+ proc_lib:spawn_link(?MODULE, init, [Server, Listen, Loop, Opts]).
+
+init(Server, Listen, Loop, Opts) ->
T1 = os:timestamp(),
case catch mochiweb_socket:accept(Listen) of
{ok, Socket} ->
gen_server:cast(Server, {accepted, self(), timer:now_diff(os:timestamp(), T1)}),
- call_loop(Loop, Socket);
+ call_loop(Loop, Socket, Opts);
{error, closed} ->
exit(normal);
{error, timeout} ->
- init(Server, Listen, Loop);
+ init(Server, Listen, Loop, Opts);
{error, esslaccept} ->
exit(normal);
Other ->
@@ -33,14 +36,14 @@ init(Server, Listen, Loop) ->
exit({error, accept_failed})
end.
-call_loop({M, F}, Socket) ->
- M:F(Socket);
-call_loop({M, F, [A1]}, Socket) ->
- M:F(Socket, A1);
-call_loop({M, F, A}, Socket) ->
- erlang:apply(M, F, [Socket | A]);
-call_loop(Loop, Socket) ->
- Loop(Socket).
+call_loop({M, F}, Socket, Opts) ->
+ M:F(Socket, Opts);
+call_loop({M, F, [A1]}, Socket, Opts) ->
+ M:F(Socket, Opts, A1);
+call_loop({M, F, A}, Socket, Opts) ->
+ erlang:apply(M, F, [Socket, Opts | A]);
+call_loop(Loop, Socket, Opts) ->
+ Loop(Socket, Opts).
%%
%% Tests
http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/ae0b9aad/src/mochiweb_http.erl
----------------------------------------------------------------------
diff --git a/src/mochiweb_http.erl b/src/mochiweb_http.erl
index 38d51d4..e3c56fa 100644
--- a/src/mochiweb_http.erl
+++ b/src/mochiweb_http.erl
@@ -6,7 +6,7 @@
-module(mochiweb_http).
-author('bob@mochimedia.com').
-export([start/1, start_link/1, stop/0, stop/1]).
--export([loop/2]).
+-export([loop/3]).
-export([after_response/2, reentry/1]).
-export([parse_range_request/1, range_skip_length/2]).
@@ -40,7 +40,7 @@ stop(Name) ->
%% Option = {name, atom()} | {ip, string() | tuple()} | {backlog, integer()}
%% | {nodelay, boolean()} | {acceptor_pool_size, integer()}
%% | {ssl, boolean()} | {profile_fun, undefined | (Props) -> ok}
-%% | {link, false}
+%% | {link, false} | {recbuf, non_negative_integer()}
%% @doc Start a mochiweb server.
%% profile_fun is used to profile accept timing.
%% After each accept, if defined, profile_fun is called with a proplist of a subset of the mochiweb_socket_server state and timing information.
@@ -52,20 +52,20 @@ start(Options) ->
start_link(Options) ->
mochiweb_socket_server:start_link(parse_options(Options)).
-loop(Socket, Body) ->
+loop(Socket, Opts, Body) ->
ok = mochiweb_socket:setopts(Socket, [{packet, http}]),
- request(Socket, Body).
+ request(Socket, Opts, Body).
-request(Socket, Body) ->
+request(Socket, Opts, Body) ->
ok = mochiweb_socket:setopts(Socket, [{active, once}]),
receive
{Protocol, _, {http_request, Method, Path, Version}} when Protocol == http orelse Protocol == ssl ->
ok = mochiweb_socket:setopts(Socket, [{packet, httph}]),
- headers(Socket, {Method, Path, Version}, [], Body, 0);
+ headers(Socket, Opts, {Method, Path, Version}, [], Body, 0);
{Protocol, _, {http_error, "\r\n"}} when Protocol == http orelse Protocol == ssl ->
- request(Socket, Body);
+ request(Socket, Opts, Body);
{Protocol, _, {http_error, "\n"}} when Protocol == http orelse Protocol == ssl ->
- request(Socket, Body);
+ request(Socket, Opts, Body);
{tcp_closed, _} ->
mochiweb_socket:close(Socket),
exit(normal);
@@ -73,7 +73,7 @@ request(Socket, Body) ->
mochiweb_socket:close(Socket),
exit(normal);
Other ->
- handle_invalid_msg_request(Other, Socket)
+ handle_invalid_msg_request(Other, Socket, Opts)
after ?REQUEST_RECV_TIMEOUT ->
mochiweb_socket:close(Socket),
exit(normal)
@@ -84,25 +84,25 @@ reentry(Body) ->
?MODULE:after_response(Body, Req)
end.
-headers(Socket, Request, Headers, _Body, ?MAX_HEADERS) ->
+headers(Socket, Opts, Request, Headers, _Body, ?MAX_HEADERS) ->
%% Too many headers sent, bad request.
ok = mochiweb_socket:setopts(Socket, [{packet, raw}]),
- handle_invalid_request(Socket, Request, Headers);
-headers(Socket, Request, Headers, Body, HeaderCount) ->
+ handle_invalid_request(Socket, Opts, Request, Headers);
+headers(Socket, Opts, Request, Headers, Body, HeaderCount) ->
ok = mochiweb_socket:setopts(Socket, [{active, once}]),
receive
{Protocol, _, http_eoh} when Protocol == http orelse Protocol == ssl ->
- Req = new_request(Socket, Request, Headers),
+ Req = new_request(Socket, Opts, Request, Headers),
call_body(Body, Req),
?MODULE:after_response(Body, Req);
{Protocol, _, {http_header, _, Name, _, Value}} when Protocol == http orelse Protocol == ssl ->
- headers(Socket, Request, [{Name, Value} | Headers], Body,
+ headers(Socket, Opts, Request, [{Name, Value} | Headers], Body,
1 + HeaderCount);
{tcp_closed, _} ->
mochiweb_socket:close(Socket),
exit(normal);
Other ->
- handle_invalid_msg_request(Other, Socket, Request, Headers)
+ handle_invalid_msg_request(Other, Socket, Opts, Request, Headers)
after ?HEADERS_RECV_TIMEOUT ->
mochiweb_socket:close(Socket),
exit(normal)
@@ -115,31 +115,31 @@ call_body({M, F}, Req) ->
call_body(Body, Req) ->
Body(Req).
--spec handle_invalid_msg_request(term(), term()) -> no_return().
-handle_invalid_msg_request(Msg, Socket) ->
- handle_invalid_msg_request(Msg, Socket, {'GET', {abs_path, "/"}, {0,9}}, []).
+-spec handle_invalid_msg_request(term(), term(), term()) -> no_return().
+handle_invalid_msg_request(Msg, Socket, Opts) ->
+ handle_invalid_msg_request(Msg, Socket, Opts, {'GET', {abs_path, "/"}, {0,9}}, []).
--spec handle_invalid_msg_request(term(), term(), term(), term()) -> no_return().
-handle_invalid_msg_request(Msg, Socket, Request, RevHeaders) ->
+-spec handle_invalid_msg_request(term(), term(), term(), term(), term()) -> no_return().
+handle_invalid_msg_request(Msg, Socket, Opts, Request, RevHeaders) ->
case {Msg, r15b_workaround()} of
{{tcp_error,_,emsgsize}, true} ->
%% R15B02 returns this then closes the socket, so close and exit
mochiweb_socket:close(Socket),
exit(normal);
_ ->
- handle_invalid_request(Socket, Request, RevHeaders)
+ handle_invalid_request(Socket, Opts, Request, RevHeaders)
end.
--spec handle_invalid_request(term(), term(), term()) -> no_return().
-handle_invalid_request(Socket, Request, RevHeaders) ->
- Req = new_request(Socket, Request, RevHeaders),
+-spec handle_invalid_request(term(), term(), term(), term()) -> no_return().
+handle_invalid_request(Socket, Opts, Request, RevHeaders) ->
+ Req = new_request(Socket, Opts, Request, RevHeaders),
Req:respond({400, [], []}),
mochiweb_socket:close(Socket),
exit(normal).
-new_request(Socket, Request, RevHeaders) ->
+new_request(Socket, Opts, Request, RevHeaders) ->
ok = mochiweb_socket:setopts(Socket, [{packet, raw}]),
- mochiweb:new_request({Socket, Request, lists:reverse(RevHeaders)}).
+ mochiweb:new_request({Socket, Opts, Request, lists:reverse(RevHeaders)}).
after_response(Body, Req) ->
Socket = Req:get(socket),
@@ -150,7 +150,7 @@ after_response(Body, Req) ->
false ->
Req:cleanup(),
erlang:garbage_collect(),
- ?MODULE:loop(Socket, Body)
+ ?MODULE:loop(Socket, mochiweb_request:get(opts, Req), Body)
end.
parse_range_request("bytes=0-") ->
http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/ae0b9aad/src/mochiweb_multipart.erl
----------------------------------------------------------------------
diff --git a/src/mochiweb_multipart.erl b/src/mochiweb_multipart.erl
index a83a88c..90bc949 100644
--- a/src/mochiweb_multipart.erl
+++ b/src/mochiweb_multipart.erl
@@ -374,7 +374,7 @@ parse3(Transport) ->
body_end,
eof],
TestCallback = fun (Next) -> test_callback(Next, Expect) end,
- ServerFun = fun (Socket) ->
+ ServerFun = fun (Socket, _Opts) ->
ok = mochiweb_socket:send(Socket, BinContent),
exit(normal)
end,
@@ -410,7 +410,7 @@ parse2(Transport) ->
body_end,
eof],
TestCallback = fun (Next) -> test_callback(Next, Expect) end,
- ServerFun = fun (Socket) ->
+ ServerFun = fun (Socket, _Opts) ->
ok = mochiweb_socket:send(Socket, BinContent),
exit(normal)
end,
@@ -447,7 +447,7 @@ do_parse_form(Transport) ->
"--AaB03x--",
""], "\r\n"),
BinContent = iolist_to_binary(Content),
- ServerFun = fun (Socket) ->
+ ServerFun = fun (Socket, _Opts) ->
ok = mochiweb_socket:send(Socket, BinContent),
exit(normal)
end,
@@ -500,7 +500,7 @@ do_parse(Transport) ->
body_end,
eof],
TestCallback = fun (Next) -> test_callback(Next, Expect) end,
- ServerFun = fun (Socket) ->
+ ServerFun = fun (Socket, _Opts) ->
ok = mochiweb_socket:send(Socket, BinContent),
exit(normal)
end,
@@ -552,7 +552,7 @@ parse_partial_body_boundary(Transport) ->
body_end,
eof],
TestCallback = fun (Next) -> test_callback(Next, Expect) end,
- ServerFun = fun (Socket) ->
+ ServerFun = fun (Socket, _Opts) ->
ok = mochiweb_socket:send(Socket, BinContent),
exit(normal)
end,
@@ -605,7 +605,7 @@ parse_large_header(Transport) ->
body_end,
eof],
TestCallback = fun (Next) -> test_callback(Next, Expect) end,
- ServerFun = fun (Socket) ->
+ ServerFun = fun (Socket, _Opts) ->
ok = mochiweb_socket:send(Socket, BinContent),
exit(normal)
end,
@@ -681,7 +681,7 @@ flash_parse(Transport) ->
body_end,
eof],
TestCallback = fun (Next) -> test_callback(Next, Expect) end,
- ServerFun = fun (Socket) ->
+ ServerFun = fun (Socket, _Opts) ->
ok = mochiweb_socket:send(Socket, BinContent),
exit(normal)
end,
@@ -729,7 +729,7 @@ flash_parse2(Transport) ->
body_end,
eof],
TestCallback = fun (Next) -> test_callback(Next, Expect) end,
- ServerFun = fun (Socket) ->
+ ServerFun = fun (Socket, _Opts) ->
ok = mochiweb_socket:send(Socket, BinContent),
exit(normal)
end,
@@ -856,7 +856,7 @@ multipart_parsing_benchmark() ->
body_end,
eof],
TestCallback = fun (Next) -> test_callback(Next, Expect) end,
- ServerFun = fun (Socket) ->
+ ServerFun = fun (Socket, _Opts) ->
ok = mochiweb_socket:send(Socket, BinContent),
exit(normal)
end,
http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/ae0b9aad/src/mochiweb_request.erl
----------------------------------------------------------------------
diff --git a/src/mochiweb_request.erl b/src/mochiweb_request.erl
index f8ba7a3..9622926 100644
--- a/src/mochiweb_request.erl
+++ b/src/mochiweb_request.erl
@@ -11,7 +11,7 @@
-define(QUIP, "Any of you quaids got a smint?").
--export([new/5]).
+-export([new/5, new/6]).
-export([get_header_value/2, get_primary_header_value/2, get_combined_header_value/2, get/2, dump/1]).
-export([send/2, recv/2, recv/3, recv_body/1, recv_body/2, stream_body/4]).
-export([start_response/2, start_response_length/2, start_raw_response/2]).
@@ -49,17 +49,22 @@
%% @spec new(Socket, Method, RawPath, Version, headers()) -> request()
%% @doc Create a new request instance.
new(Socket, Method, RawPath, Version, Headers) ->
- {?MODULE, [Socket, Method, RawPath, Version, Headers]}.
+ new(Socket, [], Method, RawPath, Version, Headers).
+
+%% @spec new(Socket, Opts, Method, RawPath, Version, headers()) -> request()
+%% @doc Create a new request instance.
+new(Socket, Opts, Method, RawPath, Version, Headers) ->
+ {?MODULE, [Socket, Opts, Method, RawPath, Version, Headers]}.
%% @spec get_header_value(K, request()) -> undefined | Value
%% @doc Get the value of a given request header.
-get_header_value(K, {?MODULE, [_Socket, _Method, _RawPath, _Version, Headers]}) ->
+get_header_value(K, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, Headers]}) ->
mochiweb_headers:get_value(K, Headers).
-get_primary_header_value(K, {?MODULE, [_Socket, _Method, _RawPath, _Version, Headers]}) ->
+get_primary_header_value(K, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, Headers]}) ->
mochiweb_headers:get_primary_value(K, Headers).
-get_combined_header_value(K, {?MODULE, [_Socket, _Method, _RawPath, _Version, Headers]}) ->
+get_combined_header_value(K, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, Headers]}) ->
mochiweb_headers:get_combined_value(K, Headers).
%% @type field() = socket | scheme | method | raw_path | version | headers | peer | path | body_length | range
@@ -70,24 +75,24 @@ get_combined_header_value(K, {?MODULE, [_Socket, _Method, _RawPath, _Version, He
%% an ssl socket will be returned as <code>{ssl, SslSocket}</code>.
%% You can use <code>SslSocket</code> with the <code>ssl</code>
%% application, eg: <code>ssl:peercert(SslSocket)</code>.
-get(socket, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}) ->
+get(socket, {?MODULE, [Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) ->
Socket;
-get(scheme, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}) ->
+get(scheme, {?MODULE, [Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) ->
case mochiweb_socket:type(Socket) of
plain ->
http;
ssl ->
https
end;
-get(method, {?MODULE, [_Socket, Method, _RawPath, _Version, _Headers]}) ->
+get(method, {?MODULE, [_Socket, _Opts, Method, _RawPath, _Version, _Headers]}) ->
Method;
-get(raw_path, {?MODULE, [_Socket, _Method, RawPath, _Version, _Headers]}) ->
+get(raw_path, {?MODULE, [_Socket, _Opts, _Method, RawPath, _Version, _Headers]}) ->
RawPath;
-get(version, {?MODULE, [_Socket, _Method, _RawPath, Version, _Headers]}) ->
+get(version, {?MODULE, [_Socket, _Opts, _Method, _RawPath, Version, _Headers]}) ->
Version;
-get(headers, {?MODULE, [_Socket, _Method, _RawPath, _Version, Headers]}) ->
+get(headers, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, Headers]}) ->
Headers;
-get(peer, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+get(peer, {?MODULE, [Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
case mochiweb_socket:peername(Socket) of
{ok, {Addr={10, _, _, _}, _Port}} ->
case get_header_value("x-forwarded-for", THIS) of
@@ -108,7 +113,7 @@ get(peer, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
{error, enotconn} ->
exit(normal)
end;
-get(path, {?MODULE, [_Socket, _Method, RawPath, _Version, _Headers]}) ->
+get(path, {?MODULE, [_Socket, _Opts, _Method, RawPath, _Version, _Headers]}) ->
case erlang:get(?SAVE_PATH) of
undefined ->
{Path0, _, _} = mochiweb_util:urlsplit_path(RawPath),
@@ -118,7 +123,7 @@ get(path, {?MODULE, [_Socket, _Method, RawPath, _Version, _Headers]}) ->
Cached ->
Cached
end;
-get(body_length, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+get(body_length, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
case erlang:get(?SAVE_BODY_LENGTH) of
undefined ->
BodyLength = body_length(THIS),
@@ -127,26 +132,29 @@ get(body_length, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THI
{cached, Cached} ->
Cached
end;
-get(range, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+get(range, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
case get_header_value(range, THIS) of
undefined ->
undefined;
RawRange ->
mochiweb_http:parse_range_request(RawRange)
- end.
+ end;
+get(opts, {?MODULE, [_Socket, Opts, _Method, _RawPath, _Version, _Headers]}) ->
+ Opts.
%% @spec dump(request()) -> {mochiweb_request, [{atom(), term()}]}
%% @doc Dump the internal representation to a "human readable" set of terms
%% for debugging/inspection purposes.
-dump({?MODULE, [_Socket, Method, RawPath, Version, Headers]}) ->
+dump({?MODULE, [_Socket, Opts, Method, RawPath, Version, Headers]}) ->
{?MODULE, [{method, Method},
{version, Version},
{raw_path, RawPath},
+ {opts, Opts},
{headers, mochiweb_headers:to_list(Headers)}]}.
%% @spec send(iodata(), request()) -> ok
%% @doc Send data over the socket.
-send(Data, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}) ->
+send(Data, {?MODULE, [Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) ->
case mochiweb_socket:send(Socket, Data) of
ok ->
ok;
@@ -157,13 +165,13 @@ send(Data, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}) ->
%% @spec recv(integer(), request()) -> binary()
%% @doc Receive Length bytes from the client as a binary, with the default
%% idle timeout.
-recv(Length, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+recv(Length, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
recv(Length, ?IDLE_TIMEOUT, THIS).
%% @spec recv(integer(), integer(), request()) -> binary()
%% @doc Receive Length bytes from the client as a binary, with the given
%% Timeout in msec.
-recv(Length, Timeout, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}) ->
+recv(Length, Timeout, {?MODULE, [Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) ->
case mochiweb_socket:recv(Socket, Length, Timeout) of
{ok, Data} ->
put(?SAVE_RECV, true),
@@ -174,7 +182,7 @@ recv(Length, Timeout, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}
%% @spec body_length(request()) -> undefined | chunked | unknown_transfer_encoding | integer()
%% @doc Infer body length from transfer-encoding and content-length headers.
-body_length({?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+body_length({?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
case get_header_value("transfer-encoding", THIS) of
undefined ->
case get_combined_header_value("content-length", THIS) of
@@ -193,13 +201,13 @@ body_length({?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
%% @spec recv_body(request()) -> binary()
%% @doc Receive the body of the HTTP request (defined by Content-Length).
%% Will only receive up to the default max-body length of 1MB.
-recv_body({?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+recv_body({?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
recv_body(?MAX_RECV_BODY, THIS).
%% @spec recv_body(integer(), request()) -> binary()
%% @doc Receive the body of the HTTP request (defined by Content-Length).
%% Will receive up to MaxBody bytes.
-recv_body(MaxBody, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+recv_body(MaxBody, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
case erlang:get(?SAVE_BODY) of
undefined ->
% we could use a sane constant for max chunk size
@@ -219,11 +227,11 @@ recv_body(MaxBody, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=T
Cached -> Cached
end.
-stream_body(MaxChunkSize, ChunkFun, FunState, {?MODULE,[_Socket,_Method,_RawPath,_Version,_Headers]}=THIS) ->
+stream_body(MaxChunkSize, ChunkFun, FunState, {?MODULE,[_Socket,_Opts,_Method,_RawPath,_Version,_Headers]}=THIS) ->
stream_body(MaxChunkSize, ChunkFun, FunState, undefined, THIS).
stream_body(MaxChunkSize, ChunkFun, FunState, MaxBodyLength,
- {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+ {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
Expect = case get_header_value("expect", THIS) of
undefined ->
undefined;
@@ -263,13 +271,13 @@ stream_body(MaxChunkSize, ChunkFun, FunState, MaxBodyLength,
%% @doc Start the HTTP response by sending the Code HTTP response and
%% ResponseHeaders. The server will set header defaults such as Server
%% and Date if not present in ResponseHeaders.
-start_response({Code, ResponseHeaders}, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+start_response({Code, ResponseHeaders}, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
start_raw_response({Code, ResponseHeaders}, THIS).
%% @spec start_raw_response({integer(), headers()}, request()) -> response()
%% @doc Start the HTTP response by sending the Code HTTP response and
%% ResponseHeaders.
-start_raw_response({Code, ResponseHeaders}, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+start_raw_response({Code, ResponseHeaders}, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
{Header, Response} = format_response_header({Code, ResponseHeaders}, THIS),
send(Header, THIS),
Response.
@@ -281,7 +289,7 @@ start_raw_response({Code, ResponseHeaders}, {?MODULE, [_Socket, _Method, _RawPat
%% will set header defaults such as Server
%% and Date if not present in ResponseHeaders.
start_response_length({Code, ResponseHeaders, Length},
- {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+ {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
HResponse = mochiweb_headers:make(ResponseHeaders),
HResponse1 = mochiweb_headers:enter("Content-Length", Length, HResponse),
start_response({Code, HResponse1}, THIS).
@@ -291,7 +299,7 @@ start_response_length({Code, ResponseHeaders, Length},
%% ResponseHeaders including an optional Content-Length of Length. The server
%% will set header defaults such as Server
%% and Date if not present in ResponseHeaders.
-format_response_header({Code, ResponseHeaders}, {?MODULE, [_Socket, _Method, _RawPath, Version, _Headers]}=THIS) ->
+format_response_header({Code, ResponseHeaders}, {?MODULE, [_Socket, _Opts, _Method, _RawPath, Version, _Headers]}=THIS) ->
HResponse = mochiweb_headers:make(ResponseHeaders),
HResponse1 = mochiweb_headers:default_from_list(server_headers(), HResponse),
F = fun ({K, V}, Acc) ->
@@ -301,7 +309,7 @@ format_response_header({Code, ResponseHeaders}, {?MODULE, [_Socket, _Method, _Ra
Response = mochiweb:new_response({THIS, Code, HResponse1}),
{[make_version(Version), make_code(Code), <<"\r\n">> | End], Response};
format_response_header({Code, ResponseHeaders, Length},
- {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+ {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
HResponse = mochiweb_headers:make(ResponseHeaders),
HResponse1 = mochiweb_headers:enter("Content-Length", Length, HResponse),
format_response_header({Code, HResponse1}, THIS).
@@ -312,7 +320,7 @@ format_response_header({Code, ResponseHeaders, Length},
%% will be set by the Body length, and the server will insert header
%% defaults.
respond({Code, ResponseHeaders, {file, IoDevice}},
- {?MODULE, [_Socket, Method, _RawPath, _Version, _Headers]}=THIS) ->
+ {?MODULE, [_Socket, _Opts, Method, _RawPath, _Version, _Headers]}=THIS) ->
Length = mochiweb_io:iodevice_size(IoDevice),
Response = start_response_length({Code, ResponseHeaders, Length}, THIS),
case Method of
@@ -324,7 +332,7 @@ respond({Code, ResponseHeaders, {file, IoDevice}},
IoDevice)
end,
Response;
-respond({Code, ResponseHeaders, chunked}, {?MODULE, [_Socket, Method, _RawPath, Version, _Headers]}=THIS) ->
+respond({Code, ResponseHeaders, chunked}, {?MODULE, [_Socket, _Opts, Method, _RawPath, Version, _Headers]}=THIS) ->
HResponse = mochiweb_headers:make(ResponseHeaders),
HResponse1 = case Method of
'HEAD' ->
@@ -346,7 +354,7 @@ respond({Code, ResponseHeaders, chunked}, {?MODULE, [_Socket, Method, _RawPath,
HResponse
end,
start_response({Code, HResponse1}, THIS);
-respond({Code, ResponseHeaders, Body}, {?MODULE, [_Socket, Method, _RawPath, _Version, _Headers]}=THIS) ->
+respond({Code, ResponseHeaders, Body}, {?MODULE, [_Socket, _Opts, Method, _RawPath, _Version, _Headers]}=THIS) ->
{Header, Response} = format_response_header({Code, ResponseHeaders, iolist_size(Body)}, THIS),
case Method of
'HEAD' -> send(Header, THIS);
@@ -356,22 +364,22 @@ respond({Code, ResponseHeaders, Body}, {?MODULE, [_Socket, Method, _RawPath, _Ve
%% @spec not_found(request()) -> response()
%% @doc Alias for <code>not_found([])</code>.
-not_found({?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+not_found({?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
not_found([], THIS).
%% @spec not_found(ExtraHeaders, request()) -> response()
%% @doc Alias for <code>respond({404, [{"Content-Type", "text/plain"}
%% | ExtraHeaders], <<"Not found.">>})</code>.
-not_found(ExtraHeaders, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+not_found(ExtraHeaders, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
respond({404, [{"Content-Type", "text/plain"} | ExtraHeaders],
<<"Not found.">>}, THIS).
%% @spec ok({value(), iodata()} | {value(), ioheaders(), iodata() | {file, IoDevice}}, request()) ->
%% response()
%% @doc respond({200, [{"Content-Type", ContentType} | Headers], Body}).
-ok({ContentType, Body}, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+ok({ContentType, Body}, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
ok({ContentType, [], Body}, THIS);
-ok({ContentType, ResponseHeaders, Body}, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+ok({ContentType, ResponseHeaders, Body}, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
HResponse = mochiweb_headers:make(ResponseHeaders),
case THIS:get(range) of
X when (X =:= undefined orelse X =:= fail) orelse Body =:= chunked ->
@@ -404,7 +412,7 @@ ok({ContentType, ResponseHeaders, Body}, {?MODULE, [_Socket, _Method, _RawPath,
%% @spec should_close(request()) -> bool()
%% @doc Return true if the connection must be closed. If false, using
%% Keep-Alive should be safe.
-should_close({?MODULE, [_Socket, _Method, _RawPath, Version, _Headers]}=THIS) ->
+should_close({?MODULE, [_Socket, _Opts, _Method, _RawPath, Version, _Headers]}=THIS) ->
ForceClose = erlang:get(?SAVE_FORCE_CLOSE) =/= undefined,
DidNotRecv = erlang:get(?SAVE_RECV) =:= undefined,
ForceClose orelse Version < {1, 0}
@@ -430,7 +438,7 @@ is_close(_) ->
%% @spec cleanup(request()) -> ok
%% @doc Clean up any junk in the process dictionary, required before continuing
%% a Keep-Alive request.
-cleanup({?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}) ->
+cleanup({?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) ->
L = [?SAVE_QS, ?SAVE_PATH, ?SAVE_RECV, ?SAVE_BODY, ?SAVE_BODY_LENGTH,
?SAVE_POST, ?SAVE_COOKIE, ?SAVE_FORCE_CLOSE],
lists:foreach(fun(K) ->
@@ -440,7 +448,7 @@ cleanup({?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}) ->
%% @spec parse_qs(request()) -> [{Key::string(), Value::string()}]
%% @doc Parse the query string of the URL.
-parse_qs({?MODULE, [_Socket, _Method, RawPath, _Version, _Headers]}) ->
+parse_qs({?MODULE, [_Socket, _Opts, _Method, RawPath, _Version, _Headers]}) ->
case erlang:get(?SAVE_QS) of
undefined ->
{_, QueryString, _} = mochiweb_util:urlsplit_path(RawPath),
@@ -453,12 +461,12 @@ parse_qs({?MODULE, [_Socket, _Method, RawPath, _Version, _Headers]}) ->
%% @spec get_cookie_value(Key::string, request()) -> string() | undefined
%% @doc Get the value of the given cookie.
-get_cookie_value(Key, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+get_cookie_value(Key, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
proplists:get_value(Key, parse_cookie(THIS)).
%% @spec parse_cookie(request()) -> [{Key::string(), Value::string()}]
%% @doc Parse the cookie header.
-parse_cookie({?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+parse_cookie({?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
case erlang:get(?SAVE_COOKIE) of
undefined ->
Cookies = case get_header_value("cookie", THIS) of
@@ -476,7 +484,7 @@ parse_cookie({?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) -
%% @spec parse_post(request()) -> [{Key::string(), Value::string()}]
%% @doc Parse an application/x-www-form-urlencoded form POST. This
%% has the side-effect of calling recv_body().
-parse_post({?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+parse_post({?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
case erlang:get(?SAVE_POST) of
undefined ->
Parsed = case recv_body(THIS) of
@@ -500,7 +508,7 @@ parse_post({?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
%% @doc The function is called for each chunk.
%% Used internally by read_chunked_body.
stream_chunked_body(MaxChunkSize, Fun, FunState,
- {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+ {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
case read_chunk_length(THIS) of
0 ->
Fun({0, read_chunk(0, THIS)}, FunState);
@@ -512,13 +520,14 @@ stream_chunked_body(MaxChunkSize, Fun, FunState,
stream_chunked_body(MaxChunkSize, Fun, NewState, THIS)
end.
-stream_unchunked_body(0, Fun, FunState, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}) ->
+stream_unchunked_body(0, Fun, FunState, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) ->
Fun({0, <<>>}, FunState);
stream_unchunked_body(Length, Fun, FunState,
- {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) when Length > 0 ->
- PktSize = case Length > ?RECBUF_SIZE of
+ {?MODULE, [_Socket, Opts, _Method, _RawPath, _Version, _Headers]}=THIS) when Length > 0 ->
+ RecBuf = mochilists:get_value(recbuf, Opts, ?RECBUF_SIZE),
+ PktSize = case Length > RecBuf of
true ->
- ?RECBUF_SIZE;
+ RecBuf;
false ->
Length
end,
@@ -528,7 +537,7 @@ stream_unchunked_body(Length, Fun, FunState,
%% @spec read_chunk_length(request()) -> integer()
%% @doc Read the length of the next HTTP chunk.
-read_chunk_length({?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}) ->
+read_chunk_length({?MODULE, [Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) ->
ok = mochiweb_socket:setopts(Socket, [{packet, line}]),
case mochiweb_socket:recv(Socket, 0, ?IDLE_TIMEOUT) of
{ok, Header} ->
@@ -545,7 +554,7 @@ read_chunk_length({?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}) ->
%% @spec read_chunk(integer(), request()) -> Chunk::binary() | [Footer::binary()]
%% @doc Read in a HTTP chunk of the given length. If Length is 0, then read the
%% HTTP footers (as a list of binaries, since they're nominal).
-read_chunk(0, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}) ->
+read_chunk(0, {?MODULE, [Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) ->
ok = mochiweb_socket:setopts(Socket, [{packet, line}]),
F = fun (F1, Acc) ->
case mochiweb_socket:recv(Socket, 0, ?IDLE_TIMEOUT) of
@@ -561,7 +570,7 @@ read_chunk(0, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}) ->
ok = mochiweb_socket:setopts(Socket, [{packet, raw}]),
put(?SAVE_RECV, true),
Footers;
-read_chunk(Length, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}) ->
+read_chunk(Length, {?MODULE, [Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) ->
case mochiweb_socket:recv(Socket, 2 + Length, ?IDLE_TIMEOUT) of
{ok, <<Chunk:Length/binary, "\r\n">>} ->
Chunk;
@@ -570,23 +579,23 @@ read_chunk(Length, {?MODULE, [Socket, _Method, _RawPath, _Version, _Headers]}) -
end.
read_sub_chunks(Length, MaxChunkSize, Fun, FunState,
- {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) when Length > MaxChunkSize ->
+ {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) when Length > MaxChunkSize ->
Bin = recv(MaxChunkSize, THIS),
NewState = Fun({size(Bin), Bin}, FunState),
read_sub_chunks(Length - MaxChunkSize, MaxChunkSize, Fun, NewState, THIS);
read_sub_chunks(Length, _MaxChunkSize, Fun, FunState,
- {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+ {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
Fun({Length, read_chunk(Length, THIS)}, FunState).
%% @spec serve_file(Path, DocRoot, request()) -> Response
%% @doc Serve a file relative to DocRoot.
-serve_file(Path, DocRoot, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+serve_file(Path, DocRoot, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
serve_file(Path, DocRoot, [], THIS).
%% @spec serve_file(Path, DocRoot, ExtraHeaders, request()) -> Response
%% @doc Serve a file relative to DocRoot.
-serve_file(Path, DocRoot, ExtraHeaders, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+serve_file(Path, DocRoot, ExtraHeaders, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
case mochiweb_util:safe_relative_path(Path) of
undefined ->
not_found(ExtraHeaders, THIS);
@@ -606,11 +615,11 @@ serve_file(Path, DocRoot, ExtraHeaders, {?MODULE, [_Socket, _Method, _RawPath, _
directory_index(FullPath) ->
filename:join([FullPath, "index.html"]).
-maybe_redirect([], FullPath, ExtraHeaders, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+maybe_redirect([], FullPath, ExtraHeaders, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
maybe_serve_file(directory_index(FullPath), ExtraHeaders, THIS);
maybe_redirect(RelPath, FullPath, ExtraHeaders,
- {?MODULE, [_Socket, _Method, _RawPath, _Version, Headers]}=THIS) ->
+ {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, Headers]}=THIS) ->
case string:right(RelPath, 1) of
"/" ->
maybe_serve_file(directory_index(FullPath), ExtraHeaders, THIS);
@@ -631,7 +640,7 @@ maybe_redirect(RelPath, FullPath, ExtraHeaders,
respond({301, MoreHeaders, Body}, THIS)
end.
-maybe_serve_file(File, ExtraHeaders, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+maybe_serve_file(File, ExtraHeaders, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
case file:read_file_info(File) of
{ok, FileInfo} ->
LastModified = httpd_util:rfc1123_date(FileInfo#file_info.mtime),
@@ -730,7 +739,7 @@ range_parts(Body0, Ranges) ->
%% accepted_encodings(["gzip", "deflate", "identity"]) ->
%% ["deflate", "gzip", "identity"]
%%
-accepted_encodings(SupportedEncodings, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+accepted_encodings(SupportedEncodings, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
AcceptEncodingHeader = case get_header_value("Accept-Encoding", THIS) of
undefined ->
"";
@@ -768,7 +777,7 @@ accepted_encodings(SupportedEncodings, {?MODULE, [_Socket, _Method, _RawPath, _V
%% 5) For an "Accept" header with value "text/*; q=0.0, */*":
%% accepts_content_type("text/plain") -> false
%%
-accepts_content_type(ContentType1, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+accepts_content_type(ContentType1, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
ContentType = re:replace(ContentType1, "\\s", "", [global, {return, list}]),
AcceptHeader = accept_header(THIS),
case mochiweb_util:parse_qvalues(AcceptHeader) of
@@ -817,7 +826,7 @@ accepts_content_type(ContentType1, {?MODULE, [_Socket, _Method, _RawPath, _Versi
%% accepts_content_types(["application/json", "text/html"]) ->
%% ["text/html", "application/json"]
%%
-accepted_content_types(Types1, {?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+accepted_content_types(Types1, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
Types = lists:map(
fun(T) -> re:replace(T, "\\s", "", [global, {return, list}]) end,
Types1),
@@ -857,7 +866,7 @@ accepted_content_types(Types1, {?MODULE, [_Socket, _Method, _RawPath, _Version,
[Type || {_Q, Type} <- lists:sort(SortFun, TypesQ)]
end.
-accept_header({?MODULE, [_Socket, _Method, _RawPath, _Version, _Headers]}=THIS) ->
+accept_header({?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) ->
case get_header_value("Accept", THIS) of
undefined ->
"*/*";
http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/ae0b9aad/src/mochiweb_socket.erl
----------------------------------------------------------------------
diff --git a/src/mochiweb_socket.erl b/src/mochiweb_socket.erl
index 8cd074f..f4b8bfb 100644
--- a/src/mochiweb_socket.erl
+++ b/src/mochiweb_socket.erl
@@ -5,7 +5,7 @@
-module(mochiweb_socket).
-export([listen/4, accept/1, recv/3, send/2, close/1, port/1, peername/1,
- setopts/2, type/1]).
+ setopts/2, getopts/2, type/1]).
-define(ACCEPT_TIMEOUT, 2000).
-define(SSL_TIMEOUT, 10000).
@@ -122,6 +122,11 @@ setopts({ssl, Socket}, Opts) ->
setopts(Socket, Opts) ->
inet:setopts(Socket, Opts).
+getopts({ssl, Socket}, Opts) ->
+ ssl:getopts(Socket, Opts);
+getopts(Socket, Opts) ->
+ inet:getopts(Socket, Opts).
+
type({ssl, _}) ->
ssl;
type(_) ->
http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/ae0b9aad/src/mochiweb_socket_server.erl
----------------------------------------------------------------------
diff --git a/src/mochiweb_socket_server.erl b/src/mochiweb_socket_server.erl
index 3b7b3da..7f8587e 100644
--- a/src/mochiweb_socket_server.erl
+++ b/src/mochiweb_socket_server.erl
@@ -22,6 +22,7 @@
ip=any,
listen=null,
nodelay=false,
+ recbuf=?RECBUF_SIZE,
backlog=128,
active_sockets=0,
acceptor_pool_size=16,
@@ -116,6 +117,8 @@ parse_options([{backlog, Backlog} | Rest], State) ->
parse_options(Rest, State#mochiweb_socket_server{backlog=Backlog});
parse_options([{nodelay, NoDelay} | Rest], State) ->
parse_options(Rest, State#mochiweb_socket_server{nodelay=NoDelay});
+parse_options([{recbuf, RecBuf} | Rest], State) when is_integer(RecBuf) ->
+ parse_options(Rest, State#mochiweb_socket_server{recbuf=RecBuf});
parse_options([{acceptor_pool_size, Max} | Rest], State) ->
MaxInt = ensure_int(Max),
parse_options(Rest,
@@ -162,13 +165,15 @@ ipv6_supported() ->
false
end.
-init(State=#mochiweb_socket_server{ip=Ip, port=Port, backlog=Backlog, nodelay=NoDelay}) ->
+init(State=#mochiweb_socket_server{ip=Ip, port=Port, backlog=Backlog,
+ nodelay=NoDelay, recbuf=RecBuf}) ->
process_flag(trap_exit, true),
+
BaseOpts = [binary,
{reuseaddr, true},
{packet, 0},
{backlog, Backlog},
- {recbuf, ?RECBUF_SIZE},
+ {recbuf, RecBuf},
{exit_on_close, false},
{active, false},
{nodelay, NoDelay}],
@@ -188,22 +193,37 @@ init(State=#mochiweb_socket_server{ip=Ip, port=Port, backlog=Backlog, nodelay=No
new_acceptor_pool(Listen,
State=#mochiweb_socket_server{acceptor_pool=Pool,
acceptor_pool_size=Size,
+ recbuf=RecBuf,
loop=Loop}) ->
+ LoopOpts = [{recbuf, RecBuf}],
F = fun (_, S) ->
- Pid = mochiweb_acceptor:start_link(self(), Listen, Loop),
+ Pid = mochiweb_acceptor:start_link(
+ self(), Listen, Loop, LoopOpts
+ ),
sets:add_element(Pid, S)
end,
Pool1 = lists:foldl(F, Pool, lists:seq(1, Size)),
State#mochiweb_socket_server{acceptor_pool=Pool1}.
-listen(Port, Opts, State=#mochiweb_socket_server{ssl=Ssl, ssl_opts=SslOpts}) ->
+listen(Port, Opts, State=#mochiweb_socket_server{ssl=Ssl, ssl_opts=SslOpts,
+ recbuf=RecBuf}) ->
case mochiweb_socket:listen(Ssl, Port, Opts, SslOpts) of
{ok, Listen} ->
+ %% XXX: `recbuf' value which is passed to `gen_tcp'
+ %% and value reported by `inet:getopts(P, [recbuf])' may
+ %% differ. They depends on underlying OS. From linux mans:
+ %%
+ %% The kernel doubles this value (to allow space for
+ %% bookkeeping overhead) when it is set using setsockopt(2),
+ %% and this doubled value is returned by getsockopt(2).
+ %%
+ %% See: man 7 socket | grep SO_RCVBUF
{ok, ListenPort} = mochiweb_socket:port(Listen),
{ok, new_acceptor_pool(
Listen,
State#mochiweb_socket_server{listen=Listen,
- port=ListenPort})};
+ port=ListenPort,
+ recbuf=RecBuf})};
{error, Reason} ->
{stop, Reason}
end.
@@ -283,13 +303,17 @@ recycle_acceptor(Pid, State=#mochiweb_socket_server{
listen=Listen,
loop=Loop,
max=Max,
+ recbuf=RecBuf,
active_sockets=ActiveSockets}) ->
+ LoopOpts = [{recbuf, RecBuf}],
case sets:is_element(Pid, Pool) of
true ->
Pool1 = sets:del_element(Pid, Pool),
case ActiveSockets + sets:size(Pool1) < Max of
true ->
- Acceptor = mochiweb_acceptor:start_link(self(), Listen, Loop),
+ Acceptor = mochiweb_acceptor:start_link(
+ self(), Listen, Loop, LoopOpts
+ ),
Pool2 = sets:add_element(Acceptor, Pool1),
State#mochiweb_socket_server{acceptor_pool=Pool2};
false ->
@@ -298,7 +322,9 @@ recycle_acceptor(Pid, State=#mochiweb_socket_server{
false ->
case sets:size(Pool) < PoolSize of
true ->
- Acceptor = mochiweb_acceptor:start_link(self(), Listen, Loop),
+ Acceptor = mochiweb_acceptor:start_link(
+ self(), Listen, Loop, LoopOpts
+ ),
Pool1 = sets:add_element(Acceptor, Pool),
State#mochiweb_socket_server{active_sockets=ActiveSockets,
acceptor_pool=Pool1};
http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/ae0b9aad/test/mochiweb_socket_server_tests.erl
----------------------------------------------------------------------
diff --git a/test/mochiweb_socket_server_tests.erl b/test/mochiweb_socket_server_tests.erl
index 0dad09d..c64f5b7 100644
--- a/test/mochiweb_socket_server_tests.erl
+++ b/test/mochiweb_socket_server_tests.erl
@@ -63,7 +63,7 @@ test_basic_accept(Max, PoolSize, NumClients, ReportTo) ->
ServerOpts = [{max, Max}, {acceptor_pool_size, PoolSize}],
ServerLoop =
- fun (Socket) ->
+ fun (Socket, _Opts) ->
Tester ! {server_accepted, self()},
mochiweb_socket:setopts(Socket, [{packet, 1}]),
echo_loop(Socket)