This is an automated email from the ASF dual-hosted git repository.

jiahuili430 pushed a commit to branch replace-catch-to-try-catch
in repository https://gitbox.apache.org/repos/asf/couchdb-ibrowse.git

commit e68b10284bceb9e93a9c2cef8d5d34171390d53e
Author: Jiahui Li <[email protected]>
AuthorDate: Mon May 18 10:15:59 2026 -0500

    Replace `catch` with `try-catch` to fix the compilation error in OTP-29
    
    ```bash
    $ make
    src/ibrowse_lib.erl:65:10: 'catch ...' is deprecated; please use 'try ... 
catch ... end' instead.
    Compile directive 'nowarn_deprecated_catch' can be used to suppress
    warnings in selected modules.
    %   65|     case catch decode_rfc822_date_1(string:tokens(String, ", 
\t\r\n")) of
    %     |
    ```
---
 src/ibrowse.erl              | 254 +++++++++++++++++++++++-----------
 src/ibrowse_http_client.erl  | 321 ++++++++++++++++++++++++++++++-------------
 src/ibrowse_lb.erl           |  26 +++-
 src/ibrowse_lib.erl          |  26 ++--
 test/ibrowse_load_test.erl   |  46 +++----
 test/ibrowse_test.erl        | 176 ++++++++++++++++++++++--
 test/ibrowse_test_server.erl |  65 +++++++--
 7 files changed, 670 insertions(+), 244 deletions(-)

diff --git a/src/ibrowse.erl b/src/ibrowse.erl
index 5adf047..9116ace 100644
--- a/src/ibrowse.erl
+++ b/src/ibrowse.erl
@@ -91,6 +91,7 @@
          set_max_sessions/3,
          set_max_pipeline_size/3,
          set_max_attempts/3,
+         set_download_dir/1,
          set_dest/3,
          trace_on/0,
          trace_off/0,
@@ -142,11 +143,11 @@ start() ->
 
 %% @doc Stop the ibrowse process. Useful when testing using the shell.
 stop() ->
-    case catch gen_server:call(ibrowse, stop) of
-        {'EXIT',{noproc,_}} ->
-            ok;
-        Res ->
-            Res
+    try
+        gen_server:call(ibrowse, stop)
+    catch
+        exit:{noproc, _} -> ok;
+        exit:Reason -> {'EXIT', Reason}
     end.
 
 %% @doc This is the basic function to send a HTTP request.
@@ -338,28 +339,46 @@ send_req(Url, Headers, Method, Body, Options) ->
 %% @spec send_req(Url, Headers::headerList(), Method::method(), Body::body(), 
Options::optionList(), Timeout) -> response()
 %% Timeout = integer() | infinity
 send_req(Url, Headers, Method, Body, Options, Timeout) ->
-    case catch parse_url(Url) of
-        #url{host = Host,
-             port = Port,
-             protocol = Protocol} = Parsed_url ->
+    try parse_url(Url) of
+        #url{
+            host = Host,
+            port = Port,
+            protocol = Protocol
+        } = Parsed_url ->
             Lb_pid = lb_pid(Host, Port, Parsed_url),
             Max_sessions = get_max_sessions(Host, Port, Options),
             Max_pipeline_size = get_max_pipeline_size(Host, Port, Options),
             Max_attempts = get_max_attempts(Host, Port, Options),
             Options_1 = merge_options(Host, Port, Options),
             {SSLOptions, IsSSL} =
-                case (Protocol == https) orelse
-                    get_value(is_ssl, Options_1, false) of
+                case
+                    (Protocol == https) orelse
+                        get_value(is_ssl, Options_1, false)
+                of
                     false -> {[], false};
                     true -> {get_value(ssl_options, Options_1, []), true}
                 end,
-            try_routing_request(Lb_pid, Parsed_url,
-                                Max_sessions, 
-                                Max_pipeline_size,
-                                {SSLOptions, IsSSL}, 
-                                Headers, Method, Body, Options_1, Timeout, 
Timeout, os:timestamp(), Max_attempts, 0);
+            try_routing_request(
+                Lb_pid,
+                Parsed_url,
+                Max_sessions,
+                Max_pipeline_size,
+                {SSLOptions, IsSSL},
+                Headers,
+                Method,
+                Body,
+                Options_1,
+                Timeout,
+                Timeout,
+                os:timestamp(),
+                Max_attempts,
+                0
+            );
         Err ->
             {error, {url_parsing_failed, Err}}
+    catch
+        _:Reason ->
+            {error, {url_parsing_failed, Reason}}
     end.
 
 lb_pid(Host, Port, Url) ->
@@ -422,7 +441,7 @@ merge_options(Host, Port, Options) ->
                      get_config_value({options, global}, []),
     lists:foldl(
       fun({Key, Val}, Acc) ->
-              case lists:keysearch(Key, 1, Options) of
+              case lists:keyfind(Key, 1, Options) of
                   false ->
                       [{Key, Val} | Acc];
                   _ ->
@@ -496,37 +515,30 @@ set_max_pipeline_size(Host, Port, Max) when 
is_integer(Max), Max > 0 ->
 set_max_attempts(Host, Port, Max) when is_integer(Max), Max > 0 ->
     gen_server:call(?MODULE, {set_config_value, {max_attempts, Host, Port}, 
Max}).
 
+%% @doc set the download directory where the files are stored
+%% @spec set_download_dir(Dir::string()) -> ok
+set_download_dir(Dir) -> 
+    gen_server:call(?MODULE, {set_config_value, download_dir, Dir}).
+
 do_send_req(Conn_Pid, Parsed_url, Headers, Method, Body, Options, Timeout) ->
-    case catch ibrowse_http_client:send_req(Conn_Pid, Parsed_url,
-                                            Headers, Method, ensure_bin(Body),
-                                            Options, Timeout) of
-        {'EXIT', {timeout, _}} ->
-            P_info = case catch erlang:process_info(Conn_Pid, [messages, 
message_queue_len, backtrace]) of
-                            [_|_] = Conn_Pid_info_list ->
-                                Conn_Pid_info_list;
-                            _ ->
-                                process_info_not_available
-                        end,
-            log_msg("{ibrowse_http_client, send_req, ~1000.p} gen_server call 
timeout.~nProcess info: ~p~n",
-                    [[Conn_Pid, Parsed_url, Headers, Method, Body, Options, 
Timeout], P_info]),
-            {error, req_timedout};
-        {'EXIT', {normal, _}} = Ex_rsn ->
-            log_msg("{ibrowse_http_client, send_req, ~1000.p} gen_server call 
got ~1000.p~n",
-                    [[Conn_Pid, Parsed_url, Headers, Method, Body, Options, 
Timeout], Ex_rsn]),
-            {error, req_timedout};
-        {error, X} when X == connection_closed;
-                        X == {send_failed, {error, enotconn}};
-                        X == {send_failed,{error,einval}};
-                        X == {send_failed,{error,closed}};
-                        X == connection_closing;
-                        ((X == connection_closed_no_retry) andalso ((Method == 
get) orelse (Method == head))) ->
+    try
+        ibrowse_http_client:send_req(
+            Conn_Pid, Parsed_url, Headers, Method, ensure_bin(Body), Options, 
Timeout
+        )
+    of
+        {error, X} when
+            X == connection_closed;
+            X == {send_failed, {error, enotconn}};
+            X == {send_failed, {error, einval}};
+            X == {send_failed, {error, closed}};
+            X == connection_closing;
+            ((X == connection_closed_no_retry) andalso ((Method == get) orelse 
(Method == head)))
+            ->
             {error, sel_conn_closed};
         {error, connection_closed_no_retry} ->
             {error, connection_closed};
         {error, {'EXIT', {noproc, _}}} ->
             {error, sel_conn_closed};
-        {'EXIT', Reason} ->
-            {error, {'EXIT', Reason}};
         {ok, St_code, Headers, Body} = Ret when is_binary(Body) ->
             case get_value(response_format, Options, list) of
                 list ->
@@ -543,6 +555,35 @@ do_send_req(Conn_Pid, Parsed_url, Headers, Method, Body, 
Options, Timeout) ->
             end;
         Ret ->
             Ret
+    catch
+        throw:Term ->
+            Term;
+        exit:{timeout, _} ->
+            P_info =
+                try erlang:process_info(Conn_Pid, [messages, 
message_queue_len, backtrace]) of
+                    [_ | _] = Conn_Pid_info_list ->
+                        Conn_Pid_info_list;
+                    _ ->
+                        process_info_not_available
+                catch
+                    _:_ ->
+                        process_info_not_available
+                end,
+            log_msg(
+                "{ibrowse_http_client, send_req, ~1000.p} gen_server call 
timeout.~nProcess info: ~p~n",
+                [[Conn_Pid, Parsed_url, Headers, Method, Body, Options, 
Timeout], P_info]
+            ),
+            {error, req_timedout};
+        exit:{normal, _} = Ex_rsn ->
+            log_msg(
+                "{ibrowse_http_client, send_req, ~1000.p} gen_server call got 
~1000.p~n",
+                [[Conn_Pid, Parsed_url, Headers, Method, Body, Options, 
Timeout], Ex_rsn]
+            ),
+            {error, req_timedout};
+        exit:Reason ->
+            {'EXIT', Reason};
+        error:Reason:Stacktrace ->
+            {'EXIT', {Reason, Stacktrace}}
     end.
 
 ensure_bin(L) when is_list(L)                     -> list_to_binary(L);
@@ -614,9 +655,11 @@ send_req_direct(Conn_pid, Url, Headers, Method, Body, 
Options) ->
 %% @doc Same as send_req/6 except that the first argument is the PID
 %% returned by spawn_worker_process/2 or spawn_link_worker_process/2
 send_req_direct(Conn_pid, Url, Headers, Method, Body, Options, Timeout) ->
-    case catch parse_url(Url) of
-        #url{host = Host,
-             port = Port} = Parsed_url ->
+    try parse_url(Url) of
+        #url{
+            host = Host,
+            port = Port
+        } = Parsed_url ->
             Options_1 = merge_options(Host, Port, Options),
             case do_send_req(Conn_pid, Parsed_url, Headers, Method, Body, 
Options_1, Timeout) of
                 {error, {'EXIT', {noproc, _}}} ->
