From eafca21198b08dfa356cb9b1ec87f80375a2af23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Tue, 12 Dec 2017 11:37:48 +0100 Subject: Fix HTTP/1.1 pipelining Cases where a request body was involved could sometimes fail depending on timing. Also fix all of the old http_SUITE tests. --- src/cowboy_http.erl | 11 +++++++---- test/http_SUITE.erl | 14 ++++++++++---- test/http_SUITE_data/rest_param_all.erl | 5 +++-- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl index 2301abb..9fc098d 100644 --- a/src/cowboy_http.erl +++ b/src/cowboy_http.erl @@ -1051,8 +1051,9 @@ stream_reset(State, StreamID, StreamError={internal_error, _, _}) -> % stream_terminate(State#state{out_state=done}, StreamID, StreamError). stream_terminate(State, StreamID, StreamError). -stream_terminate(State0=#state{opts=Opts, in_state=InState, out_streamid=OutStreamID, - out_state=OutState, streams=Streams0, children=Children0}, StreamID, Reason) -> +stream_terminate(State0=#state{opts=Opts, in_streamid=InStreamID, in_state=InState, + out_streamid=OutStreamID, out_state=OutState, streams=Streams0, + children=Children0}, StreamID, Reason) -> #stream{version=Version} = lists:keyfind(StreamID, #stream.id, Streams0), State1 = #state{streams=Streams1} = case OutState of wait when element(1, Reason) =:= internal_error -> @@ -1084,9 +1085,11 @@ stream_terminate(State0=#state{opts=Opts, in_state=InState, out_streamid=OutStre %% @todo Only do this if Current =:= StreamID. MaxSkipBodyLength = maps:get(max_skip_body_length, Opts, 1000000), case InState of - #ps_body{length=undefined} -> + #ps_body{length=undefined} + when InStreamID =:= OutStreamID -> terminate(State#state{streams=Streams, children=Children}, skip_body_unknown_length); - #ps_body{length=Len, received=Received} when Received + MaxSkipBodyLength < Len -> + #ps_body{length=Len, received=Received} + when InStreamID =:= OutStreamID, Received + MaxSkipBodyLength < Len -> terminate(State#state{streams=Streams, children=Children}, skip_body_too_large); _ -> %% Move on to the next stream. diff --git a/test/http_SUITE.erl b/test/http_SUITE.erl index 203378c..52ef86b 100644 --- a/test/http_SUITE.erl +++ b/test/http_SUITE.erl @@ -464,9 +464,15 @@ rest_keepalive(Config) -> rest_keepalive_post(Config) -> ConnPid = gun_open(Config), Refs = [begin - Ref1 = gun:post(ConnPid, "/forbidden_post", [{<<"content-type">>, <<"text/plain">>}]), + Ref1 = gun:post(ConnPid, "/forbidden_post", [ + {<<"content-type">>, <<"text/plain">>}, + {<<"content-length">>, <<"12">>} + ]), gun:data(ConnPid, Ref1, fin, "Hello world!"), - Ref2 = gun:post(ConnPid, "/simple_post", [{<<"content-type">>, <<"text/plain">>}]), + Ref2 = gun:post(ConnPid, "/simple_post", [ + {<<"content-type">>, <<"text/plain">>}, + {<<"content-length">>, <<"12">>} + ]), gun:data(ConnPid, Ref2, fin, "Hello world!"), {Ref1, Ref2} end || _ <- lists:seq(1, 5)], @@ -550,8 +556,8 @@ rest_resource_etags(Config) -> {200, <<"\"etag-header-value\"">>, "tuple-strong"}, {200, <<"W/\"etag-header-value\"">>, "binary-weak-quoted"}, {200, <<"\"etag-header-value\"">>, "binary-strong-quoted"}, - {400, false, "binary-strong-unquoted"}, - {400, false, "binary-weak-unquoted"} + {500, false, "binary-strong-unquoted"}, + {500, false, "binary-weak-unquoted"} ], _ = [{Status, ETag, Type} = begin {Ret, RespETag} = rest_resource_get_etag(Config, Type), diff --git a/test/http_SUITE_data/rest_param_all.erl b/test/http_SUITE_data/rest_param_all.erl index d74df74..784214b 100644 --- a/test/http_SUITE_data/rest_param_all.erl +++ b/test/http_SUITE_data/rest_param_all.erl @@ -17,7 +17,7 @@ content_types_provided(Req, State) -> {[{{<<"text">>, <<"plain">>, '*'}, get_text_plain}], Req, State}. get_text_plain(Req, State) -> - {_, _, Param} = maps:get(media_type, Req, {{<<"text">>, <<"plain">>}, []}), + {_, _, Param} = maps:get(media_type, Req, {<<"text">>, <<"plain">>, []}), Body = if Param == '*' -> <<"'*'">>; @@ -31,5 +31,6 @@ get_text_plain(Req, State) -> content_types_accepted(Req, State) -> {[{{<<"text">>, <<"plain">>, '*'}, put_text_plain}], Req, State}. -put_text_plain(Req, State) -> +put_text_plain(Req0, State) -> + {ok, _, Req} = cowboy_req:read_body(Req0), {true, Req, State}. -- cgit v1.2.3