Upgrade ibrowse to version 2.1.3

This version fixes several bugs and adds a few minor improvements.
For a list and description of the changes relative to the previous
version, see the README file at:

https://github.com/cmullaparthi/ibrowse



git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@1061340 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/Makefile.am b/Makefile.am
index 4cebe5d..bfd52ba 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -10,7 +10,7 @@
 ## License for the specific language governing permissions and limitations under
 ## the License.
 
-ibrowseebindir = $(localerlanglibdir)/ibrowse-2.1.2/ebin
+ibrowseebindir = $(localerlanglibdir)/ibrowse-2.1.3/ebin
 
 ibrowse_file_collection = \
 	ibrowse.app.in \
diff --git a/ibrowse.app.in b/ibrowse.app.in
index c8e4227..875620d 100644
--- a/ibrowse.app.in
+++ b/ibrowse.app.in
@@ -1,6 +1,6 @@
 {application, ibrowse,
         [{description, "HTTP client application"},
-         {vsn, "2.1.2"},
+         {vsn, "2.1.3"},
          {modules, [ ibrowse, 
 		     ibrowse_http_client, 
 		     ibrowse_app, 
diff --git a/ibrowse.erl b/ibrowse.erl
index e105150..f70f92f 100644
--- a/ibrowse.erl
+++ b/ibrowse.erl
@@ -6,8 +6,8 @@
 %%% Created : 11 Oct 2003 by Chandrashekhar Mullaparthi <chandrashekhar.mullaparthi@t-mobile.co.uk>
 %%%-------------------------------------------------------------------
 %% @author Chandrashekhar Mullaparthi <chandrashekhar dot mullaparthi at gmail dot com>
-%% @copyright 2005-2010 Chandrashekhar Mullaparthi
-%% @version 2.1.2
+%% @copyright 2005-2011 Chandrashekhar Mullaparthi
+%% @version 2.1.3
 %% @doc The ibrowse application implements an HTTP 1.1 client in erlang. This
 %% module implements the API of the HTTP client. There is one named
 %% process called 'ibrowse' which assists in load balancing and maintaining configuration. There is one load balancing process per unique webserver. There is
@@ -683,16 +683,16 @@
     State = #state{},
     put(my_trace_flag, State#state.trace),
     put(ibrowse_trace_token, "ibrowse"),
-    ets:new(ibrowse_lb, [named_table, public, {keypos, 2}]),
-    ets:new(ibrowse_conf, [named_table, protected, {keypos, 2}]),
-    ets:new(ibrowse_stream, [named_table, public]),
+    ibrowse_lb     = ets:new(ibrowse_lb, [named_table, public, {keypos, 2}]),
+    ibrowse_conf   = ets:new(ibrowse_conf, [named_table, protected, {keypos, 2}]),
+    ibrowse_stream = ets:new(ibrowse_stream, [named_table, public]),
     import_config(),
     {ok, #state{}}.
 
 import_config() ->
     case code:priv_dir(ibrowse) of
-        {error, _} = Err ->
-            Err;
+        {error, _} ->
+            ok;
         PrivDir ->
             Filename = filename:join(PrivDir, "ibrowse.conf"),
             import_config(Filename)
@@ -723,8 +723,8 @@
                           io:format("Skipping unrecognised term: ~p~n", [X])
                   end,
             lists:foreach(Fun, Terms);
-        Err ->
-            Err
+        _Err ->
+            ok
     end.
 
 %% @doc Internal export
diff --git a/ibrowse_http_client.erl b/ibrowse_http_client.erl
index 5dce321..7d606e6 100644
--- a/ibrowse_http_client.erl
+++ b/ibrowse_http_client.erl
@@ -188,7 +188,7 @@
                                           cur_req = #request{req_id = Req_id}} = State) ->
     %% io:format("Client process set {active, once}~n", []),
     do_setopts(Socket, [{active, once}], State),
-    {noreply, State};
+    {noreply, set_inac_timer(State)};
 
 handle_info({stream_next, _Req_id}, State) ->
     _Cur_req_id = case State#state.cur_req of
@@ -216,12 +216,14 @@
     handle_sock_closed(State),
     {stop, normal, State};
 
-handle_info({tcp_error, _Sock}, State) ->
-    do_trace("Error on connection to ~1000.p:~1000.p~n", [State#state.host, State#state.port]),
+handle_info({tcp_error, _Sock, Reason}, State) ->
+    do_trace("Error on connection to ~1000.p:~1000.p -> ~1000.p~n",
+             [State#state.host, State#state.port, Reason]),
     handle_sock_closed(State),
     {stop, normal, State};
-handle_info({ssl_error, _Sock}, State) ->
-    do_trace("Error on SSL connection to ~1000.p:~1000.p~n", [State#state.host, State#state.port]),
+handle_info({ssl_error, _Sock, Reason}, State) ->
+    do_trace("Error on SSL connection to ~1000.p:~1000.p -> ~1000.p~n",
+             [State#state.host, State#state.port, Reason]),
     handle_sock_closed(State),
     {stop, normal, State};
 
@@ -334,8 +336,13 @@
                             active_once(State_1)
                     end,
                     State_2 = State_1#state{interim_reply_sent = false},
-                    State_3 = set_inac_timer(State_2),
-                    {noreply, State_3};
+                    case Ccs of
+                    true ->
+                        cancel_timer(State_2#state.inactivity_timer_ref, {eat_message, timeout}),
+                        {noreply, State_2#state{inactivity_timer_ref = undefined}};
+                    _ ->
+                        {noreply, set_inac_timer(State_2)}
+                    end;
                 State_1 ->
                     active_once(State_1),
                     State_2 = set_inac_timer(State_1),
@@ -461,7 +468,7 @@
                        undefined ->
                            Buf;
                        _ ->
-                           file:close(Fd),
+                           ok = file:close(Fd),
                            {file, TmpFilename}
                    end,
             Reply = case get_value(give_raw_headers, Options, false) of
@@ -470,11 +477,11 @@
                         false ->
                             {ok, SC, Headers, Buf}
                     end,
-            do_reply(State, From, StreamTo, ReqId, Resp_format, Reply),
-            do_error_reply(State#state{reqs = Reqs_1}, connection_closed),
-            State;
+            State_1 = do_reply(State, From, StreamTo, ReqId, Resp_format, Reply),
+            ok = do_error_reply(State_1#state{reqs = Reqs_1}, connection_closed),
+            State_1;
         _ ->
-            do_error_reply(State, connection_closed),
+            ok = do_error_reply(State, connection_closed),
             State
     end.
 
@@ -482,17 +489,19 @@
                                        use_proxy   = false,
                                        ssl_options = SSLOptions},
            Timeout) ->
+    ssl:connect(Host, Port, get_sock_options(Options, SSLOptions), Timeout);
+do_connect(Host, Port, Options, _State, Timeout) ->
+    gen_tcp:connect(Host, Port, get_sock_options(Options, []), Timeout).
+
+get_sock_options(Options, SSLOptions) ->
     Caller_socket_options = get_value(socket_options, Options, []),
     Other_sock_options = filter_sock_options(SSLOptions ++ Caller_socket_options),
-    ssl:connect(Host, Port,
-                [binary, {nodelay, true}, {active, false} | Other_sock_options],
-                Timeout);
-do_connect(Host, Port, Options, _State, Timeout) ->
-    Caller_socket_options = get_value(socket_options, Options, []),
-    Other_sock_options = filter_sock_options(Caller_socket_options),
-    gen_tcp:connect(Host, to_integer(Port),
-                    [binary, {nodelay, true}, {active, false} | Other_sock_options],
-                    Timeout).
+    case lists:keysearch(nodelay, 1, Other_sock_options) of
+        false ->
+            [{nodelay, true}, binary, {active, false} | Other_sock_options];
+        {value, _} ->
+            [binary, {active, false} | Other_sock_options]
+    end.
 
 %% We don't want the caller to specify certain options
 filter_sock_options(Opts) ->
@@ -547,7 +556,7 @@
 maybe_chunked_encode(Data, false) ->
     Data;
 maybe_chunked_encode(Data, true) ->
-    [?dec2hex(size(to_binary(Data))), "\r\n", Data, "\r\n"].
+    [?dec2hex(iolist_size(Data)), "\r\n", Data, "\r\n"].
 
 do_close(#state{socket = undefined})            ->  ok;
 do_close(#state{socket = Sock,
@@ -1269,7 +1278,7 @@
                        reply_buffer  = RepBuf,
                        recvd_headers = RespHeaders}=State) when SaveResponseToFile /= false ->
     Body = RepBuf,
-    file:close(Fd),
+    ok = file:close(Fd),
     ResponseBody = case TmpFilename of
                        undefined ->
                            Body;
@@ -1656,8 +1665,8 @@
     {_, Reqs_1} = queue:out(Reqs),
     #request{from=From, stream_to=StreamTo, req_id=ReqId,
              response_format = Resp_format} = CurReq,
-    do_reply(State, From, StreamTo, ReqId, Resp_format, Reply),
-    do_error_reply(State#state{reqs = Reqs_1}, previous_request_failed).
+    State_1 = do_reply(State, From, StreamTo, ReqId, Resp_format, Reply),
+    do_error_reply(State_1#state{reqs = Reqs_1}, previous_request_failed).
 
 split_list_at(List, N) ->
     split_list_at(List, N, []).
@@ -1701,7 +1710,8 @@
 to_ascii($0) -> 0.
 
 cancel_timer(undefined) -> ok;
-cancel_timer(Ref)       -> erlang:cancel_timer(Ref).
+cancel_timer(Ref)       -> _ = erlang:cancel_timer(Ref),
+                           ok.
 
 cancel_timer(Ref, {eat_message, Msg}) ->
     cancel_timer(Ref),
@@ -1814,8 +1824,5 @@
             ok
     end.
 
-to_integer(X) when is_list(X)    -> list_to_integer(X); 
-to_integer(X) when is_integer(X) -> X.
-
 to_binary(X) when is_list(X)   -> list_to_binary(X); 
 to_binary(X) when is_binary(X) -> X.
diff --git a/ibrowse_test.erl b/ibrowse_test.erl
index b8e0a4a..ff3b530 100644
--- a/ibrowse_test.erl
+++ b/ibrowse_test.erl
@@ -11,8 +11,6 @@
 	 unit_tests/0,
 	 unit_tests/1,
 	 unit_tests_1/2,
-	 drv_ue_test/0,
-	 drv_ue_test/1,
 	 ue_test/0,
 	 ue_test/1,
 	 verify_chunked_streaming/0,
@@ -21,7 +19,8 @@
 	 i_do_async_req_list/4,
 	 test_stream_once/3,
 	 test_stream_once/4,
-         test_20122010/0
+         test_20122010/0,
+         test_20122010/1
 	]).
 
 test_stream_once(Url, Method, Options) ->
@@ -413,20 +412,6 @@
 	    io:format("~p~n", [Err])
     end.
 
-drv_ue_test() ->
-    drv_ue_test(lists:duplicate(1024, 127)).
-drv_ue_test(Data) ->
-    [{port, Port}| _] = ets:lookup(ibrowse_table, port),
-%     erl_ddll:unload_driver("ibrowse_drv"),
-%     timer:sleep(1000),
-%     erl_ddll:load_driver("../priv", "ibrowse_drv"),
-%     Port = open_port({spawn, "ibrowse_drv"}, []),
-    {Time, Res} = timer:tc(ibrowse_lib, drv_ue, [Data, Port]),
-    io:format("Time -> ~p~n", [Time]),
-    io:format("Data Length -> ~p~n", [length(Data)]),
-    io:format("Res Length -> ~p~n", [length(Res)]).
-%    io:format("Result -> ~s~n", [Res]).
-
 ue_test() ->
     ue_test(lists:duplicate(1024, $?)).
 ue_test(Data) ->
@@ -445,11 +430,14 @@
 %%------------------------------------------------------------------------------
 
 test_20122010() ->
-    {ok, Pid} = ibrowse:spawn_worker_process("http://localhost:8181"),
+    test_20122010("http://localhost:8181").
+
+test_20122010(Url) ->
+    {ok, Pid} = ibrowse:spawn_worker_process(Url),
     Expected_resp = <<"1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49-50-51-52-53-54-55-56-57-58-59-60-61-62-63-64-65-66-67-68-69-70-71-72-73-74-75-76-77-78-79-80-81-82-83-84-85-86-87-88-89-90-91-92-93-94-95-96-97-98-99-100">>,
     Test_parent = self(),
     Fun = fun() ->
-                  do_test_20122010(Pid, Expected_resp, Test_parent)
+                  do_test_20122010(Url, Pid, Expected_resp, Test_parent)
           end,
     Pids = [erlang:spawn_monitor(Fun) || _ <- lists:seq(1,10)],
     wait_for_workers(Pids).
@@ -458,18 +446,24 @@
     receive
         {Pid, success} ->
             wait_for_workers(Pids)
-    after 5000 ->
+    after 60000 ->
             test_failed
     end;
 wait_for_workers([]) ->
     success.
 
-do_test_20122010(Pid, Expected_resp, Test_parent) ->
+do_test_20122010(Url, Pid, Expected_resp, Test_parent) ->
+    do_test_20122010(10, Url, Pid, Expected_resp, Test_parent).
+
+do_test_20122010(0, _Url, _Pid, _Expected_resp, Test_parent) ->
+    Test_parent ! {self(), success};
+do_test_20122010(Rem_count, Url, Pid, Expected_resp, Test_parent) ->
     {ibrowse_req_id, Req_id} = ibrowse:send_req_direct(
                                  Pid,
-                                 "http://localhost:8181/ibrowse_stream_once_chunk_pipeline_test",
+                                 Url ++ "/ibrowse_stream_once_chunk_pipeline_test",
                                  [], get, [],
                                  [{stream_to, {self(), once}},
+                                  {inactivity_timeout, 10000},
                                   {include_ibrowse_req_id, true}]),
     do_trace("~p -- sent request ~1000.p~n", [self(), Req_id]),
     Req_id_str = lists:flatten(io_lib:format("~1000.p",[Req_id])),
@@ -491,7 +485,7 @@
     ok = ibrowse:stream_next(Req_id),
     case do_test_20122010_1(Expected_resp, Req_id, []) of
         true ->
-            Test_parent ! {self(), success};
+            do_test_20122010(Rem_count - 1, Url, Pid, Expected_resp, Test_parent);
         false ->
             Test_parent ! {self(), failed}
     end.