From 26ce366296ccd02fdc3f4a3317f068dedd04c131 Mon Sep 17 00:00:00 2001 From: Stuart Coyle Date: Mon, 15 Jul 2013 18:33:44 +1000 Subject: [PATCH] allow_303_with_no_body option allows 303 responses to have no body --- src/ibrowse_http_client.erl | 22 +++++++++++++++++-- test/ibrowse_test.erl | 41 ++++++++++++++++++++++++++++++++++-- test/ibrowse_test_server.erl | 12 +++++++++++ 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/src/ibrowse_http_client.erl b/src/ibrowse_http_client.erl index 5d457d2..1f0f4ff 100644 --- a/src/ibrowse_http_client.erl +++ b/src/ibrowse_http_client.erl @@ -1091,8 +1091,7 @@ parse_response(Data, #state{reply_buffer = Acc, reqs = Reqs, parse_response(Data_1, State_1#state{recvd_headers = [], status = get_header}); _ when StatCode =:= "204"; - StatCode =:= "304"; - StatCode =:= "303" -> + StatCode =:= "304" -> %% No message body is expected for these Status Codes. %% RFC2616 - Sec 4.4 {_, Reqs_1} = queue:out(Reqs), @@ -1121,6 +1120,25 @@ parse_response(Data, #state{reply_buffer = Acc, reqs = Reqs, ConnClose =:= "close" -> send_async_headers(ReqId, StreamTo, Give_raw_headers, State_1), State_1#state{reply_buffer = Data_1}; + undefined when StatCode =:= "303" -> + %% Some servers send 303 requests without a body. + %% RFC2616 says that they SHOULD, but they dont. + case ibrowse:get_config_value(allow_303_with_no_body, false) of + false -> + fail_pipelined_requests(State_1, + {error, {content_length_undefined, + {stat_code, StatCode}, Headers}}), + {error, content_length_undefined}; + true -> + {_, Reqs_1} = queue:out(Reqs), + send_async_headers(ReqId, StreamTo, Give_raw_headers, State_1), + State_1_1 = do_reply(State_1, From, StreamTo, ReqId, Resp_format, + {ok, StatCode, Headers_1, []}), + cancel_timer(T_ref, {eat_message, {req_timedout, From}}), + State_2 = reset_state(State_1_1), + State_3 = set_cur_request(State_2#state{reqs = Reqs_1}), + parse_response(Data_1, State_3) + end; undefined -> fail_pipelined_requests(State_1, {error, {content_length_undefined, diff --git a/test/ibrowse_test.erl b/test/ibrowse_test.erl index d97f76c..de7b4d5 100644 --- a/test/ibrowse_test.erl +++ b/test/ibrowse_test.erl @@ -27,7 +27,11 @@ test_head_transfer_encoding/0, test_head_transfer_encoding/1, test_head_response_with_body/0, - test_head_response_with_body/1 + test_head_response_with_body/1, + test_303_response_with_no_body/0, + test_303_response_with_no_body/1, + test_303_response_with_a_body/0, + test_303_response_with_a_body/1 ]). test_stream_once(Url, Method, Options) -> @@ -233,7 +237,9 @@ dump_errors(Key, Iod) -> {local_test_fun, test_20122010, []}, {local_test_fun, test_pipeline_head_timeout, []}, {local_test_fun, test_head_transfer_encoding, []}, - {local_test_fun, test_head_response_with_body, []} + {local_test_fun, test_head_response_with_body, []}, + {local_test_fun, test_303_response_with_a_body, []} + ]). unit_tests() -> @@ -476,6 +482,37 @@ test_head_response_with_body(Url) -> {test_failed, Res} end. +%%------------------------------------------------------------------------------ +%% Test what happens when a 303 response has no body +%% Github issue #97 +%% ------------------------------------------------------------------------------ +test_303_response_with_no_body() -> + clear_msg_q(), + test_303_response_with_no_body("http://localhost:8181/ibrowse_303_no_body_test"). + +test_303_response_with_no_body(Url) -> + ibrowse:add_config([{allow_303_with_no_body, true}]), + case ibrowse:send_req(Url, [], post) of + {ok, "303", _, _} -> + success; + Res -> + {test_failed, Res} + end. + +%% Make sure we don't break requests that do have a body. +test_303_response_with_a_body() -> + clear_msg_q(), + test_303_response_with_no_body("http://localhost:8181/ibrowse_303_with_body_test"). + +test_303_response_with_a_body(Url) -> + ibrowse:add_config([{allow_303_with_no_body, true}]), + case ibrowse:send_req(Url, [], post) of + {ok, "303", _, "abcde"} -> + 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 75d1b44..d3bfabc 100644 --- a/test/ibrowse_test_server.erl +++ b/test/ibrowse_test_server.erl @@ -159,6 +159,18 @@ process_request(Sock, Sock_type, 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, + #request{method='POST', + headers = _Headers, + uri = {abs_path, "/ibrowse_303_no_body_test"}}) -> + Resp = <<"HTTP/1.1 303 See Other\r\nLocation: http://example.org\r\n">>, + do_send(Sock, Sock_type, Resp); +process_request(Sock, Sock_type, + #request{method='POST', + headers = _Headers, + uri = {abs_path, "/ibrowse_303_with_body_test"}}) -> + Resp = <<"HTTP/1.1 303 See Other\r\nLocation: http://example.org\r\nContent-Length: 5\r\n\r\nabcde">>, + 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">>,