Commits

Oscar Hellström committed b57682c Merge

Merged with 1.2 branch

Comments (0)

Files changed (5)

 0000000000000000000000000000000000000000 1.2.1
 6d41a8a076413c441fd752cd889dad4e9872bcf7 1.2.1
 0aa6509343cce7e39d14573a10ef81a88d2fa69b 1.2.2
+82c315b53a5dce40df76d28244cdb678084fbb1b 1.2.3
       after completing requests which came from the lhttpc_client process.
       These are now avoided.
 
+Version 1.2.3:
+* Fix handling of unexpected 100 Continue response (patch by Magnus Henoch)
+ 
 Version 1.2.2:
 * Fix Host header, add port number (reported by Benoit Chesneau)
 

src/lhttpc_client.erl

 
 read_response(#client_state{socket = Socket, ssl = Ssl} = State) ->
     lhttpc_sock:setopts(Socket, [{packet, http}], Ssl),
-    read_response(State, nil, nil, []).
+    read_response(State, nil, {nil, nil}, []).
 
-read_response(State, Vsn, Status, Hdrs) ->
+read_response(State, Vsn, {StatusCode, _} = Status, Hdrs) ->
     Socket = State#client_state.socket,
     Ssl = State#client_state.ssl,
     case lhttpc_sock:recv(Socket, Ssl) of
-        {ok, {http_response, NewVsn, StatusCode, Reason}} ->
-            NewStatus = {StatusCode, Reason},
+        {ok, {http_response, NewVsn, NewStatusCode, Reason}} ->
+            NewStatus = {NewStatusCode, Reason},
             read_response(State, NewVsn, NewStatus, Hdrs);
         {ok, {http_header, _, Name, _, Value}} ->
             Header = {lhttpc_lib:maybe_atom_to_list(Name), Value},
             read_response(State, Vsn, Status, [Header | Hdrs]);
+        {ok, http_eoh} when StatusCode >= 100, StatusCode =< 199 ->
+            % RFC 2616, section 10.1:
+            % A client MUST be prepared to accept one or more
+            % 1xx status responses prior to a regular
+            % response, even if the client does not expect a
+            % 100 (Continue) status message. Unexpected 1xx
+            % status responses MAY be ignored by a user agent.
+            read_response(State, nil, {nil, nil}, []);
         {ok, http_eoh} ->
             lhttpc_sock:setopts(Socket, [{packet, raw}], Ssl),
             Response = handle_response_body(State, Vsn, Status, Hdrs),

test/lhttpc_tests.erl

                 ?_test(pre_1_1_server_keep_alive()),
                 ?_test(simple_put()),
                 ?_test(post()),
+                ?_test(post_100_continue()),
                 ?_test(bad_url()),
                 ?_test(persistent_connection()),
                 ?_test(request_timeout()),
     ?assertEqual("OK", ReasonPhrase),
     ?assertEqual(iolist_to_binary(Body), body(Response)).
 
+post_100_continue() ->
+    Port = start(gen_tcp, [fun copy_body_100_continue/5]),
+    URL = url(Port, "/post"),
+    {X, Y, Z} = now(),
+    Body = [
+        "This is a rather simple post :)",
+        integer_to_list(X),
+        integer_to_list(Y),
+        integer_to_list(Z)
+    ],
+    {ok, Response} = lhttpc:request(URL, "POST", [], Body, 1000),
+    {StatusCode, ReasonPhrase} = status(Response),
+    ?assertEqual(200, StatusCode),
+    ?assertEqual("OK", ReasonPhrase),
+    ?assertEqual(iolist_to_binary(Body), body(Response)).
+
 bad_url() ->
     ?assertError(_, lhttpc:request(ost, "GET", [], 100)).
 
         ]
     ).
 
+copy_body_100_continue(Module, Socket, _, _, Body) ->
+    Module:send(
+        Socket,
+        [
+            "HTTP/1.1 100 Continue\r\n\r\n"
+            "HTTP/1.1 200 OK\r\n"
+            "Content-type: text/plain\r\nContent-length: "
+            ++ integer_to_list(size(Body)) ++ "\r\n\r\n",
+            Body
+        ]
+    ).
+
 respond_and_close(Module, Socket, _, _, Body) ->
     Pid = list_to_pid(binary_to_list(Body)),
     Module:send(
-VSN=1.2.2
+VSN=1.2.3