From 52ce596b91bf3e857808277fe684f05618cf53b8 Mon Sep 17 00:00:00 2001 From: Chandrashekhar Mullaparthi Date: Fri, 3 Aug 2012 06:31:57 +0100 Subject: [PATCH] Bug fix for issue #67 --- CHANGELOG | 6 ++++++ CONTRIBUTORS | 1 + README.md | 2 +- src/ibrowse.app.src | 2 +- src/ibrowse.erl | 3 ++- src/ibrowse_http_client.erl | 14 ++++++++++++-- src/ibrowse_test.erl | 27 ++++++++++++++++++++++++--- test/ibrowse_test_server.erl | 6 ++++++ 8 files changed, 53 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 3aff4ac..e635efc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,11 @@ CONTRIBUTIONS & CHANGE HISTORY ============================== +03-08-2012 - v4.0.0 + * Fixed a regression in handling HEAD. + https://github.com/cmullaparthi/ibrowse/issues/67 + + * Fixed a bug in handling SSL requests through a proxy + 06-04-2012 - v3.0.4 * Fix for the following issue https://github.com/cmullaparthi/ibrowse/issues/67 diff --git a/CONTRIBUTORS b/CONTRIBUTORS index d84318e..d38c240 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -24,6 +24,7 @@ Karol Skocik Konstantin Nikiforov Kostis Sagonas Matthew Reilly +Michael Terry Oscar Hellstr?m Paul J. Davis Peter Kristensen diff --git a/README.md b/README.md index 206cd2b..8d0b764 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ibrowse is a HTTP client written in erlang. **Comments to:** chandrashekhar.mullaparthi@gmail.com -**Current Version:** 3.0.4 +**Current Version:** 4.0.0 **Latest Version:** git://github.com/cmullaparthi/ibrowse.git diff --git a/src/ibrowse.app.src b/src/ibrowse.app.src index b793dd6..6a4aef8 100644 --- a/src/ibrowse.app.src +++ b/src/ibrowse.app.src @@ -1,6 +1,6 @@ {application, ibrowse, [{description, "Erlang HTTP client application"}, - {vsn, "3.0.4"}, + {vsn, "4.0.0"}, {modules, [ ibrowse, ibrowse_http_client, ibrowse_app, diff --git a/src/ibrowse.erl b/src/ibrowse.erl index bda0de1..80a4282 100644 --- a/src/ibrowse.erl +++ b/src/ibrowse.erl @@ -285,7 +285,8 @@ send_req(Url, Headers, Method, Body) -> %% {transfer_encoding, {chunked, ChunkSize}} | %% {headers_as_is, boolean()} | %% {give_raw_headers, boolean()} | -%% {preserve_chunked_encoding,boolean()} +%% {preserve_chunked_encoding,boolean()} | +%% {workaround, head_response_with_body} %% %% stream_to() = process() | {process(), once} %% process() = pid() | atom() diff --git a/src/ibrowse_http_client.erl b/src/ibrowse_http_client.erl index 32f08c0..d879b74 100644 --- a/src/ibrowse_http_client.erl +++ b/src/ibrowse_http_client.erl @@ -1034,6 +1034,7 @@ parse_response(Data, #state{reply_buffer = Acc, reqs = Reqs, end, put(conn_close, ConnClose), TransferEncoding = to_lower(get_value("transfer-encoding", LCHeaders, "false")), + Head_response_with_body = lists:member({workaround, head_response_with_body}, Options), case get_value("content-length", LCHeaders, undefined) of _ when Method == connect, hd(StatCode) == $2 -> @@ -1048,8 +1049,8 @@ parse_response(Data, #state{reply_buffer = Acc, reqs = Reqs, do_error_reply(State#state{reqs = Reqs_1}, {error, proxy_tunnel_failed}), {error, proxy_tunnel_failed}; - _ when Method == head, - TransferEncoding =/= "chunked" -> + _ when Method =:= head, + Head_response_with_body =:= true -> %% This is not supposed to happen, but it does. An %% Apache server was observed to send an "empty" %% body, but in a Chunked-Transfer-Encoding way, @@ -1063,6 +1064,15 @@ 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 Method =:= head -> + {_, 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); _ when hd(StatCode) =:= $1 -> %% No message body is expected. Server may send %% one or more 1XX responses before a proper diff --git a/src/ibrowse_test.erl b/src/ibrowse_test.erl index 6353f1a..d97f76c 100644 --- a/src/ibrowse_test.erl +++ b/src/ibrowse_test.erl @@ -25,7 +25,9 @@ test_pipeline_head_timeout/1, do_test_pipeline_head_timeout/4, test_head_transfer_encoding/0, - test_head_transfer_encoding/1 + test_head_transfer_encoding/1, + test_head_response_with_body/0, + test_head_response_with_body/1 ]). test_stream_once(Url, Method, Options) -> @@ -230,7 +232,8 @@ dump_errors(Key, Iod) -> {"https://github.com", get, [{ssl_options, [{depth, 2}]}]}, {local_test_fun, test_20122010, []}, {local_test_fun, test_pipeline_head_timeout, []}, - {local_test_fun, test_head_transfer_encoding, []} + {local_test_fun, test_head_transfer_encoding, []}, + {local_test_fun, test_head_response_with_body, []} ]). unit_tests() -> @@ -446,15 +449,33 @@ log_msg(Fmt, Args) -> %% ------------------------------------------------------------------------------ test_head_transfer_encoding() -> clear_msg_q(), - test_head_transfer_encoding("http://localhost:8181/ibrowse_head_transfer_enc"). + test_head_transfer_encoding("http://localhost:8181/ibrowse_head_test"). test_head_transfer_encoding(Url) -> case ibrowse:send_req(Url, [], head) of + {ok, "200", _, _} -> + success; + 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 +%% Github +%% ------------------------------------------------------------------------------ +test_head_response_with_body() -> + clear_msg_q(), + test_head_response_with_body("http://localhost:8181/ibrowse_head_transfer_enc"). + +test_head_response_with_body(Url) -> + case ibrowse:send_req(Url, [], head, [], [{workaround, head_response_with_body}]) of {ok, "400", _, _} -> success; Res -> {test_failed, Res} end. + %%------------------------------------------------------------------------------ %% Test what happens when the request at the head of a pipeline times out %%------------------------------------------------------------------------------ diff --git a/test/ibrowse_test_server.erl b/test/ibrowse_test_server.erl index 562e908..1cc0280 100644 --- a/test/ibrowse_test_server.erl +++ b/test/ibrowse_test_server.erl @@ -153,6 +153,12 @@ process_request(Sock, Sock_type, uri = {abs_path, "/ibrowse_head_transfer_enc"}}) -> Resp = <<"HTTP/1.1 400 Bad Request\r\nServer: Apache-Coyote/1.1\r\nTransfer-Encoding: chunked\r\nDate: Wed, 04 Apr 2012 16:53:49 GMT\r\nConnection: close\r\n\r\n0\r\n\r\n">>, do_send(Sock, Sock_type, Resp); +process_request(Sock, Sock_type, + #request{method='HEAD', + headers = _Headers, + uri = {abs_path, "/ibrowse_head_test"}}) -> + Resp = <<"HTTP/1.1 200 OK\r\nServer: Apache-Coyote/1.1\r\nTransfer-Encoding: chunked\r\nDate: Wed, 04 Apr 2012 16:53:49 GMT\r\nConnection: close\r\n\r\n">>, + do_send(Sock, Sock_type, Resp); 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">>,