@@ -626,18 +669,27 @@ send_req_direct(Conn_pid, Url, Headers, Method, Body, 
Options, Timeout) ->
             end;
         Err ->
             {error, {url_parsing_failed, Err}}
+    catch
+        _:Reason ->
+            {error, {url_parsing_failed, Reason}}
     end.
 
 %% @doc Tell ibrowse to stream the next chunk of data to the
 %% caller. Should be used in conjunction with the
 %% <code>stream_to</code> option
 %% @spec stream_next(Req_id :: req_id()) -> ok | {error, unknown_req_id}
-stream_next(Req_id) ->    
+stream_next(Req_id) ->
     case ets:lookup(ibrowse_stream, {req_id_pid, Req_id}) of
         [] ->
             {error, unknown_req_id};
         [{_, Pid}] ->
-            catch Pid ! {stream_next, Req_id},
+            try
+                Pid ! {stream_next, Req_id}
+            catch
+                throw:Term -> Term;
+                exit:Reason -> {'EXIT', Reason};
+                error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+            end,
             ok
     end.
 
@@ -647,12 +699,18 @@ stream_next(Req_id) ->
 %% the connection which is serving this Req_id will be aborted, and an
 %% error returned.
 %% @spec stream_close(Req_id :: req_id()) -> ok | {error, unknown_req_id}
-stream_close(Req_id) ->    
+stream_close(Req_id) ->
     case ets:lookup(ibrowse_stream, {req_id_pid, Req_id}) of
         [] ->
             {error, unknown_req_id};
         [{_, Pid}] ->
-            catch Pid ! {stream_close, Req_id},
+            try
+                Pid ! {stream_close, Req_id}
+            catch
+                throw:Term -> Term;
+                exit:Reason -> {'EXIT', Reason};
+                error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+            end,
             ok
     end.
 
@@ -688,7 +746,6 @@ all_trace_off() ->
 %% @doc Shows some internal information about load balancing. Info
 %% about workers spawned using spawn_worker_process/2 or
 %% spawn_link_worker_process/2 is not included.
--ifdef(ets_ref).
 show_dest_status() ->
     io:format("~-40.40s | ~-5.5s | ~-10.10s | ~s~n",
               ["Server:port", "ETS", "Num conns", "LB Pid"]),
@@ -702,21 +759,6 @@ show_dest_status() ->
                          integer_to_list(Size), 
                          Lb_pid])
       end, Metrics).
--else.
-show_dest_status() ->
-    io:format("~-40.40s | ~-5.5s | ~-10.10s | ~s~n",
-              ["Server:port", "ETS", "Num conns", "LB Pid"]),
-    io:format("~80.80.=s~n", [""]),
-    Metrics = get_metrics(),
-    lists:foreach(
-      fun({Host, Port, {Lb_pid, _, Tid, Size, _}}) ->
-              io:format("~40.40s | ~-5.5s | ~-5.5s | ~p~n",
-                        [Host ++ ":" ++ integer_to_list(Port),
-                         integer_to_list(Tid),
-                         integer_to_list(Size), 
-                         Lb_pid])
-      end, Metrics).
--endif.
 
 show_dest_status(Url) ->                                          
     #url{host = Host, port = Port} = ibrowse_lib:parse_url(Url),
@@ -767,12 +809,15 @@ get_metrics(Host, Port) ->
         [] ->
             no_active_processes;
         [#lb_pid{pid = Lb_pid, ets_tid = Tid}] ->
-            MsgQueueSize = case (catch process_info(Lb_pid, 
message_queue_len)) of
-                              {message_queue_len, Msg_q_len} ->
-                                  Msg_q_len;
-                              _ ->
-                                  -1
-                          end,
+            MsgQueueSize =
+                try process_info(Lb_pid, message_queue_len) of
+                    {message_queue_len, Msg_q_len} ->
+                        Msg_q_len;
+                    _ ->
+                        -1
+                catch
+                    _:_ -> -1
+                end,
             case Tid of
                 undefined ->
                     {Lb_pid, MsgQueueSize, undefined, 0, {{0, 0}, {0, 0}}};
@@ -934,19 +979,47 @@ handle_call({set_config_value, Key, Val}, _From, State) ->
     {reply, ok, State};
 
 handle_call(rescan_config, _From, State) ->
-    Ret = (catch import_config()),
+    Ret =
+        try
+            import_config()
+        catch
+            throw:Term -> Term;
+            exit:Reason -> {'EXIT', Reason};
+            error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+        end,
     {reply, Ret, State};
 
 handle_call({rescan_config, File}, _From, State) ->
-    Ret = (catch import_config(File)),
+    Ret =
+        try
+            import_config(File)
+        catch
+            throw:Term -> Term;
+            exit:Reason -> {'EXIT', Reason};
+            error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+        end,
     {reply, Ret, State};
 
 handle_call({rescan_config_terms, Terms}, _From, State) ->
-    Ret = (catch apply_config(Terms)),
+    Ret =
+        try
+            apply_config(Terms)
+        catch
+            throw:Term -> Term;
+            exit:Reason -> {'EXIT', Reason};
+            error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+        end,
     {reply, Ret, State};
 
 handle_call({add_config_terms, Terms}, _From, State) ->
-    Ret = (catch insert_config(Terms)),
+    Ret =
+        try
+            insert_config(Terms)
+        catch
+            throw:Term -> Term;
+            exit:Reason -> {'EXIT', Reason};
+            error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+        end,
     {reply, Ret, State};
 
 handle_call(Request, _From, State) ->
@@ -979,7 +1052,13 @@ handle_info(all_trace_off, State) ->
                       false ->
                           ok;
                       true ->
-                          catch Pid ! {trace, false}
+                          try
+                              Pid ! {trace, false}
+                          catch
+                              throw:Term -> Term;
+                              exit:Reason -> {'EXIT', Reason};
+                              error:Reason:Stacktrace -> {'EXIT', {Reason, 
Stacktrace}}
+                          end
                   end;
              (_, Acc) ->
                   Acc
@@ -993,13 +1072,22 @@ handle_info({trace, Bool}, State) ->
     {noreply, State};
 
 handle_info({trace, Bool, Host, Port}, State) ->
-    Fun = fun(#lb_pid{host_port = {H, P}, pid = Pid}, _)
-             when H == Host,
-                  P == Port ->
-                  catch Pid ! {trace, Bool};
-             (_, Acc) ->
-                  Acc
-          end,
+    Fun =
+        fun
+            (#lb_pid{host_port = {H, P}, pid = Pid}, _) when
+                H == Host,
+                P == Port
+                ->
+                try
+                    Pid ! {trace, Bool}
+                catch
+                    throw:Term -> Term;
+                    exit:Reason -> {'EXIT', Reason};
+                    error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+                end;
+            (_, Acc) ->
+                Acc
+        end,
     ets:foldl(Fun, undefined, ibrowse_lb),
     ets:insert(ibrowse_conf, #ibrowse_conf{key = {trace, Host, Port},
                                            value = Bool}),
diff --git a/src/ibrowse_http_client.erl b/src/ibrowse_http_client.erl
index 443772e..2b9aa53 100644
--- a/src/ibrowse_http_client.erl
+++ b/src/ibrowse_http_client.erl
@@ -19,7 +19,8 @@
          start/1,
          start/2,
          stop/1,
-         send_req/7
+         send_req/7,
+         chunk_request_body/2
         ]).
 
 -ifdef(debug).
