Merge pull request #252 from mochi/test-chunked-encoding

Add a test for the chunked encoding fix
diff --git a/.editorconfig b/.editorconfig
index d03550e..0a7aa67 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -15,3 +15,4 @@
 [*.{erl,src,hrl}]
 indent_style = space
 indent_size = 4
+tab_width = 8
diff --git a/CHANGES.md b/CHANGES.md
index 728541e..b14ceec 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 425e220..a130893 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 bbb613a..3d64906 100644
--- a/src/mochiweb_request.erl
+++ b/src/mochiweb_request.erl
@@ -710,7 +710,7 @@
 
 %% @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 35be11d..8b8ba64 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 c343384..8698771 100644
--- a/test/mochiweb_test_util.erl
+++ b/test/mochiweb_test_util.erl
@@ -67,6 +67,11 @@
 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 @@
     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 @@
               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 ->