diff --git a/.editorconfig b/.editorconfig index d03550ed..0a7aa67a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,3 +15,4 @@ insert_final_newline = true [*.{erl,src,hrl}] indent_style = space indent_size = 4 +tab_width = 8 diff --git a/CHANGES.md b/CHANGES.md index 728541eb..b14ceec7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,4 +1,4 @@ -Version 3.1.1 released 2022-XX-XX +Version 3.1.1 released 2022-10-11 * OTP 25 added to test matrix https://github.com/mochi/mochiweb/pull/251 diff --git a/src/mochiweb.app.src b/src/mochiweb.app.src index 425e2206..a130893c 100644 --- a/src/mochiweb.app.src +++ b/src/mochiweb.app.src @@ -1,7 +1,7 @@ %% This is generated from src/mochiweb.app.src {application, mochiweb, [{description, "MochiMedia Web Server"}, - {vsn, "3.1.0"}, + {vsn, "3.1.1"}, {modules, []}, {registered, []}, {env, []}, diff --git a/src/mochiweb_request.erl b/src/mochiweb_request.erl index bbb613a1..3d64906e 100644 --- a/src/mochiweb_request.erl +++ b/src/mochiweb_request.erl @@ -710,7 +710,7 @@ parse_post({?MODULE, %% @spec stream_chunked_body(integer(), fun(), term(), request()) -> term() %% @doc The function is called for each chunk. -%% Used internally by read_chunked_body. +%% Used internally by stream_body. stream_chunked_body(MaxChunkSize, Fun, FunState, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, diff --git a/test/mochiweb_http_tests.erl b/test/mochiweb_http_tests.erl index 35be11dd..8b8ba645 100644 --- a/test/mochiweb_http_tests.erl +++ b/test/mochiweb_http_tests.erl @@ -1,17 +1,49 @@ -module(mochiweb_http_tests). -include_lib("eunit/include/eunit.hrl"). +-include("mochiweb_test_util.hrl"). has_acceptor_bug_test_() -> {setup, fun start_server/0, fun mochiweb_http:stop/1, fun has_acceptor_bug_tests/1}. + start_server() -> application:start(inets), {ok, Pid} = mochiweb_http:start_link([{port, 0}, {loop, fun responder/1}]), Pid. +chunked_server(Req) -> + mochiweb_request:respond( + { + 201, + [{"Content-Type", "application/octet-stream"}], + mochiweb_request:recv_body(Req) + }, + Req + ). + +chunked_client(Transport, Port) -> + mochiweb_test_util:client_request( + Transport, + Port, + 'POST', + [#treq{ + path = "/", + body = {chunked, ["5\r\n", "Mochi\r\n", "9 \r\n", "Developer\r\n", "0\r\n\r\n"]}, + xreply = <<"MochiDeveloper">> + }] + ). + +chunked_encoding_test() -> + Res = mochiweb_test_util:with_server( + plain, + fun chunked_server/1, + fun chunked_client/2 + ), + ?assertEqual(ok, Res). + has_acceptor_bug_tests(Server) -> Port = mochiweb_socket_server:get(Server, port), [{"1000 should be fine even with the bug", diff --git a/test/mochiweb_test_util.erl b/test/mochiweb_test_util.erl index c343384e..86987715 100644 --- a/test/mochiweb_test_util.erl +++ b/test/mochiweb_test_util.erl @@ -67,6 +67,11 @@ sock_fun(Transport, Port) -> client_request(Transport, Port, Method, TestReqs) -> client_request(sock_fun(Transport, Port), Method, TestReqs). +body({ chunked, ChunkedBody }) -> + ChunkedBody; +body(Body) -> + Body. + client_request(SockFun, _Method, []) -> {the_end, {error, closed}} = {the_end, SockFun(recv)}, ok; @@ -75,7 +80,7 @@ client_request(SockFun, Method, Request = [atom_to_list(Method), " ", Path, " HTTP/1.1\r\n", client_headers(Body, Rest =:= []), "\r\n", - Body], + body(Body)], ok = SockFun({setopts, [{packet, http}]}), ok = SockFun({send, Request}), case Method of @@ -118,14 +123,20 @@ read_server_headers(SockFun, Headers) -> mochiweb_headers:insert(Header, Value, Headers)) end. +body_length_headers(<<>>) -> + ""; +body_length_headers({ chunked, _ }) -> + "Transfer-Encoding: chunked\r\n"; +body_length_headers(Body) -> + ["Content-Length: ", integer_to_list(byte_size(Body)), "\r\n"]. + client_headers(Body, IsLastRequest) -> ["Host: localhost\r\n", case Body of <<>> -> ""; _ -> - ["Content-Type: application/octet-stream\r\n", - "Content-Length: ", integer_to_list(byte_size(Body)), "\r\n"] + ["Content-Type: application/octet-stream\r\n" | body_length_headers(Body)] end, case IsLastRequest of true ->