@@ -102,23 +103,29 @@ start_link(Args, Options) ->
     gen_server:start_link(?MODULE, Args, Options).
 
 stop(Conn_pid) ->
-    case catch gen_server:call(Conn_pid, stop) of
-        {'EXIT', {timeout, _}} ->
+    try gen_server:call(Conn_pid, stop) of
+        _ ->
+            ok
+    catch
+        exit:{timeout, _} ->
             exit(Conn_pid, kill),
             ok;
-        _ ->
+        _:_ ->
             ok
     end.
 
 send_req(Conn_Pid, Url, Headers, Method, Body, Options, Timeout) ->
-    case catch gen_server:call(Conn_Pid,
-                               {send_req, {Url, Headers, Method, Body, 
Options, Timeout}}, Timeout) of
-        {'EXIT', {timeout, _}} ->
+    try
+        gen_server:call(
+            Conn_Pid, {send_req, {Url, Headers, Method, Body, Options, 
Timeout}}, Timeout
+        )
+    catch
+        exit:{timeout, _} ->
             {error, req_timedout};
-        {'EXIT', {noproc, _}} ->
+        exit:{noproc, _} ->
             {error, connection_closed};
-        Res ->
-            Res
+        exit:Reason ->
+            {'EXIT', Reason}
     end.
 
 %%====================================================================
@@ -145,10 +152,13 @@ init({Lb_Tid, #url{host = Host, port = Port}, 
{SSLOptions, Is_ssl}}) ->
     {ok, set_inac_timer(State)};
 init(Url) when is_list(Url) ->
     maybe_trap_exits(),
-    case catch ibrowse_lib:parse_url(Url) of
+    try ibrowse_lib:parse_url(Url) of
         #url{protocol = Protocol} = Url_rec ->
             init({undefined, Url_rec, {[], Protocol == https}});
-        {'EXIT', _} ->
+        _ ->
+            {error, invalid_url}
+    catch
+        _:_ ->
             {error, invalid_url}
     end;
 init({Host, Port}) ->
