You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by dc...@apache.org on 2014/03/07 01:18:33 UTC
[50/50] [abbrv] couchdb commit: updated
refs/heads/2041-update-ibrowse to 948e7d9
ibrowse: update to 4.0.3
- for COUCHDB-2041
- should be re-pushed with amended VSN when upstream tags a release
- ibrowse sha#108c131d at 20140306
Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/948e7d9a
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/948e7d9a
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/948e7d9a
Branch: refs/heads/2041-update-ibrowse
Commit: 948e7d9a66741b8178b154f3445620ee59ad28c1
Parents: 4e60f0b
Author: Dave Cottlehuber <dc...@apache.org>
Authored: Wed Jan 29 11:05:23 2014 +0100
Committer: Dave Cottlehuber <dc...@apache.org>
Committed: Fri Mar 7 00:16:38 2014 +0000
----------------------------------------------------------------------
src/ibrowse/ibrowse.app.in | 2 +-
src/ibrowse/ibrowse.erl | 51 +++++----
src/ibrowse/ibrowse_http_client.erl | 190 ++++++++++++++++---------------
src/ibrowse/ibrowse_lb.erl | 28 +++--
src/ibrowse/ibrowse_lib.erl | 7 +-
src/ibrowse/ibrowse_socks5.erl | 143 ++++++++---------------
6 files changed, 198 insertions(+), 223 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb/blob/948e7d9a/src/ibrowse/ibrowse.app.in
----------------------------------------------------------------------
diff --git a/src/ibrowse/ibrowse.app.in b/src/ibrowse/ibrowse.app.in
index 1d88084..813192b 100644
--- a/src/ibrowse/ibrowse.app.in
+++ b/src/ibrowse/ibrowse.app.in
@@ -1,6 +1,6 @@
{application, ibrowse,
[{description, "Erlang HTTP client application"},
- {vsn, "4.0.1"},
+ {vsn, "4.0.3pre"},
{registered, [ibrowse_sup, ibrowse]},
{applications, [kernel,stdlib]},
{env, []},
http://git-wip-us.apache.org/repos/asf/couchdb/blob/948e7d9a/src/ibrowse/ibrowse.erl
----------------------------------------------------------------------
diff --git a/src/ibrowse/ibrowse.erl b/src/ibrowse/ibrowse.erl
index 80a4282..42030af 100644
--- a/src/ibrowse/ibrowse.erl
+++ b/src/ibrowse/ibrowse.erl
@@ -175,9 +175,11 @@ send_req(Url, Headers, Method) ->
send_req(Url, Headers, Method, Body) ->
send_req(Url, Headers, Method, Body, []).
-%% @doc Same as send_req/4.
-%% For a description of SSL Options, look in the <a href="http://www.erlang.org/doc/apps/ssl/index.html">ssl</a> manpage. If the
-%% HTTP Version to use is not specified, the default is 1.1.
+%% @doc Same as send_req/4.
+
+%% For a description of SSL Options, look in the <a href="http://www.erlang.org/doc/apps/ssl/index.html">ssl</a> manpage.
+%% For a description of Process Options, look in the <a href="http://www.erlang.org/doc/man/gen_server.html">gen_server</a> manpage.
+%% If the HTTP Version to use is not specified, the default is 1.1.
%% <br/>
%% <ul>
%% <li>The <code>host_header</code> option is useful in the case where ibrowse is
@@ -286,7 +288,8 @@ send_req(Url, Headers, Method, Body) ->
%% {headers_as_is, boolean()} |
%% {give_raw_headers, boolean()} |
%% {preserve_chunked_encoding,boolean()} |
-%% {workaround, head_response_with_body}
+%% {workaround, head_response_with_body} |
+%% {worker_process_options, list()}
%%
%% stream_to() = process() | {process(), once}
%% process() = pid() | atom()
@@ -340,10 +343,12 @@ try_routing_request(Lb_pid, Parsed_url,
Max_pipeline_size,
{SSLOptions, IsSSL},
Headers, Method, Body, Options_1, Timeout, Try_count) when Try_count < 3 ->
+ ProcessOptions = get_value(worker_process_options, Options_1, []),
case ibrowse_lb:spawn_connection(Lb_pid, Parsed_url,
Max_sessions,
Max_pipeline_size,
- {SSLOptions, IsSSL}) of
+ {SSLOptions, IsSSL},
+ ProcessOptions) of
{ok, Conn_Pid} ->
case do_send_req(Conn_Pid, Parsed_url, Headers,
Method, Body, Options_1, Timeout) of
@@ -438,6 +443,8 @@ do_send_req(Conn_Pid, Parsed_url, Headers, Method, Body, Options, Timeout) ->
{error, sel_conn_closed};
{'EXIT', {normal, _}} ->
{error, req_timedout};
+ {'EXIT', {connection_closed, _}} ->
+ {error, sel_conn_closed};
{error, connection_closed} ->
{error, sel_conn_closed};
{'EXIT', Reason} ->
@@ -470,28 +477,32 @@ ensure_bin({Fun, _} = Body) when is_function(Fun) -> Body.
%% request is sent via any of the send_req_direct/4,5,6,7 functions.<br/>
%% <b>Note:</b> It is the responsibility of the calling process to control
%% pipeline size on such connections.
-%%
-%% @spec spawn_worker_process(Url::string()) -> {ok, pid()}
-spawn_worker_process(Url) ->
- ibrowse_http_client:start(Url).
-%% @doc Same as spawn_worker_process/1 but takes as input a Host and Port
-%% instead of a URL.
+%% @spec spawn_worker_process(Url::string() | {Host::string(), Port::integer()}) -> {ok, pid()}
+spawn_worker_process(Args) ->
+ spawn_worker_process(Args, []).
+
+%% @doc Same as spawn_worker_process/1 except with Erlang process options.
%% @spec spawn_worker_process(Host::string(), Port::integer()) -> {ok, pid()}
-spawn_worker_process(Host, Port) ->
- ibrowse_http_client:start({Host, Port}).
+spawn_worker_process(Host, Port) when is_list(Host), is_integer(Port) ->
+ %% Convert old API calls to new API format.
+ spawn_worker_process({Host, Port}, []);
+spawn_worker_process(Args, Options) ->
+ ibrowse_http_client:start(Args, Options).
%% @doc Same as spawn_worker_process/1 except the the calling process
%% is linked to the worker process which is spawned.
-%% @spec spawn_link_worker_process(Url::string()) -> {ok, pid()}
-spawn_link_worker_process(Url) ->
- ibrowse_http_client:start_link(Url).
+%% @spec spawn_link_worker_process(Url::string() | {Host::string(), Port::integer()}) -> {ok, pid()}
+spawn_link_worker_process(Args) ->
+ spawn_link_worker_process(Args, []).
-%% @doc Same as spawn_worker_process/2 except the the calling process
-%% is linked to the worker process which is spawned.
+%% @doc Same as spawn_link_worker_process/1 except with Erlang process options.
%% @spec spawn_link_worker_process(Host::string(), Port::integer()) -> {ok, pid()}
-spawn_link_worker_process(Host, Port) ->
- ibrowse_http_client:start_link({Host, Port}).
+spawn_link_worker_process(Host, Port) when is_list(Host), is_integer(Port) ->
+ %% Convert old API calls to new API format.
+ spawn_link_worker_process({Host, Port}, []);
+spawn_link_worker_process(Args, Options) ->
+ ibrowse_http_client:start_link(Args, Options).
%% @doc Terminate a worker process spawned using
%% spawn_worker_process/2 or spawn_link_worker_process/2. Requests in
http://git-wip-us.apache.org/repos/asf/couchdb/blob/948e7d9a/src/ibrowse/ibrowse_http_client.erl
----------------------------------------------------------------------
diff --git a/src/ibrowse/ibrowse_http_client.erl b/src/ibrowse/ibrowse_http_client.erl
index a1cf6eb..0410c08 100644
--- a/src/ibrowse/ibrowse_http_client.erl
+++ b/src/ibrowse/ibrowse_http_client.erl
@@ -15,7 +15,9 @@
%% External exports
-export([
start_link/1,
+ start_link/2,
start/1,
+ start/2,
stop/1,
send_req/7
]).
@@ -39,8 +41,7 @@
-record(state, {host, port, connect_timeout,
inactivity_timer_ref,
- use_http_proxy = false, http_proxy_auth_digest,
- socks5_host, socks5_port, socks5_user, socks5_password,
+ use_proxy = false, proxy_auth_digest,
ssl_options = [], is_ssl = false, socket,
proxy_tunnel_setup = false,
tunnel_setup_queue = [],
@@ -80,10 +81,16 @@
%% Description: Starts the server
%%--------------------------------------------------------------------
start(Args) ->
- gen_server:start(?MODULE, Args, []).
+ start(Args, []).
+
+start(Args, Options) ->
+ gen_server:start(?MODULE, Args, Options).
start_link(Args) ->
- gen_server:start_link(?MODULE, Args, []).
+ start_link(Args, []).
+
+start_link(Args, Options) ->
+ gen_server:start_link(?MODULE, Args, Options).
stop(Conn_pid) ->
case catch gen_server:call(Conn_pid, stop) of
@@ -187,7 +194,7 @@ handle_info({ssl, _Sock, Data}, State) ->
handle_info({stream_next, Req_id}, #state{socket = Socket,
cur_req = #request{req_id = Req_id}} = State) ->
- do_setopts(Socket, [{active, once}], State),
+ _ = do_setopts(Socket, [{active, once}], State),
{noreply, set_inac_timer(State)};
handle_info({stream_next, _Req_id}, State) ->
@@ -208,11 +215,11 @@ handle_info({stream_close, _Req_id}, State) ->
handle_info({tcp_closed, _Sock}, State) ->
do_trace("TCP connection closed by peer!~n", []),
handle_sock_closed(State),
- {stop, normal, State};
+ {stop, connection_closed, State};
handle_info({ssl_closed, _Sock}, State) ->
do_trace("SSL connection closed by peer!~n", []),
handle_sock_closed(State),
- {stop, normal, State};
+ {stop, connection_closed, State};
handle_info({tcp_error, _Sock, Reason}, State) ->
do_trace("Error on connection to ~1000.p:~1000.p -> ~1000.p~n",
@@ -226,12 +233,12 @@ handle_info({ssl_error, _Sock, Reason}, State) ->
{stop, normal, State};
handle_info({req_timedout, From}, State) ->
- case lists:keymember(From, #request.from, queue:to_list(State#state.reqs)) of
+ case lists:keysearch(From, #request.from, queue:to_list(State#state.reqs)) of
false ->
{noreply, State};
- true ->
+ {value, #request{stream_to = StreamTo, req_id = ReqId}} ->
+ catch StreamTo ! {ibrowse_async_response_timeout, ReqId},
shutting_down(State),
-%% do_error_reply(State, req_timedout),
{stop, normal, State}
end;
@@ -288,12 +295,12 @@ handle_sock_data(Data, #state{status = get_header}=State) ->
shutting_down(State),
{stop, normal, State};
#state{socket = Socket, status = Status, cur_req = CurReq} = State_1 ->
- case {Status, CurReq} of
- {get_header, #request{caller_controls_socket = true}} ->
- do_setopts(Socket, [{active, once}], State_1);
- _ ->
- active_once(State_1)
- end,
+ _ = case {Status, CurReq} of
+ {get_header, #request{caller_controls_socket = true}} ->
+ do_setopts(Socket, [{active, once}], State_1);
+ _ ->
+ active_once(State_1)
+ end,
{noreply, set_inac_timer(State_1)}
end;
@@ -312,7 +319,7 @@ handle_sock_data(Data, #state{status = get_body,
{error, {Reason, {stat_code, StatCode}, Headers}}),
{stop, normal, State};
State_1 ->
- active_once(State_1),
+ _ = active_once(State_1),
State_2 = set_inac_timer(State_1),
{noreply, State_2}
end;
@@ -325,14 +332,14 @@ handle_sock_data(Data, #state{status = get_body,
{stop, normal, State};
#state{cur_req = #request{caller_controls_socket = Ccs},
interim_reply_sent = Irs} = State_1 ->
- case Irs of
- true ->
- active_once(State_1);
- false when Ccs == true ->
- do_setopts(Socket, [{active, once}], State);
- false ->
- active_once(State_1)
- end,
+ _ = case Irs of
+ true ->
+ active_once(State_1);
+ false when Ccs == true ->
+ do_setopts(Socket, [{active, once}], State);
+ false ->
+ active_once(State_1)
+ end,
State_2 = State_1#state{interim_reply_sent = false},
case Ccs of
true ->
@@ -342,7 +349,7 @@ handle_sock_data(Data, #state{status = get_body,
{noreply, set_inac_timer(State_2)}
end;
State_1 ->
- active_once(State_1),
+ _ = active_once(State_1),
State_2 = set_inac_timer(State_1),
{noreply, State_2}
end
@@ -489,25 +496,19 @@ handle_sock_closed(#state{reply_buffer = Buf, reqs = Reqs, http_status_code = SC
State
end.
-do_connect(Host, Port, Options, #state{socks5_host = SocksHost}=State, Timeout)
- when SocksHost /= undefined ->
- ProxyOptions = [
- {user, State#state.socks5_user},
- {password, State#state.socks5_password},
- {host, SocksHost},
- {port, State#state.socks5_port},
- {is_ssl, State#state.is_ssl},
- {ssl_opts, State#state.ssl_options}],
- ibrowse_socks5:connect(Host, Port, ProxyOptions,
- get_sock_options(SocksHost, Options, []),
- Timeout);
-do_connect(Host, Port, Options, #state{is_ssl = true,
- use_http_proxy = false,
- ssl_options = SSLOptions},
+do_connect(Host, Port, Options, #state{is_ssl = true,
+ use_proxy = false,
+ ssl_options = SSLOptions},
Timeout) ->
ssl:connect(Host, Port, get_sock_options(Host, Options, SSLOptions), Timeout);
do_connect(Host, Port, Options, _State, Timeout) ->
- gen_tcp:connect(Host, Port, get_sock_options(Host, Options, []), Timeout).
+ Socks5Host = get_value(socks5_host, Options, undefined),
+ case Socks5Host of
+ undefined ->
+ gen_tcp:connect(Host, Port, get_sock_options(Host, Options, []), Timeout);
+ _ ->
+ catch ibrowse_socks5:connect(Host, Port, Options)
+ end.
get_sock_options(Host, Options, SSLOptions) ->
Caller_socket_options = get_value(socket_options, Options, []),
@@ -554,7 +555,7 @@ filter_sock_options(Opts) ->
do_send(Req, #state{socket = Sock,
is_ssl = true,
- use_http_proxy = true,
+ use_proxy = true,
proxy_tunnel_setup = Pts}) when Pts /= done -> gen_tcp:send(Sock, Req);
do_send(Req, #state{socket = Sock, is_ssl = true}) -> ssl:send(Sock, Req);
do_send(Req, #state{socket = Sock, is_ssl = false}) -> gen_tcp:send(Sock, Req).
@@ -578,16 +579,16 @@ do_send_body1(Source, Resp, State, TE) ->
{ok, Data} when Data == []; Data == <<>> ->
do_send_body({Source}, State, TE);
{ok, Data} ->
- do_send(maybe_chunked_encode(Data, TE), State),
+ _ = do_send(maybe_chunked_encode(Data, TE), State),
do_send_body({Source}, State, TE);
{ok, Data, New_source_state} when Data == []; Data == <<>> ->
do_send_body({Source, New_source_state}, State, TE);
{ok, Data, New_source_state} ->
- do_send(maybe_chunked_encode(Data, TE), State),
+ _ = do_send(maybe_chunked_encode(Data, TE), State),
do_send_body({Source, New_source_state}, State, TE);
eof when TE == true ->
- do_send(<<"0\r\n\r\n">>, State),
- ok;
+ _ = do_send(<<"0\r\n\r\n">>, State),
+ ok;
eof ->
ok;
Err ->
@@ -602,7 +603,7 @@ maybe_chunked_encode(Data, true) ->
do_close(#state{socket = undefined}) -> ok;
do_close(#state{socket = Sock,
is_ssl = true,
- use_http_proxy = true,
+ use_proxy = true,
proxy_tunnel_setup = Pts
}) when Pts /= done -> catch gen_tcp:close(Sock);
do_close(#state{socket = Sock, is_ssl = true}) -> catch ssl:close(Sock);
@@ -611,11 +612,11 @@ do_close(#state{socket = Sock, is_ssl = false}) -> catch gen_tcp:close(Sock).
active_once(#state{cur_req = #request{caller_controls_socket = true}}) ->
ok;
active_once(#state{socket = Socket} = State) ->
- do_setopts(Socket, [{active, once}], State).
+ _ = do_setopts(Socket, [{active, once}], State).
do_setopts(_Sock, [], _) -> ok;
do_setopts(Sock, Opts, #state{is_ssl = true,
- use_http_proxy = true,
+ use_proxy = true,
proxy_tunnel_setup = Pts}
) when Pts /= done -> inet:setopts(Sock, Opts);
do_setopts(Sock, Opts, #state{is_ssl = true}) -> ssl:setopts(Sock, Opts);
@@ -634,28 +635,17 @@ send_req_1(From,
port = Port} = Url,
Headers, Method, Body, Options, Timeout,
#state{socket = undefined} = State) ->
- ProxyHost = get_value(proxy_host, Options, false),
- ProxyProtocol = get_value(proxy_protocol, Options, http),
{Host_1, Port_1, State_1} =
- case {ProxyHost, ProxyProtocol} of
- {false, _} ->
+ case get_value(proxy_host, Options, false) of
+ false ->
{Host, Port, State};
- {_, http} ->
+ PHost ->
ProxyUser = get_value(proxy_user, Options, []),
ProxyPassword = get_value(proxy_password, Options, []),
Digest = http_auth_digest(ProxyUser, ProxyPassword),
- {ProxyHost, get_value(proxy_port, Options, 80),
- State#state{use_http_proxy = true,
- http_proxy_auth_digest = Digest}};
- {_, socks5} ->
- ProxyUser = list_to_binary(get_value(proxy_user, Options, [])),
- ProxyPassword = list_to_binary(get_value(proxy_password, Options, [])),
- ProxyPort = get_value(proxy_port, Options, 1080),
- {Host, Port,
- State#state{socks5_host = ProxyHost,
- socks5_port = ProxyPort,
- socks5_user = ProxyUser,
- socks5_password = ProxyPassword}}
+ {PHost, get_value(proxy_port, Options, 80),
+ State#state{use_proxy = true,
+ proxy_auth_digest = Digest}}
end,
State_2 = check_ssl_options(Options, State_1),
do_trace("Connecting...~n", []),
@@ -686,7 +676,7 @@ send_req_1(From,
Headers, Method, Body, Options, Timeout,
#state{
proxy_tunnel_setup = false,
- use_http_proxy = true,
+ use_proxy = true,
is_ssl = true} = State) ->
Ref = case Timeout of
infinity ->
@@ -713,7 +703,7 @@ send_req_1(From,
case do_send_body(Body_1, State_1, TE) of
ok ->
trace_request_body(Body_1),
- active_once(State_1),
+ _ = active_once(State_1),
State_1_1 = inc_pipeline_counter(State_1),
State_2 = State_1_1#state{status = get_header,
cur_req = NewReq,
@@ -796,7 +786,7 @@ send_req_1(From,
AbsPath, RelPath, Body, Options, State_1,
ReqId),
trace_request(Req),
- do_setopts(Socket, Caller_socket_options, State_1),
+ _ = do_setopts(Socket, Caller_socket_options, State_1),
TE = is_chunked_encoding_specified(Options),
case do_send(Req, State_1) of
ok ->
@@ -804,7 +794,7 @@ send_req_1(From,
ok ->
trace_request_body(Body_1),
State_2 = inc_pipeline_counter(State_1),
- active_once(State_2),
+ _ = active_once(State_2),
State_3 = case Status of
idle ->
State_2#state{status = get_header,
@@ -874,11 +864,11 @@ add_auth_headers(#url{username = User,
end,
add_proxy_auth_headers(State, Headers_1).
-add_proxy_auth_headers(#state{use_http_proxy = false}, Headers) ->
+add_proxy_auth_headers(#state{use_proxy = false}, Headers) ->
Headers;
-add_proxy_auth_headers(#state{http_proxy_auth_digest = []}, Headers) ->
+add_proxy_auth_headers(#state{proxy_auth_digest = []}, Headers) ->
Headers;
-add_proxy_auth_headers(#state{http_proxy_auth_digest = Auth_digest}, Headers) ->
+add_proxy_auth_headers(#state{proxy_auth_digest = Auth_digest}, Headers) ->
[{"Proxy-Authorization", ["Basic ", Auth_digest]} | Headers].
http_auth_digest([], []) ->
@@ -887,7 +877,7 @@ http_auth_digest(Username, Password) ->
ibrowse_lib:encode_base64(Username ++ [$: | Password]).
make_request(Method, Headers, AbsPath, RelPath, Body, Options,
- #state{use_http_proxy = UseHttpProxy, is_ssl = Is_ssl}, ReqId) ->
+ #state{use_proxy = UseProxy, is_ssl = Is_ssl}, ReqId) ->
HttpVsn = http_vsn_string(get_value(http_vsn, Options, {1,1})),
Fun1 = fun({X, Y}) when is_atom(X) ->
{to_lower(atom_to_list(X)), X, Y};
@@ -930,7 +920,7 @@ make_request(Method, Headers, AbsPath, RelPath, Body, Options,
Headers_2
end,
Headers_4 = cons_headers(Headers_3),
- Uri = case get_value(use_absolute_uri, Options, false) or UseHttpProxy of
+ Uri = case get_value(use_absolute_uri, Options, false) or UseProxy of
true ->
case Is_ssl of
true ->
@@ -1061,7 +1051,9 @@ parse_response(Data, #state{reply_buffer = Acc, reqs = Reqs,
http_status_code=StatCode}
end,
put(conn_close, ConnClose),
- TransferEncoding = to_lower(get_value("transfer-encoding", LCHeaders, "false")),
+ TransferEncodings = to_lower(get_value("transfer-encoding", LCHeaders, "false")),
+ IsChunked = lists:any(fun(Enc) -> string:strip(Enc) =:= "chunked" end,
+ string:tokens(TransferEncodings, ",")),
Head_response_with_body = lists:member({workaround, head_response_with_body}, Options),
case get_value("content-length", LCHeaders, undefined) of
_ when Method == connect,
@@ -1112,7 +1104,7 @@ parse_response(Data, #state{reply_buffer = Acc, reqs = Reqs,
State_2 = reset_state(State_1_1),
State_3 = set_cur_request(State_2#state{reqs = Reqs_1}),
parse_response(Data_1, State_3);
- _ when TransferEncoding =:= "chunked" ->
+ _ when IsChunked ->
do_trace("Chunked encoding detected...~n",[]),
send_async_headers(ReqId, StreamTo, Give_raw_headers, State_1),
case parse_11_response(Data_1, State_1#state{transfer_encoding=chunked,
@@ -1130,6 +1122,25 @@ parse_response(Data, #state{reply_buffer = Acc, reqs = Reqs,
ConnClose =:= "close" ->
send_async_headers(ReqId, StreamTo, Give_raw_headers, State_1),
State_1#state{reply_buffer = Data_1};
+ undefined when StatCode =:= "303" ->
+ %% Some servers send 303 requests without a body.
+ %% RFC2616 says that they SHOULD, but they dont.
+ case ibrowse:get_config_value(allow_303_with_no_body, false) of
+ false ->
+ fail_pipelined_requests(State_1,
+ {error, {content_length_undefined,
+ {stat_code, StatCode}, Headers}}),
+ {error, content_length_undefined};
+ true ->
+ {_, Reqs_1} = queue:out(Reqs),
+ send_async_headers(ReqId, StreamTo, Give_raw_headers, State_1),
+ State_1_1 = do_reply(State_1, From, StreamTo, ReqId, Resp_format,
+ {ok, StatCode, Headers_1, []}),
+ cancel_timer(T_ref, {eat_message, {req_timedout, From}}),
+ State_2 = reset_state(State_1_1),
+ State_3 = set_cur_request(State_2#state{reqs = Reqs_1}),
+ parse_response(Data_1, State_3)
+ end;
undefined ->
fail_pipelined_requests(State_1,
{error, {content_length_undefined,
@@ -1407,12 +1418,8 @@ set_cur_request(#state{reqs = Reqs, socket = Socket} = State) ->
empty ->
State#state{cur_req = undefined};
{value, #request{caller_controls_socket = Ccs} = NextReq} ->
- case Ccs of
- true ->
- do_setopts(Socket, [{active, once}], State);
- _ ->
- ok
- end,
+ _ = Ccs =:= true
+ andalso do_setopts(Socket, [{active, once}], State),
State#state{cur_req = NextReq}
end.
@@ -1586,6 +1593,7 @@ get_crlf_pos(<<>>, _) -> no.
fmt_val(L) when is_list(L) -> L;
fmt_val(I) when is_integer(I) -> integer_to_list(I);
fmt_val(A) when is_atom(A) -> atom_to_list(A);
+fmt_val(B) when is_binary(B) -> B;
fmt_val(Term) -> io_lib:format("~p", [Term]).
crnl() -> "\r\n".
@@ -1863,13 +1871,13 @@ dec_pipeline_counter(#state{lb_ets_tid = undefined} = State) ->
State;
dec_pipeline_counter(#state{cur_pipeline_size = Pipe_sz,
lb_ets_tid = Tid} = State) ->
- try
- update_counter(Tid, self(), {2,-1,0,0}),
- update_counter(Tid, self(), {3,-1,0,0})
- catch
- _:_ ->
- ok
- end,
+ _ = try
+ update_counter(Tid, self(), {2,-1,0,0}),
+ update_counter(Tid, self(), {3,-1,0,0})
+ catch
+ _:_ ->
+ ok
+ end,
State#state{cur_pipeline_size = Pipe_sz - 1}.
flatten([H | _] = L) when is_integer(H) ->
http://git-wip-us.apache.org/repos/asf/couchdb/blob/948e7d9a/src/ibrowse/ibrowse_lb.erl
----------------------------------------------------------------------
diff --git a/src/ibrowse/ibrowse_lb.erl b/src/ibrowse/ibrowse_lb.erl
index d98cf32..f5a9aef 100644
--- a/src/ibrowse/ibrowse_lb.erl
+++ b/src/ibrowse/ibrowse_lb.erl
@@ -16,7 +16,7 @@
%% External exports
-export([
start_link/1,
- spawn_connection/5,
+ spawn_connection/6,
stop/1
]).
@@ -81,13 +81,14 @@ init([Host, Port]) ->
spawn_connection(Lb_pid, Url,
Max_sessions,
Max_pipeline_size,
- SSL_options)
+ SSL_options,
+ Process_options)
when is_pid(Lb_pid),
is_record(Url, url),
is_integer(Max_pipeline_size),
is_integer(Max_sessions) ->
gen_server:call(Lb_pid,
- {spawn_connection, Url, Max_sessions, Max_pipeline_size, SSL_options}).
+ {spawn_connection, Url, Max_sessions, Max_pipeline_size, SSL_options, Process_options}).
stop(Lb_pid) ->
case catch gen_server:call(Lb_pid, stop) of
@@ -123,19 +124,19 @@ handle_call(_, _From, #state{proc_state = shutting_down} = State) ->
{reply, {error, shutting_down}, State};
%% Update max_sessions in #state with supplied value
-handle_call({spawn_connection, _Url, Max_sess, Max_pipe, _}, _From,
- #state{num_cur_sessions = Num} = State)
+handle_call({spawn_connection, _Url, Max_sess, Max_pipe, _, _}, _From,
+ #state{num_cur_sessions = Num} = State)
when Num >= Max_sess ->
State_1 = maybe_create_ets(State),
Reply = find_best_connection(State_1#state.ets_tid, Max_pipe),
{reply, Reply, State_1#state{max_sessions = Max_sess,
max_pipeline_size = Max_pipe}};
-handle_call({spawn_connection, Url, Max_sess, Max_pipe, SSL_options}, _From,
+handle_call({spawn_connection, Url, Max_sess, Max_pipe, SSL_options, Process_options}, _From,
#state{num_cur_sessions = Cur} = State) ->
State_1 = maybe_create_ets(State),
Tid = State_1#state.ets_tid,
- {ok, Pid} = ibrowse_http_client:start_link({Tid, Url, SSL_options}),
+ {ok, Pid} = ibrowse_http_client:start_link({Tid, Url, SSL_options}, Process_options),
ets:insert(Tid, {Pid, 0, 0}),
{reply, {ok, Pid}, State_1#state{num_cur_sessions = Cur + 1,
max_sessions = Max_sess,
@@ -230,7 +231,9 @@ code_change(_OldVsn, State, _Extra) ->
%%% Internal functions
%%--------------------------------------------------------------------
find_best_connection(Tid, Max_pipe) ->
+ ets:safe_fixtable(Tid, true),
Res = find_best_connection(ets:first(Tid), Tid, Max_pipe),
+ ets:safe_fixtable(Tid, false),
Res.
find_best_connection('$end_of_table', _, _) ->
@@ -239,9 +242,14 @@ find_best_connection(Pid, Tid, Max_pipe) ->
case ets:lookup(Tid, Pid) of
[{Pid, Cur_sz, Speculative_sz}] when Cur_sz < Max_pipe,
Speculative_sz < Max_pipe ->
- ets:update_counter(Tid, Pid, {3, 1, 9999999, 9999999}),
- {ok, Pid};
- _ ->
+ case catch ets:update_counter(Tid, Pid, {3, 1, 9999999, 9999999}) of
+ {'EXIT', _} ->
+ %% The selected process has shutdown
+ find_best_connection(ets:next(Tid, Pid), Tid, Max_pipe);
+ _ ->
+ {ok, Pid}
+ end;
+ _ ->
find_best_connection(ets:next(Tid, Pid), Tid, Max_pipe)
end.
http://git-wip-us.apache.org/repos/asf/couchdb/blob/948e7d9a/src/ibrowse/ibrowse_lib.erl
----------------------------------------------------------------------
diff --git a/src/ibrowse/ibrowse_lib.erl b/src/ibrowse/ibrowse_lib.erl
index 7b12cb3..1ce6bd4 100644
--- a/src/ibrowse/ibrowse_lib.erl
+++ b/src/ibrowse/ibrowse_lib.erl
@@ -362,10 +362,9 @@ parse_url([], get_password, Url, TmpAcc) ->
parse_url([], State, Url, TmpAcc) ->
{invalid_uri_2, State, Url, TmpAcc}.
-default_port(socks5) -> 1080;
-default_port(http) -> 80;
-default_port(https) -> 443;
-default_port(ftp) -> 21.
+default_port(http) -> 80;
+default_port(https) -> 443;
+default_port(ftp) -> 21.
printable_date() ->
{{Y,Mo,D},{H, M, S}} = calendar:local_time(),
http://git-wip-us.apache.org/repos/asf/couchdb/blob/948e7d9a/src/ibrowse/ibrowse_socks5.erl
----------------------------------------------------------------------
diff --git a/src/ibrowse/ibrowse_socks5.erl b/src/ibrowse/ibrowse_socks5.erl
index d00df44..e6d8913 100644
--- a/src/ibrowse/ibrowse_socks5.erl
+++ b/src/ibrowse/ibrowse_socks5.erl
@@ -1,109 +1,58 @@
-% Licensed under the Apache License, Version 2.0 (the "License"); you may not
-% use this file except in compliance with the License. You may obtain a copy of
-% the License at
-%
-% http://www.apache.org/licenses/LICENSE-2.0
-%
-% Unless required by applicable law or agreed to in writing, software
-% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-% License for the specific language governing permissions and limitations under
-% the License.
-
-module(ibrowse_socks5).
--define(VERSION, 5).
--define(CONNECT, 1).
+-include_lib("kernel/src/inet_dns.hrl").
--define(NO_AUTH, 0).
--define(USERPASS, 2).
--define(UNACCEPTABLE, 16#FF).
--define(RESERVED, 0).
+-export([connect/3]).
--define(ATYP_IPV4, 1).
--define(ATYP_DOMAINNAME, 3).
--define(ATYP_IPV6, 4).
+-define(TIMEOUT, 2000).
--define(SUCCEEDED, 0).
+-define(SOCKS5, 5).
+-define(AUTH_METHOD_NO, 0).
+-define(AUTH_METHOD_USERPASS, 2).
+-define(ADDRESS_TYPE_IP4, 1).
+-define(COMMAND_TYPE_TCPIP_STREAM, 1).
+-define(RESERVER, 0).
+-define(STATUS_GRANTED, 0).
--export([connect/5]).
+-define(DNS_IP, {8,8,8,8}).
--import(ibrowse_lib, [get_value/2, get_value/3]).
+connect(Host, Port, Options) ->
+ Socks5Host = proplists:get_value(socks5_host, Options),
+ Socks5Port = proplists:get_value(socks5_port, Options),
-connect(TargetHost, TargetPort, ProxyOptions, Options, Timeout) ->
- case gen_tcp:connect(get_value(host, ProxyOptions),
- get_value(port, ProxyOptions),
- Options, Timeout) of
- {ok, Socket} ->
- case handshake(Socket, Options) of
- ok ->
- case connect(TargetHost, TargetPort, Socket) of
- ok ->
- maybe_ssl(Socket, ProxyOptions, Timeout);
- Else ->
- gen_tcp:close(Socket),
- Else
- end;
- Else ->
- gen_tcp:close(Socket),
- Else
- end;
- Else ->
- Else
- end.
+ {ok, Socket} = gen_tcp:connect(Socks5Host, Socks5Port, [binary, {packet, 0}, {keepalive, true}, {active, false}]),
-handshake(Socket, ProxyOptions) when is_port(Socket) ->
- {Handshake, Success} = case get_value(user, ProxyOptions, <<>>) of
- <<>> ->
- {<<?VERSION, 1, ?NO_AUTH>>, ?NO_AUTH};
- User ->
- Password = get_value(password, ProxyOptions, <<>>),
- {<<?VERSION, 1, ?USERPASS, (byte_size(User)), User,
- (byte_size(Password)), Password>>, ?USERPASS}
- end,
- ok = gen_tcp:send(Socket, Handshake),
- case gen_tcp:recv(Socket, 0) of
- {ok, <<?VERSION, Success>>} ->
- ok;
- {ok, <<?VERSION, ?UNACCEPTABLE>>} ->
- {error, unacceptable};
- {error, Reason} ->
- {error, Reason}
- end.
+ {ok, _Bin} =
+ case proplists:get_value(socks5_user, Options, undefined) of
+ undefined ->
+ ok = gen_tcp:send(Socket, <<?SOCKS5, 1, ?AUTH_METHOD_NO>>),
+ {ok, <<?SOCKS5, ?AUTH_METHOD_NO>>} = gen_tcp:recv(Socket, 2, ?TIMEOUT);
+ _Else ->
+ Socks5User = list_to_binary(proplists:get_value(socks5_user, Options)),
+ Socks5Pass = list_to_binary(proplists:get_value(socks5_pass, Options)),
+
+ ok = gen_tcp:send(Socket, <<?SOCKS5, 1, ?AUTH_METHOD_USERPASS>>),
+ {ok, <<?SOCKS5, ?AUTH_METHOD_USERPASS>>} = gen_tcp:recv(Socket, 2, ?TIMEOUT),
-connect(Host, Port, Via) when is_list(Host) ->
- connect(list_to_binary(Host), Port, Via);
-connect(Host, Port, Via) when is_binary(Host), is_integer(Port),
- is_port(Via) ->
- ok = gen_tcp:send(Via,
- <<?VERSION, ?CONNECT, ?RESERVED, ?ATYP_DOMAINNAME,
- (byte_size(Host)), Host/binary,
- (Port):16>>),
- case gen_tcp:recv(Via, 0) of
- {ok, <<?VERSION, ?SUCCEEDED, ?RESERVED, _/binary>>} ->
- ok;
- {ok, <<?VERSION, Rep, ?RESERVED, _/binary>>} ->
- {error, rep(Rep)};
- {error, Reason} ->
- {error, Reason}
- end.
+ UserLength = byte_size(Socks5User),
-maybe_ssl(Socket, ProxyOptions, Timeout) ->
- IsSsl = get_value(is_ssl, ProxyOptions, false),
- SslOpts = get_value(ssl_opts, ProxyOptions, []),
- case IsSsl of
- false ->
- {ok, Socket};
- true ->
- ssl:connect(Socket, SslOpts, Timeout)
- end.
+ ok = gen_tcp:send(Socket, << 1, UserLength >>),
+ ok = gen_tcp:send(Socket, Socks5User),
+ PassLength = byte_size(Socks5Pass),
+ ok = gen_tcp:send(Socket, << PassLength >>),
+ ok = gen_tcp:send(Socket, Socks5Pass),
+ {ok, <<1, 0>>} = gen_tcp:recv(Socket, 2, ?TIMEOUT)
+ end,
+
+ {IP1,IP2,IP3,IP4} = case inet_parse:address(Host) of
+ {ok, IP} ->
+ IP;
+ _Other ->
+ {ok, NsData} = inet_res:nslookup(Host, in, a, [{?DNS_IP, 53}]),
+ [Addr | _NewAnList] = [D || #dns_rr{data=D, type=a} <- NsData#dns_rec.anlist],
+ Addr
+ end,
-rep(0) -> succeeded;
-rep(1) -> server_fail;
-rep(2) -> disallowed_by_ruleset;
-rep(3) -> network_unreachable;
-rep(4) -> host_unreachable;
-rep(5) -> connection_refused;
-rep(6) -> ttl_expired;
-rep(7) -> command_not_supported;
-rep(8) -> address_type_not_supported.
+ ok = gen_tcp:send(Socket, <<?SOCKS5, ?COMMAND_TYPE_TCPIP_STREAM, ?RESERVER, ?ADDRESS_TYPE_IP4, IP1, IP2, IP3, IP4, Port:16>>),
+ {ok, << ?SOCKS5, ?STATUS_GRANTED, ?RESERVER, ?ADDRESS_TYPE_IP4, IP1, IP2, IP3, IP4, Port:16 >>} = gen_tcp:recv(Socket, 10, ?TIMEOUT),
+ {ok, Socket}.