diff options
Diffstat (limited to 'src/ibrowse')
-rw-r--r-- | src/ibrowse/Makefile.am | 2 | ||||
-rw-r--r-- | src/ibrowse/ibrowse.erl | 41 | ||||
-rw-r--r-- | src/ibrowse/ibrowse_http_client.erl | 23 | ||||
-rw-r--r-- | src/ibrowse/ibrowse_lb.erl | 38 | ||||
-rw-r--r-- | src/ibrowse/ibrowse_test.erl | 4 |
5 files changed, 92 insertions, 16 deletions
diff --git a/src/ibrowse/Makefile.am b/src/ibrowse/Makefile.am index 02a3e6e0..76262a6e 100644 --- a/src/ibrowse/Makefile.am +++ b/src/ibrowse/Makefile.am @@ -10,7 +10,7 @@ ## License for the specific language governing permissions and limitations under ## the License. -ibrowseebindir = $(localerlanglibdir)/ibrowse-1.4.1/ebin +ibrowseebindir = $(localerlanglibdir)/ibrowse-1.5.2/ebin ibrowse_file_collection = \ ibrowse.erl \ diff --git a/src/ibrowse/ibrowse.erl b/src/ibrowse/ibrowse.erl index 81fc74df..1913ef59 100644 --- a/src/ibrowse/ibrowse.erl +++ b/src/ibrowse/ibrowse.erl @@ -7,7 +7,7 @@ %%%------------------------------------------------------------------- %% @author Chandrashekhar Mullaparthi <chandrashekhar dot mullaparthi at gmail dot com> %% @copyright 2005-2009 Chandrashekhar Mullaparthi -%% @version 1.5.1 +%% @version 1.5.2 %% @doc The ibrowse application implements an HTTP 1.1 client. 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 @@ -98,6 +98,7 @@ trace_on/2, trace_off/2, all_trace_off/0, + show_dest_status/0, show_dest_status/2 ]). @@ -480,6 +481,44 @@ all_trace_off() -> ibrowse ! all_trace_off, ok. +show_dest_status() -> + Dests = lists:filter(fun({lb_pid, {Host, Port}, _}) when is_list(Host), + is_integer(Port) -> + true; + (_) -> + false + end, ets:tab2list(ibrowse_lb)), + All_ets = ets:all(), + io:format("~-40.40s | ~-5.5s | ~-10.10s | ~s~n", + ["Server:port", "ETS", "Num conns", "LB Pid"]), + io:format("~80.80.=s~n", [""]), + lists:foreach(fun({lb_pid, {Host, Port}, Lb_pid}) -> + case lists:dropwhile( + fun(Tid) -> + ets:info(Tid, owner) /= Lb_pid + end, All_ets) of + [] -> + io:format("~40.40s | ~-5.5s | ~-5.5s | ~s~n", + [Host ++ ":" ++ integer_to_list(Port), + "", + "", + io_lib:format("~p", [Lb_pid])] + ); + [Tid | _] -> + catch ( + begin + Size = ets:info(Tid, size), + io:format("~40.40s | ~-5.5s | ~-5.5s | ~s~n", + [Host ++ ":" ++ integer_to_list(Port), + integer_to_list(Tid), + integer_to_list(Size), + io_lib:format("~p", [Lb_pid])] + ) + end + ) + end + end, Dests). + %% @doc Shows some internal information about load balancing to a %% specified Host:Port. Info about workers spawned using %% spawn_worker_process/2 or spawn_link_worker_process/2 is not diff --git a/src/ibrowse/ibrowse_http_client.erl b/src/ibrowse/ibrowse_http_client.erl index 013f31b6..dde258ef 100644 --- a/src/ibrowse/ibrowse_http_client.erl +++ b/src/ibrowse/ibrowse_http_client.erl @@ -137,7 +137,7 @@ handle_call({send_req, {Url, Headers, Method, Body, Options, Timeout}}, handle_call(stop, _From, State) -> do_close(State), do_error_reply(State, closing_on_request), - {stop, normal, State}; + {stop, normal, ok, State}; handle_call(Request, _From, State) -> Reply = {unknown_request, Request}, @@ -184,6 +184,15 @@ handle_info({ssl_closed, _Sock}, State) -> handle_sock_closed(State), {stop, normal, State}; +handle_info({tcp_error, _Sock}, State) -> + io:format("Error on connection to ~1000.p:~1000.p~n", [State#state.host, State#state.port]), + handle_sock_closed(State), + {stop, normal, State}; +handle_info({ssl_error, _Sock}, State) -> + io:format("Error on SSL connection to ~1000.p:~1000.p~n", [State#state.host, State#state.port]), + handle_sock_closed(State), + {stop, normal, State}; + handle_info({req_timedout, From}, State) -> case lists:keysearch(From, #request.from, queue:to_list(State#state.reqs)) of false -> @@ -204,6 +213,8 @@ handle_info({trace, Bool}, State) -> {noreply, State}; handle_info(Info, State) -> + io:format("Unknown message recvd for ~1000.p:~1000.p -> ~p~n", + [State#state.host, State#state.port, Info]), io:format("Recvd unknown message ~p when in state: ~p~n", [Info, State]), {noreply, State}. @@ -869,8 +880,8 @@ is_connection_closing(_, _) -> false. %% This clause determines the chunk size when given data from the beginning of the chunk parse_11_response(DataRecvd, - #state{transfer_encoding=chunked, - chunk_size=chunk_start, + #state{transfer_encoding = chunked, + chunk_size = chunk_start, chunk_size_buffer = Chunk_sz_buf } = State) -> case scan_crlf(Chunk_sz_buf, DataRecvd) of @@ -906,15 +917,15 @@ parse_11_response(DataRecvd, {yes, _, NextChunk} -> State_1 = State#state{chunk_size = chunk_start, chunk_size_buffer = <<>>, -%% reply_buffer = Buf_1, deleted_crlf = true}, parse_11_response(NextChunk, State_1); {no, Data_1} -> -%% State#state{reply_buffer = Data_1, rep_buf_size = size(Data_1)} State#state{chunk_size_buffer = Data_1} end; -%% This clause deals with the end of a chunked transfer +%% This clause deals with the end of a chunked transfer. ibrowse does +%% not support Trailers in the Chunked Transfer encoding. Any trailer +%% received is silently discarded. parse_11_response(DataRecvd, #state{transfer_encoding = chunked, chunk_size = 0, cur_req = CurReq, diff --git a/src/ibrowse/ibrowse_lb.erl b/src/ibrowse/ibrowse_lb.erl index 9c2165b0..834054a7 100644 --- a/src/ibrowse/ibrowse_lb.erl +++ b/src/ibrowse/ibrowse_lb.erl @@ -108,18 +108,19 @@ spawn_connection(Lb_pid, Url, %% Update max_sessions in #state with supplied value handle_call({spawn_connection, _Url, Max_sess, Max_pipe, _}, _From, - #state{ets_tid = Tid, - num_cur_sessions = Num} = State) + #state{num_cur_sessions = Num} = State) when Num >= Max_sess -> - Reply = find_best_connection(Tid, Max_pipe), - {reply, Reply, State#state{max_sessions = 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}}; handle_call({spawn_connection, Url, _Max_sess, _Max_pipe, SSL_options}, _From, - #state{num_cur_sessions = Cur, - ets_tid = Tid} = State) -> + #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}), ets:insert(Tid, {{1, Pid}, []}), - {reply, {ok, Pid}, State#state{num_cur_sessions = Cur + 1}}; + {reply, {ok, Pid}, State_1#state{num_cur_sessions = Cur + 1}}; handle_call(Request, _From, State) -> Reply = {unknown_request, Request}, @@ -145,11 +146,26 @@ handle_cast(_Msg, State) -> handle_info({'EXIT', Parent, _Reason}, #state{parent_pid = Parent} = State) -> {stop, normal, State}; +handle_info({'EXIT', _Pid, _Reason}, #state{ets_tid = undefined} = State) -> + {noreply, State}; + handle_info({'EXIT', Pid, _Reason}, #state{num_cur_sessions = Cur, ets_tid = Tid} = State) -> ets:match_delete(Tid, {{'_', Pid}, '_'}), - {noreply, State#state{num_cur_sessions = Cur - 1}}; + Cur_1 = Cur - 1, + State_1 = case Cur_1 of + 0 -> + ets:delete(Tid), + State#state{ets_tid = undefined}; + _ -> + State + end, + {noreply, State_1#state{num_cur_sessions = Cur_1}}; + +handle_info({trace, Bool}, #state{ets_tid = undefined} = State) -> + put(my_trace_flag, Bool), + {noreply, State}; handle_info({trace, Bool}, #state{ets_tid = Tid} = State) -> ets:foldl(fun({{_, Pid}, _}, Acc) when is_pid(Pid) -> @@ -192,3 +208,9 @@ find_best_connection(Tid, Max_pipe) -> _ -> {error, retry_later} end. + +maybe_create_ets(#state{ets_tid = undefined} = State) -> + Tid = ets:new(ibrowse_lb, [public, ordered_set]), + State#state{ets_tid = Tid}; +maybe_create_ets(State) -> + State. diff --git a/src/ibrowse/ibrowse_test.erl b/src/ibrowse/ibrowse_test.erl index cab1f882..3dc66ecf 100644 --- a/src/ibrowse/ibrowse_test.erl +++ b/src/ibrowse/ibrowse_test.erl @@ -231,6 +231,7 @@ unit_tests(Options) -> {'DOWN', Ref, _, _, Info} -> io:format("Test process crashed: ~p~n", [Info]) after 60000 -> + exit(Pid, kill), io:format("Timed out waiting for tests to complete~n", []) end. @@ -301,6 +302,9 @@ wait_for_resp(Pid) -> receive {async_result, Pid, Res} -> Res; + {async_result, Other_pid, _} -> + io:format("~p: Waiting for result from ~p: got from ~p~n", [self(), Pid, Other_pid]), + wait_for_resp(Pid); {'DOWN', _, _, Pid, Reason} -> {'EXIT', Reason}; {'DOWN', _, _, _, _} -> |