@@ -266,11 +276,17 @@ handle_info({ssl_error, _Sock, Reason}, State) ->
 
 handle_info({req_timedout, From}, #state{reqs = Reqs} = State) ->
     Reqs_list = queue:to_list(Reqs),
-    case lists:keysearch(From, #request.from, Reqs_list) of
+    case lists:keyfind(From, #request.from, Reqs_list) of
         false ->
             {noreply, State};
-        {value, #request{stream_to = StreamTo, req_id = ReqId}} ->
-            catch StreamTo ! {ibrowse_async_response_timeout, ReqId},
+        #request{stream_to = StreamTo, req_id = ReqId} ->
+            try
+                StreamTo ! {ibrowse_async_response_timeout, ReqId}
+            catch
+                throw:Term -> Term;
+                exit:Reason -> {'EXIT', Reason};
+                error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+            end,
             State_1 = State#state{proc_state = ?dead_proc_walking},
             shutting_down(State_1),
             Reqs_1 = lists:filter(fun(#request{from = X_from}) ->
@@ -311,7 +327,13 @@ handle_info(Info, State) ->
 terminate(_Reason, #state{lb_ets_tid = Tid} = State) ->
     do_close(State),
     shutting_down(State),
-    (catch ets:select_delete(Tid, 
[{{{'_','_','$1'},'_'},[{'==','$1',{const,self()}}],[true]}])),
+    try
+        ets:select_delete(Tid, 
[{{{'_','_','$1'},'_'},[{'==','$1',{const,self()}}],[true]}])
+    catch
+        throw:Term -> Term;
+        exit:Reason -> {'EXIT', Reason};
+        error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+    end,
     ok.
 
 %%--------------------------------------------------------------------
@@ -322,11 +344,10 @@ terminate(_Reason, #state{lb_ets_tid = Tid} = State) ->
 code_change(_OldVsn, State, _Extra) ->
     {ok, State}.
 
-
 %%--------------------------------------------------------------------
 %% Function: format_status/1
 %% Purpose: Clean process state before logging
-%% Returns: key value maps
+%% Returns: #{state => ScrubbedState}
 %%--------------------------------------------------------------------
 format_status(Status) ->
     maps:map(
@@ -539,13 +560,9 @@ accumulate_response(Data, #state{reply_buffer      = 
RepBuf,
     end.
 
 generate_timestamp() ->
-    case catch erlang:unique_integer([positive]) of
-        {'EXIT', _} ->
-            erlang:apply(erlang, now, []);
-        Unique ->
-            {A,B,C} = os:timestamp(),
-            {A * 1000000 + B, C, Unique}
-    end.
+    {A, B, C} = os:timestamp(),
+    Unique = erlang:unique_integer([positive]),
+    {A * 1000000 + B, C, Unique}.
 
 make_tmp_filename(true) ->
     DownloadDir = ibrowse:get_config_value(download_dir, 
filename:absname("./")),
@@ -634,13 +651,18 @@ do_connect(Host, Port, Options, #state{is_ssl      = true,
                                        use_proxy   = false,
                                        ssl_options = SSLOptions},
            Timeout) ->
+    %% Check for connect_to override and remove from options
+    Host1 = get_value(connect_to, Options, Host),
+    Options1 = proplists:delete(connect_to, Options),
+    
     %% if a socks5 proxy is configured, open the socket separately
     %% before upgrading the socket to a TLS connection.
-    case get_value(socks5_host, Options, undefined) of
+    case get_value(socks5_host, Options1, undefined) of
         %% no socks5 proxy is configured, connect directly with TLS:
         undefined ->
-            Sock_options = get_sock_options(Host, Options, SSLOptions),
-            ssl:connect(Host, Port, Sock_options, Timeout);
+            Sock_options = get_sock_options(Host, Options1, SSLOptions),
+            Sock_options1 = ensure_sni(Sock_options, Host),
+            ssl:connect(Host1, Port, Sock_options1, Timeout);
 
         %% proxy configuration is present: first establish a socket
         %% and then upgrade:
@@ -657,13 +679,23 @@ do_connect(Host, Port, Options, #state{is_ssl      = true,
     end;
 
 do_connect(Host, Port, Options, _State, Timeout) ->
-    Socks5Host = get_value(socks5_host, Options, undefined),
-    Sock_options = get_sock_options(Host, Options, []),
+    %% Check for connect_to override and remove from options
+    Host1 = get_value(connect_to, Options, Host),
+    Options1 = proplists:delete(connect_to, Options),
+
+    Socks5Host = get_value(socks5_host, Options1, undefined),
+    Sock_options = get_sock_options(Host, Options1, []),
     case Socks5Host of
-      undefined ->
-        gen_tcp:connect(Host, Port, Sock_options, Timeout);
-      _ ->
-        catch ibrowse_socks5:connect(Host, Port, Options, Sock_options, 
Timeout)
+        undefined ->
+            gen_tcp:connect(Host1, Port, Sock_options, Timeout);
+        _ ->
+            try
+                ibrowse_socks5:connect(Host1, Port, Options1, Sock_options, 
Timeout)
+            catch
+                throw:Term -> Term;
+                exit:Reason -> {'EXIT', Reason};
+                error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+            end
     end.
 
 get_sock_options(Host, Options, SSLOptions) ->
@@ -681,10 +713,10 @@ get_sock_options(Host, Options, SSLOptions) ->
                           []
                   end,
     Other_sock_options = filter_sock_options(SSLOptions ++ 
Caller_socket_options ++ Ipv6Options),
-    case lists:keysearch(nodelay, 1, Other_sock_options) of
+    case lists:keyfind(nodelay, 1, Other_sock_options) of
         false ->
             [{nodelay, true}, binary, {active, false} | Other_sock_options];
-        {value, _} ->
+        _ ->
             [binary, {active, false} | Other_sock_options]
     end.
 
@@ -711,10 +743,20 @@ filter_sock_options(Opts) ->
                          false;
                     (list) ->
                          false;
+
                     (_) ->
                          true
                  end, Opts).
 
+%% Ensure SNI is set for SSL connections when using connect_to override
+ensure_sni(Opts, Host) ->
+    case lists:keyfind(server_name_indication, 1, Opts) of
+        false ->
+            [{server_name_indication, Host} | Opts];
+        _ ->
+            Opts
+    end.
+
 do_send(Req, #state{socket = Sock,
                     is_ssl = true,
                     use_proxy = true,
@@ -807,9 +849,30 @@ do_close(#state{socket = Sock,
                 is_ssl = 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);
-do_close(#state{socket = Sock, is_ssl = false}) ->  catch gen_tcp:close(Sock).
+               }) when Pts /= done ->
+    try
+        gen_tcp:close(Sock)
+    catch
+        throw:Term -> Term;
+        exit:Reason -> {'EXIT', Reason};
+        error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+    end;
+do_close(#state{socket = Sock, is_ssl = true})  ->
+    try
+        ssl:close(Sock)
+    catch
+        throw:Term -> Term;
+        exit:Reason -> {'EXIT', Reason};
+        error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+    end;
+do_close(#state{socket = Sock, is_ssl = false}) ->
+    try
+        gen_tcp:close(Sock)
+    catch
+        throw:Term -> Term;
+        exit:Reason -> {'EXIT', Reason};
+        error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+    end.
 
 active_once(#state{cur_req = #request{caller_controls_socket = true}}) ->
     ok;
@@ -1023,7 +1086,13 @@ send_req_1(From,
                                 false ->
                                     ok;
                                 true ->
-                                    catch StreamTo ! {ibrowse_async_raw_req, 
Raw_req}
+                                    try
+                                        StreamTo ! {ibrowse_async_raw_req, 
Raw_req}
+                                    catch
+                                        throw:Term -> Term;
+                                        exit:Reason -> {'EXIT', Reason};
+                                        error:Reason:Stacktrace -> {'EXIT', 
{Reason, Stacktrace}}
+                                    end
                             end
                     end,
                     State_4 = set_inac_timer(State_3),
@@ -1053,14 +1122,14 @@ maybe_modify_headers(#url{host = Host, port = Port} = 
Url,
     case get_value(headers_as_is, Options, false) of
         false ->
             Headers_1 = add_auth_headers(Url, Options, Headers, State),
-            HostHeaderValue = case lists:keysearch(host_header, 1, Options) of
+            HostHeaderValue = case lists:keyfind(host_header, 1, Options) of
                                   false ->
                                       case Port of
                                           80 -> Host;
                                           443 -> Host;
                                           _ -> [Host, ":", 
integer_to_list(Port)]
                                       end;
-                                  {value, {_, Host_h_val}} ->
+                                  {_, Host_h_val} ->
                                       Host_h_val
                               end,
             [{"Host", HostHeaderValue} | Headers_1];
@@ -1108,7 +1177,7 @@ make_request(Method, Headers, AbsPath, RelPath, Body, 
Options,
            end,
     Headers_0 = [Fun1(X) || X <- Headers],
     Headers_1 =
-        case lists:keysearch("content-length", 1, Headers_0) of
+        case lists:keyfind("content-length", 1, Headers_0) of
             false when (Body =:= [] orelse Body =:= <<>>) andalso
                        (Method =:= post orelse Method =:= put) ->
                 [{"content-length", "Content-Length", "0"} | Headers_0];
@@ -1202,33 +1271,36 @@ chunk_request_body(Body, _ChunkSize) when 
is_tuple(Body) orelse
 chunk_request_body(Body, ChunkSize) ->
     chunk_request_body(Body, ChunkSize, []).
 
-chunk_request_body(Body, _ChunkSize, Acc) when Body == <<>>; Body == [] ->
+chunk_request_body(Body, ChunkSize, Acc) when is_binary(Body) ->
+    chunk_binary_body(Body, ChunkSize, Acc);
+chunk_request_body([], _ChunkSize, Acc) ->
     LastChunk = "0\r\n",
     lists:reverse(["\r\n", LastChunk | Acc]);
-chunk_request_body(Body, ChunkSize, Acc) when is_binary(Body),
-                                              size(Body) >= ChunkSize ->
-    <<ChunkBody:ChunkSize/binary, Rest/binary>> = Body,
-    Chunk = [?dec2hex(ChunkSize),"\r\n",
-             ChunkBody, "\r\n"],
-    chunk_request_body(Rest, ChunkSize, [Chunk | Acc]);
-chunk_request_body(Body, _ChunkSize, Acc) when is_binary(Body) ->
-    BodySize = size(Body),
-    Chunk = [?dec2hex(BodySize),"\r\n",
-             Body, "\r\n"],
-    LastChunk = "0\r\n",
-    lists:reverse(["\r\n", LastChunk, Chunk | Acc]);
 chunk_request_body(Body, ChunkSize, Acc) when length(Body) >= ChunkSize ->
     {ChunkBody, Rest} = split_list_at(Body, ChunkSize),
-    Chunk = [?dec2hex(ChunkSize),"\r\n",
-             ChunkBody, "\r\n"],
+    Chunk = [?dec2hex(ChunkSize),"\r\n", ChunkBody, "\r\n"],
     chunk_request_body(Rest, ChunkSize, [Chunk | Acc]);
 chunk_request_body(Body, _ChunkSize, Acc) when is_list(Body) ->
     BodySize = length(Body),
-    Chunk = [?dec2hex(BodySize),"\r\n",
-             Body, "\r\n"],
+    Chunk = [?dec2hex(BodySize),"\r\n", Body, "\r\n"],
     LastChunk = "0\r\n",
     lists:reverse(["\r\n", LastChunk, Chunk | Acc]).
 
+chunk_binary_body(Body, ChunkSize, Acc) ->
+    case Body of
+        <<ChunkBody:ChunkSize/binary, Rest/binary>> ->
+            Chunk = [?dec2hex(ChunkSize),"\r\n", ChunkBody, "\r\n"],
+            chunk_binary_body(Rest, ChunkSize, [Chunk | Acc]);
+        <<>> ->
+            LastChunk = "0\r\n",
+            lists:reverse(["\r\n", LastChunk | Acc]);
+        _ ->
+            BodySize = byte_size(Body),
+            Chunk = [?dec2hex(BodySize),"\r\n", Body, "\r\n"],
+            LastChunk = "0\r\n",
+            lists:reverse(["\r\n", LastChunk, Chunk | Acc])
+    end.
+
 
 parse_response(<<>>, #state{cur_req = undefined}=State) ->
     State#state{status = idle};
@@ -1382,26 +1454,37 @@ parse_response(Data, #state{reply_buffer = Acc, reqs = 
Reqs,
                                                      {stat_code, StatCode}, 
Headers}}),
                     {error, content_length_undefined};
                 V ->
-                    case catch list_to_integer(V) of
+                    try list_to_integer(V) of
                         V_1 when is_integer(V_1), V_1 >= 0 ->
                             send_async_headers(ReqId, StreamTo, 
Give_raw_headers, State_1),
                             do_trace("Recvd Content-Length of ~p~n", [V_1]),
-                            State_2 = State_1#state{rep_buf_size=0,
-                                                    reply_buffer = <<>>,
-                                                    content_length=V_1},
+                            State_2 = State_1#state{
+                                rep_buf_size = 0,
+                                reply_buffer = <<>>,
+                                content_length = V_1
+                            },
                             case parse_11_response(Data_1, State_2) of
                                 {error, Reason} ->
-                                    fail_pipelined_requests(State_1,
-                                                            {error, {Reason,
-                                                                     
{stat_code, StatCode}, Headers_1}}),
+                                    fail_pipelined_requests(
+                                        State_1,
+                                        {error, {Reason, {stat_code, 
StatCode}, Headers_1}}
+                                    ),
                                     {error, Reason};
                                 State_3 ->
                                     State_3
                             end;
                         _ ->
-                            fail_pipelined_requests(State_1,
-                                                    {error, 
{content_length_undefined,
-                                                             {stat_code, 
StatCode}, Headers}}),
+                            fail_pipelined_requests(
+                                State_1,
+                                {error, {content_length_undefined, {stat_code, 
StatCode}, Headers}}
+                            ),
+                            {error, content_length_undefined}
+                    catch
+                        _:_ ->
+                            fail_pipelined_requests(
+                                State_1,
+                                {error, {content_length_undefined, {stat_code, 
StatCode}, Headers}}
+                            ),
                             {error, content_length_undefined}
                     end
             end;
@@ -1425,7 +1508,7 @@ upgrade_to_ssl(#state{socket = Socket,
                                   proxy_tunnel_setup = done},
             send_queued_requests(lists:reverse(Q), State_1);
         Err ->
-            do_trace("Upgrade to SSL socket failed. Reson: ~p~n", [Err]),
+            do_trace("Upgrade to SSL socket failed. Reason: ~p~n", [Err]),
             do_error_reply(State, {error, {send_failed, Err}}),
             {error, send_failed}
     end.
@@ -1956,9 +2039,21 @@ send_async_headers(ReqId, StreamTo, Give_raw_headers,
     {Headers_1, Raw_headers_1} = maybe_add_custom_headers(Status_line, 
Headers, Raw_headers, Opts),
     case Give_raw_headers of
         false ->
-            catch StreamTo ! {ibrowse_async_headers, ReqId, StatCode, 
Headers_1};
+            try
+                StreamTo ! {ibrowse_async_headers, ReqId, StatCode, Headers_1}
+            catch
+                throw:Term -> Term;
+                exit:Reason -> {'EXIT', Reason};
+                error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+            end;
         true ->
-            catch StreamTo ! {ibrowse_async_headers, ReqId, Status_line, 
Raw_headers_1}
+            try
+                StreamTo ! {ibrowse_async_headers, ReqId, Status_line, 
Raw_headers_1}
+            catch
+                throw:Term -> Term;
+                exit:Reason -> {'EXIT', Reason};
+                error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+            end
     end.
 
 maybe_add_custom_headers(Status_line, Headers, Raw_headers, Opts) ->
@@ -2012,16 +2107,28 @@ do_reply(#state{prev_req_id = Prev_req_id} = State,
             ok;
         _ ->
             Body_1 = format_response_data(Resp_format, Body),
-            catch StreamTo ! {ibrowse_async_response, ReqId, Body_1}
+            try
+                StreamTo ! {ibrowse_async_response, ReqId, Body_1}
+            catch
+                throw:Term -> Term;
+                exit:Reason -> {'EXIT', Reason};
+                error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+            end
+    end,
+    try
+        StreamTo ! {ibrowse_async_response_end, ReqId}
+    catch
+        throw:_Term -> _Term;
+        exit:_Reason -> {'EXIT', _Reason};
+        error:_Reason:_Stacktrace -> {'EXIT', {_Reason, _Stacktrace}}
     end,
-    catch StreamTo ! {ibrowse_async_response_end, ReqId},
-    %% We don't want to delete the Req-id to Pid mapping straightaway
+    %% We don't want to delete the Req-id to Pid mapping straight away
     %% as the client may send a stream_next message just while we are
     %% sending back this ibrowse_async_response_end message. If we
-    %% deleted this mapping straightaway, the caller will see a
+    %% deleted this mapping straight away, the caller will see a
     %% {error, unknown_req_id} when it calls ibrowse:stream_next/1. To
     %% get around this, we store the req id, and clear it after the
-    %% next request. If there are wierd combinations of stream,
+    %% next request. If there are weird combinations of stream,
     %% stream_once and sync requests on the same connection, it will
     %% take a while for the req_id-pid mapping to get cleared, but it
     %% should do no harm.
@@ -2030,14 +2137,26 @@ do_reply(#state{prev_req_id = Prev_req_id} = State,
 do_reply(State, _From, StreamTo, ReqId, Resp_format, Msg) ->
     State_1 = dec_pipeline_counter(State),
     Msg_1 = format_response_data(Resp_format, Msg),
-    catch StreamTo ! {ibrowse_async_response, ReqId, Msg_1},
+    try
+        StreamTo ! {ibrowse_async_response, ReqId, Msg_1}
+    catch
+        throw:Term -> Term;
+        exit:Reason -> {'EXIT', Reason};
+        error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+    end,
     State_1.
 
 do_interim_reply(undefined, _, _ReqId, _Msg) ->
     ok;
 do_interim_reply(StreamTo, Response_format, ReqId, Msg) ->
     Msg_1 = format_response_data(Response_format, Msg),
-    catch StreamTo ! {ibrowse_async_response, ReqId, Msg_1}.
+    try
+        StreamTo ! {ibrowse_async_response, ReqId, Msg_1}
+    catch
+        throw:Term -> Term;
+        exit:Reason -> {'EXIT', Reason};
+        error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+    end.
 
 do_error_reply(#state{reqs = Reqs, tunnel_setup_queue = Tun_q} = State, Err) ->
     ReqList = queue:to_list(Reqs),
@@ -2130,7 +2249,13 @@ shutting_down(#state{lb_ets_tid = undefined}) ->
     ok;
 shutting_down(#state{lb_ets_tid = Tid,
                      cur_pipeline_size = _Sz}) ->
-    (catch ets:select_delete(Tid, [{{{'_', '_', 
'$1'},'_'},[{'==','$1',{const,self()}}],[true]}])).
+    try
+        ets:select_delete(Tid, [{{{'_', '_', 
'$1'},'_'},[{'==','$1',{const,self()}}],[true]}])
+    catch
+        throw:Term -> Term;
+        exit:Reason -> {'EXIT', Reason};
+        error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+    end.
 
 inc_pipeline_counter(#state{is_closing = true} = State) ->
     State;
@@ -2144,12 +2269,24 @@ dec_pipeline_counter(#state{cur_pipeline_size = Pipe_sz,
                             proc_state        = Proc_state} = State) when Tid 
/= undefined,
                                                                           
Proc_state /= ?dead_proc_walking ->
     Ts = os:timestamp(),
-    catch ets:insert(Tid, {{Pipe_sz - 1, os:timestamp(), self()}, []}),
-    (catch ets:select_delete(Tid, [{{{'_', '$2', '$1'},'_'},
-                                    [{'==', '$1', {const,self()}},
-                                     {'<',  '$2', {const,Ts}}
-                                    ],
-                                    [true]}])),
+    try
+        ets:insert(Tid, {{Pipe_sz - 1, os:timestamp(), self()}, []})
+    catch
+        throw:Term -> Term;
+        exit:Reason -> {'EXIT', Reason};
+        error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+    end,
+    try
+        ets:select_delete(Tid, [{{{'_', '$2', '$1'},'_'},
+                                 [{'==', '$1', {const,self()}},
+                                  {'<',  '$2', {const,Ts}}
+                                 ],
+                                 [true]}])
+    catch
+        throw:_Term -> _Term;
+        exit:_Reason -> {'EXIT', _Reason};
+        error:_Reason:_Stacktrace -> {'EXIT', {_Reason, _Stacktrace}}
+    end,
     State#state{cur_pipeline_size = Pipe_sz - 1};
 dec_pipeline_counter(State) ->
     State.
@@ -2166,8 +2303,8 @@ get_stream_chunk_size(Options) ->
         true ->
             infinity;
         _ ->
-            case lists:keysearch(stream_chunk_size, 1, Options) of
-                {value, {_, V}} when V > 0 ->
+            case lists:keyfind(stream_chunk_size, 1, Options) of
+                {_, V} when V > 0 ->
                     V;
                 _ ->
                     ?DEFAULT_STREAM_CHUNK_SIZE
@@ -2234,12 +2371,12 @@ to_binary(X) when is_list(X)          -> 
list_to_binary(X);
 to_binary(X) when is_binary(X)        -> X.
 
 get_header_value(Name, Headers, Default_val) ->
-    case lists:keysearch(Name, 1, Headers) of
+    case lists:keyfind(Name, 1, Headers) of
         false ->
             Default_val;
-        {value, {_, Val}} when is_binary(Val) ->
+        {_, Val} when is_binary(Val) ->
             binary_to_list(Val);
-        {value, {_, Val}} ->
+        {_, Val} ->
             Val
     end.
 
diff --git a/src/ibrowse_lb.erl b/src/ibrowse_lb.erl
index 894d8ad..e7b19ce 100644
--- a/src/ibrowse_lb.erl
+++ b/src/ibrowse_lb.erl
@@ -90,11 +90,11 @@ spawn_connection(Lb_pid, Url,
                    {spawn_connection, Url, Max_sessions, Max_pipeline_size, 
SSL_options, Process_options}).
 
 stop(Lb_pid) ->
-    case catch gen_server:call(Lb_pid, stop) of
-        {'EXIT', {timeout, _}} ->
-            exit(Lb_pid, kill);
-        ok ->
-            ok
+    try
+        gen_server:call(Lb_pid, stop)
+    catch
+        exit:{timeout, _} -> exit(Lb_pid, kill);
+        exit:Reason -> {'EXIT', Reason}
     end.
 %%--------------------------------------------------------------------
 %% Function: handle_call/3
@@ -165,7 +165,13 @@ handle_info({trace, Bool}, #state{ets_tid = undefined} = 
State) ->
 
 handle_info({trace, Bool}, #state{ets_tid = Tid} = State) ->
     ets:foldl(fun({{_, Pid}, _}, Acc) when is_pid(Pid) ->
-                     catch Pid ! {trace, Bool},
+              try
+                  Pid ! {trace, Bool}
+              catch
+                  throw:Term -> Term;
+                  exit:Reason -> {'EXIT', Reason};
+                  error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+              end,
                      Acc;
                 (_, Acc) ->
                      Acc
@@ -194,7 +200,13 @@ handle_info(_Info, State) ->
 %% Returns: any (ignored by gen_server)
 %%--------------------------------------------------------------------
 terminate(_Reason, #state{host = Host, port = Port, ets_tid = Tid} = _State) ->
-    catch ets:delete(ibrowse_lb, {Host, Port}),
+    try
+        ets:delete(ibrowse_lb, {Host, Port})
+    catch
+        throw:Term -> Term;
+        exit:Reason -> {'EXIT', Reason};
+        error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+    end,
     stop_all_conn_procs(Tid),
     ok.
 
diff --git a/src/ibrowse_lib.erl b/src/ibrowse_lib.erl
index 6c1883d..4053721 100644
--- a/src/ibrowse_lib.erl
+++ b/src/ibrowse_lib.erl
@@ -62,11 +62,13 @@ d2h(N) when N<10 -> N+$0;
 d2h(N) -> N+$a-10.
 
 decode_rfc822_date(String) when is_list(String) ->
-    case catch decode_rfc822_date_1(string:tokens(String, ", \t\r\n")) of
-        {'EXIT', _} ->
-            {error, invalid_date};
-        Res ->
-            Res
+    try
+        decode_rfc822_date_1(string:tokens(String, ", \t\r\n"))
+    catch
+        throw:Term ->
+            Term;
+        _:_ ->
+            {error, invalid_date}
     end.
 
 % TODO: Have to handle the Zone
@@ -174,15 +176,15 @@ decode_base64(Bin) when is_binary(Bin) ->
     base64:decode(Bin).
 
 get_value(Tag, TVL, DefVal) ->
-    case lists:keysearch(Tag, 1, TVL) of
+    case lists:keyfind(Tag, 1, TVL) of
         false ->
             DefVal;
-        {value, {_, Val}} ->
+        {_, Val} ->
             Val
     end.
 
 get_value(Tag, TVL) ->
-    {value, {_, V}} = lists:keysearch(Tag,1,TVL),
+    {_, V} = lists:keyfind(Tag, 1, TVL),
     V.
 
 parse_url(Url) ->
@@ -422,7 +424,13 @@ log_msg(Fmt, Args) ->
     end.
 
 log_msg(M, F, Fmt, Args) ->
-    catch apply(M, F, [Fmt, Args]).
+    try
+        apply(M, F, [Fmt, Args])
+    catch
+        throw:Term -> Term;
+        exit:Reason -> {'EXIT', Reason};
+        error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+    end.
 
 -ifdef(EUNIT).
 
diff --git a/test/ibrowse_load_test.erl b/test/ibrowse_load_test.erl
index 076c46b..707b75b 100644
--- a/test/ibrowse_load_test.erl
+++ b/test/ibrowse_load_test.erl
@@ -1,7 +1,6 @@
 -module(ibrowse_load_test).
 %%-compile(export_all).
 -export([
-         random_seed/0,
          start/3,
          query_state/0,
          shutdown/0,
@@ -15,20 +14,6 @@
          update_unknown_counter/2
         ]).
 
--ifdef(new_rand).
-
--define(RAND, rand).
-random_seed() ->
-       ok.
-
--else.
-
--define(RAND, random).
-random_seed() ->
-       random:seed(os:timestamp()).
-
--endif.
-
 -define(ibrowse_load_test_counters, ibrowse_load_test_counters).
 
 start(Num_workers, Num_requests, Max_sess) ->
@@ -47,12 +32,16 @@ start_1(Num_workers, Num_requests, Max_sess) ->
     application:start(ibrowse),
     application:set_env(ibrowse, inactivity_timeout, 5000),
     Ulimit = os:cmd("ulimit -n"),
-    case catch list_to_integer(string:strip(Ulimit, right, $\n)) of
+    try list_to_integer(string:strip(Ulimit, right, $\n)) of
         X when is_integer(X), X > 3000 ->
             ok;
         X ->
             io:format("Load test not starting. {insufficient_value_for_ulimit, 
~p}~n", [X]),
             exit({insufficient_value_for_ulimit, X})
+    catch
+        _:X ->
+            io:format("Load test not starting. {insufficient_value_for_ulimit, 
~p}~n", [X]),
+            exit({insufficient_value_for_ulimit, X})
     end,
     ets:new(?ibrowse_load_test_counters, [named_table, public]),
     ets:new(ibrowse_load_timings, [named_table, public]),
@@ -123,12 +112,11 @@ spawn_workers(0, _Num_requests, _Parent, Acc) ->
     lists:reverse(Acc);
 spawn_workers(Num_workers, Num_requests, Parent, Acc) ->
     Pid_ref = spawn_monitor(fun() ->
-                                    random_seed(),
-                                    case catch worker_loop(Parent, 
Num_requests) of
-                                        {'EXIT', Rsn} ->
-                                            io:format("Worker crashed with 
reason: ~p~n", [Rsn]);
-                                        _ ->
-                                            ok
+                                    try worker_loop(Parent, Num_requests) of
+                                        _ -> ok
+                                    catch
+                                        throw:_ -> ok;
+                                        _:Rsn -> io:format("Worker crashed 
with reason: ~p~n", [Rsn])
                                     end
                             end),
     spawn_workers(Num_workers - 1, Num_requests, Parent, [Pid_ref | Acc]).
@@ -163,7 +151,7 @@ wait_for_workers([{Pid, Pid_ref} | T] = Pids) ->
 worker_loop(Parent, 0) ->
     Parent ! {done, self()};
 worker_loop(Parent, N) ->
-    Delay = ?RAND:uniform(100),
+    Delay = rand:uniform(100),
     Url = case Delay rem 10 of
               %% Change 10 to some number between 0-9 depending on how
               %% much chaos you want to introduce into the server
@@ -200,10 +188,12 @@ worker_loop(Parent, N) ->
     worker_loop(Parent, N - 1).
 
 update_unknown_counter(Counter, Inc_val) ->
-    case catch ets:update_counter(?ibrowse_load_test_counters, Counter, 
Inc_val) of
-        {'EXIT', _} ->
+    try ets:update_counter(?ibrowse_load_test_counters, Counter, Inc_val) of
+        _ -> ok
+    catch
+        throw:_ ->
+            ok;
+        _:_ ->
             ets:insert_new(?ibrowse_load_test_counters, {Counter, 0}),
-            update_unknown_counter(Counter, Inc_val);
-        _ ->
-            ok
+            update_unknown_counter(Counter, Inc_val)
     end.
diff --git a/test/ibrowse_test.erl b/test/ibrowse_test.erl
index 9a7b192..5fe5be2 100644
--- a/test/ibrowse_test.erl
+++ b/test/ibrowse_test.erl
@@ -34,14 +34,18 @@
          test_preserve_status_line/0,
          test_binary_headers/0,
          test_binary_headers/1,
+         test_connect_to_overrides_target/0,
+         test_connect_to_unreachable_fails/0,
+         test_connect_to_preserves_host_header/0,
+         test_dead_lb_pid/0,
+         test_chunk_request_body/0,
          test_generate_body_0/0,
          test_retry_of_requests/0,
          test_retry_of_requests/1,
         test_save_to_file_no_content_length/0,
          socks5_noauth/0,
          socks5_auth_succ/0,
-         socks5_auth_fail/0,
-         test_dead_lb_pid/0
+         socks5_auth_fail/0
        ]).
 
 -include_lib("ibrowse/include/ibrowse.hrl").
@@ -62,11 +66,15 @@
                       {local_test_fun, test_303_response_with_a_body, []},
                      {local_test_fun, test_303_response_with_no_body, []},
                       {local_test_fun, test_binary_headers, []},
+                      {local_test_fun, test_connect_to_overrides_target, []},
+                      {local_test_fun, test_connect_to_unreachable_fails, []},
+                      {local_test_fun, test_connect_to_preserves_host_header, 
[]},
+                      {local_test_fun, test_dead_lb_pid, []},
+                      {local_test_fun, test_chunk_request_body, []},
                       {local_test_fun, test_retry_of_requests, []},
                      {local_test_fun, verify_chunked_streaming, []},
                      {local_test_fun, test_chunked_streaming_once, []},
-                     {local_test_fun, test_generate_body_0, []},
-                     {local_test_fun, test_dead_lb_pid, []}
+                     {local_test_fun, test_generate_body_0, []}
                      ]).
 
 -define(TEST_LIST, [{"http://intranet/messenger";, get},
@@ -224,8 +232,20 @@ spawn_workers(Url, NumWorkers, NumReqsPerWorker) ->
 do_wait(Url) ->
     receive
        {'EXIT', _, normal} ->
-            catch ibrowse:show_dest_status(Url),
-            catch ibrowse:show_dest_status(),
+            try
+                ibrowse:show_dest_status(Url)
+            catch
+                throw:Term -> Term;
+                exit:Reason -> {'EXIT', Reason};
+                error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+            end,
+            try
+                ibrowse:show_dest_status()
+            catch
+                throw:_Term -> _Term;
+                exit:_Reason -> {'EXIT', _Reason};
+                error:_Reason:_Stacktrace -> {'EXIT', {_Reason, _Stacktrace}}
+            end,
            do_wait(Url);
        {'EXIT', Pid, Reason} ->
            ets:delete(pid_table, Pid),
@@ -240,8 +260,20 @@ do_wait(Url) ->
                0 ->
                    done;
                _ ->
-                    catch ibrowse:show_dest_status(Url),
-                    catch ibrowse:show_dest_status(),
+                    try
+                        ibrowse:show_dest_status(Url)
+                    catch
+                        throw:Term -> Term;
+                        exit:Reason -> {'EXIT', Reason};
+                        error:Reason:Stacktrace -> {'EXIT', {Reason, 
Stacktrace}}
+                    end,
+                    try
+                        ibrowse:show_dest_status()
+                    catch
+                        throw:_Term -> _Term;
+                        exit:_Reason -> {'EXIT', _Reason};
+                        error:_Reason:_Stacktrace -> {'EXIT', {_Reason, 
_Stacktrace}}
+                    end,
                    do_wait(Url)
            end
     end.
@@ -312,7 +344,13 @@ unit_tests(Options, Test_list) ->
     application:start(asn1),
     application:start(public_key),
     application:start(ssl),
-    (catch ibrowse_test_server:start_server(8181, tcp)),
+    try
+        ibrowse_test_server:start_server(8181, tcp)
+    catch
+        throw:Term -> Term;
+        exit:Reason -> {'EXIT', Reason};
+        error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+    end,
     application:start(ibrowse),
     Options_1 = Options ++ [{connect_timeout, 5000}],
     Test_timeout = proplists:get_value(test_timeout, Options, 60000),
@@ -326,7 +364,13 @@ unit_tests(Options, Test_list) ->
            exit(Pid, kill),
            io:format("Timed out waiting for tests to complete~n", [])
     end,
-    catch ibrowse_test_server:stop_server(8181),
+    try
+        ibrowse_test_server:stop_server(8181)
+    catch
+        throw:_Term -> _Term;
+        exit:_Reason -> {'EXIT', _Reason};
+        error:_Reason:_Stacktrace -> {'EXIT', {_Reason, _Stacktrace}}
+    end,
     error_logger:tty(true),
     ok.
 
@@ -490,12 +534,26 @@ maybe_stream_next(Req_id, Options) ->
 
 execute_req(local_test_fun, Method, Args) ->
     reset_ibrowse(),
-    Result = (catch apply(?MODULE, Method, Args)),
+    Result =
+        try
+            apply(?MODULE, Method, Args)
+        catch
+            throw:Term -> Term;
+            exit:Reason -> {'EXIT', Reason};
+            error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+        end,
     io:format("     ~-54.54w: ", [Method]),
     io:format("~p~n", [Result]);
 execute_req(Url, Method, Options) ->
     io:format("~7.7w, ~50.50s: ", [Method, Url]),
-    Result = (catch ibrowse:send_req(Url, [], Method, [], Options)),
+    Result =
+        try
+            ibrowse:send_req(Url, [], Method, [], Options)
+        catch
+            throw:Term -> Term;
+            exit:Reason -> {'EXIT', Reason};
+            error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+        end,
     case Result of
        {ok, SCode, _H, _B} ->
            io:format("Status code: ~p~n", [SCode]);
@@ -546,6 +604,55 @@ test_binary_headers(Url) ->
             {test_failed, Res}
     end.
 
+%%------------------------------------------------------------------------------
+%% url host is bogus, request only succeeds if connect_to actually
+%% redirects
+%%------------------------------------------------------------------------------
+test_connect_to_overrides_target() ->
+    clear_msg_q(),
+    Url = "http://no.such.host.invalid:8181/";,
+    case ibrowse:send_req(Url, [], get, [], [{connect_to, "localhost"}], 5000) 
of
+        {ok, "200", _, _} ->
+            success;
+        Res ->
+            {test_failed, Res}
+    end.
+
+%%------------------------------------------------------------------------------
+%% url host reachable, but connect_to points at an unroutable
+%% address
+%%------------------------------------------------------------------------------
+test_connect_to_unreachable_fails() ->
+    clear_msg_q(),
+    case ibrowse:send_req("http://localhost:8181/";, [], get, [],
+                          [{connect_to, "192.0.2.1"},
+                           {connect_timeout, 500}],
+                          5000) of
+        {error, _} ->
+            success;
+        Res ->
+            {test_failed, Res}
+    end.
+
+%%------------------------------------------------------------------------------
+%% connect_to shouldn't bleed into the Host header, server should see the
+%% original url host
+%%------------------------------------------------------------------------------
+test_connect_to_preserves_host_header() ->
+    clear_msg_q(),
+    Url = "http://example.invalid:8181/ibrowse_echo_host";,
+    case ibrowse:send_req(Url, [], get, [], [{connect_to, "localhost"}], 5000) 
of
+        {ok, "200", Headers, _} ->
+            case proplists:get_value("x-host", Headers) of
+                "example.invalid:8181" ->
+                    success;
+                V ->
+                    {fail, V}
+            end;
+        Res ->
+            {test_failed, Res}
+    end.
+
 
%%------------------------------------------------------------------------------
 %% Test what happens when the response to a HEAD request is a
 %% Chunked-Encoding response with a non-empty body. Issue #67 on
@@ -690,7 +797,14 @@ test_retry_of_requests(Url, Timeout) ->
     Parent = self(),
     Pids = lists:map(fun(_) ->
                         spawn(fun() ->
-                                 Res = (catch ibrowse:send_req(Url, [], get, 
[], [], Timeout)),
+                                 Res =
+                                     try
+                                         ibrowse:send_req(Url, [], get, [], 
[], Timeout)
+                                     catch
+                                         throw:Term -> Term;
+                                         exit:Reason -> {'EXIT', Reason};
+                                         error:Reason:Stacktrace -> {'EXIT', 
{Reason, Stacktrace}}
+                                     end,
                                  Parent ! {self(), Res}
                               end)
                      end, lists:seq(1,10)),
@@ -879,6 +993,7 @@ test_generate_body_0() ->
         ets:delete(Tid)
     end.
 
+%%------------------------------------------------------------------------------
 %% Test that when an lb process dies, its entry is removed from the ibrowse_lb
 %% table by the next requestor and replaced with a new process
 
%%------------------------------------------------------------------------------
@@ -895,6 +1010,41 @@ test_dead_lb_pid() ->
     true = is_process_alive(NewPid),
     success.
 
+%%------------------------------------------------------------------------------
+%% Test chunk request body encoding. We exported the function from the module
+%% to run it through these tests
+%%------------------------------------------------------------------------------
+
+% Helper
+chunk_body(Body, N) ->
+    ibrowse_http_client:chunk_request_body(Body, N).
+
+test_chunk_request_body() ->
+    Zero = <<"0\r\n\r\n">>,
+    Cases = [
+             {<<Zero/binary>>,                                            
<<>>,               1024},
+             {<<Zero/binary>>,                                            [],  
               1024},
+             {<<"5\r\nhello\r\n", Zero/binary>>,                          
<<"hello">>,        1024},
+             {<<"5\r\nhello\r\n", Zero/binary>>,                          
"hello",            1024},
+             {<<"5\r\nhello\r\n", Zero/binary>>,                          
<<"hello">>,        5},
+             {<<"5\r\nhello\r\n", Zero/binary>>,                          
"hello",            5},
+             {<<"5\r\nhello\r\n5\r\n worl\r\n2\r\nd!\r\n", Zero/binary>>, 
<<"hello world!">>, 5},
+             {<<"5\r\nhello\r\n5\r\n worl\r\n2\r\nd!\r\n", Zero/binary>>, 
"hello world!",     5}
+            ],
+    Failures =
+        [{Body, N, Expect, Got}
+         || {Expect, Body, N} <- Cases,
+            Got <- [iolist_to_binary(chunk_body(Body, N))],
+            Got =/= Expect
+        ],
+    % We expect fun tuples to pass through
+    Fun = fun(_) -> eof end,
+    PassthroughOk = chunk_body(Fun, 1024) =:= Fun andalso chunk_body({Fun, 
foo}, 1024) =:= {Fun, foo},
+    case {Failures, PassthroughOk} of
+        {[], true} -> success;
+        {_, _}     -> {failed, Failures, {passthrough_ok, PassthroughOk}}
+    end.
+
 do_trace(Fmt, Args) ->
     do_trace(get(my_trace_flag), Fmt, Args).
 
diff --git a/test/ibrowse_test_server.erl b/test/ibrowse_test_server.erl
index 631e93a..aa6badf 100644
--- a/test/ibrowse_test_server.erl
+++ b/test/ibrowse_test_server.erl
@@ -11,12 +11,6 @@
          get_conn_pipeline_depth/0
         ]).
 
--ifdef(new_rand).
--define(RAND, rand).
--else.
--define(RAND, random).
--endif.
-
 -record(request, {method, uri, version, headers = [], body = [], state}).
 
 -define(dec2hex(X), erlang:integer_to_list(X, 16)).
@@ -57,7 +51,13 @@ start_server(Port, Sock_type) ->
     ibrowse_socks_server:start(8383, 2). %% Username/Password auth
 
 stop_server(Port) ->
-    catch server_proc_name(Port) ! stop,
+    try
+        server_proc_name(Port) ! stop
+    catch
+        throw:Term -> Term;
+        exit:Reason -> {'EXIT', Reason};
+        error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+    end,
     ibrowse_socks_server:stop(8282),
     ibrowse_socks_server:stop(8383),
     timer:sleep(2000),  % wait for server to receive msg and unregister
@@ -110,12 +110,24 @@ accept_loop(Sock, Sock_type) ->
     end.
 
 connection(Conn, Sock_type) ->
-    catch ets:insert(?CONN_PIPELINE_DEPTH, {self(), 0}),
+    try
+        ets:insert(?CONN_PIPELINE_DEPTH, {self(), 0})
+    catch
+        throw:Term -> Term;
+        exit:Reason -> {'EXIT', Reason};
+        error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+    end,
     try
        inet:setopts(Conn, [{packet, http}, {active, true}]),
         server_loop(Conn, Sock_type, #request{})
     after
-        catch ets:delete(?CONN_PIPELINE_DEPTH, self())
+        try
+            ets:delete(?CONN_PIPELINE_DEPTH, self())
+        catch
+            throw:_Term -> _Term;
+            exit:_Reason -> {'EXIT', _Reason};
+            error:_Reason:_Stacktrace -> {'EXIT', {_Reason, _Stacktrace}}
+        end
     end.
 
 set_controlling_process(Sock, tcp, Pid) ->
@@ -131,7 +143,13 @@ setopts(Sock, ssl, Opts) ->
 server_loop(Sock, Sock_type, #request{headers = Headers} = Req) ->
     receive
         {http, Sock, {http_request, HttpMethod, HttpUri, HttpVersion}} ->
-            catch ets:update_counter(?CONN_PIPELINE_DEPTH, self(), 1),
+            try
+                ets:update_counter(?CONN_PIPELINE_DEPTH, self(), 1)
+            catch
+                throw:Term -> Term;
+                exit:Reason -> {'EXIT', Reason};
+                error:Reason:Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+            end,
             server_loop(Sock, Sock_type, Req#request{method = HttpMethod,
                                                      uri = HttpUri,
                                                      version = HttpVersion});
@@ -146,7 +164,13 @@ server_loop(Sock, Sock_type, #request{headers = Headers} = 
Req) ->
                collect_body ->
                    server_loop(Sock, Sock_type, Req#request{state = 
collect_body});
                 _ ->
-                    catch ets:update_counter(?CONN_PIPELINE_DEPTH, self(), -1)
+                    try
+                        ets:update_counter(?CONN_PIPELINE_DEPTH, self(), -1)
+                    catch
+                        throw:Term -> Term;
+                        exit:Reason -> {'EXIT', Reason};
+                        error:Reason:Stacktrace -> {'EXIT', {Reason, 
Stacktrace}}
+                    end
             end,
             server_loop(Sock, Sock_type, #request{});
         {http, Sock, {http_error, Packet}} when Req#request.state == 
collect_body ->
@@ -235,6 +259,16 @@ process_request(Sock, Sock_type,
        false ->
            collect_body
     end;
+process_request(Sock, Sock_type,
+                #request{method='GET',
+                         headers = Headers,
+                         uri = {abs_path, "/ibrowse_echo_host"}}) ->
+    Host = get_host_header(Headers),
+    Resp = [<<"HTTP/1.1 200 OK\r\n">>,
+            <<"Server: ibrowse_test\r\n">>,
+            "x-host: ", Host, "\r\n",
+            <<"Content-Length: 0\r\n\r\n">>],
+    do_send(Sock, Sock_type, Resp);
 process_request(Sock, Sock_type,
                 #request{method='GET',
                          headers = Headers,
@@ -307,7 +341,7 @@ process_request(Sock, Sock_type, Req) ->
     do_trace("Recvd req: ~p~n", [Req]),
     Resp = <<"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n">>,
     do_send(Sock, Sock_type, Resp),
-    timer:sleep(?RAND:uniform(100)).
+    timer:sleep(rand:uniform(100)).
 
 do_send(Sock, tcp, Resp) ->
     gen_tcp:send(Sock, Resp);
@@ -372,3 +406,10 @@ get_content_length([{http_header, _, _X, _, _Y} | T]) ->
     get_content_length(T);
 get_content_length([]) ->
     undefined.
+
+get_host_header([{http_header, _, 'Host', _, V} | _]) ->
+    V;
+get_host_header([_ | T]) ->
+    get_host_header(T);
+get_host_header([]) ->
+    "not_found".

Reply via email to