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/06 15:47:29 UTC

couchdb commit: updated refs/heads/2041-update-ibrowse to fbb4491

Repository: couchdb
Updated Branches:
  refs/heads/2041-update-ibrowse 8b6319f2a -> fbb4491dd (forced update)


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/fbb4491d
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/fbb4491d
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/fbb4491d

Branch: refs/heads/2041-update-ibrowse
Commit: fbb4491dd2195ad3397a457e1cee96dff9a24c88
Parents: 5c9f9a9
Author: Dave Cottlehuber <dc...@apache.org>
Authored: Wed Jan 29 11:05:23 2014 +0100
Committer: Dave Cottlehuber <dc...@apache.org>
Committed: Thu Mar 6 14:46:51 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/fbb4491d/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/fbb4491d/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/fbb4491d/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/fbb4491d/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/fbb4491d/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/fbb4491d/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}.