One of my colleagues encountered a problem in Erlang code that uses Cowboy. When he POST
ed application/x-www-form-urlencoded
data with Content-Length: 1213
through nginx, it took 0.020s. Acceptable? Yes. When he did POST
to server directly, it took 1.008s. And then he increased Content-Length
by 1 and POST
ed again: it took 5s and 1s respectively. Definitely not acceptable.
Let’s take a look at code. Note that this happened before cowboy_http_req
became cowboy_req
:
handle(Req, State) ->
cowboy_http_req:body(Req),
Reply = <<"I'm reply">>,
{ok, Req2} = cowboy_http_req:reply(200, [], Reply, Req),
{ok, Req2, State}.
Seems good, right? But this is where bug lies. When you’re writing server with Cowboy, it is important to use newReq
. Let’s take a look at spec of body
:
-spec body(Req) -> {ok, binary(), Req} | {error, atom()} when Req::req().
It returns {ok, Body, Req}
, but returned tuple is ignored in code of handle
(actually, if we’ll remove that line, bug will disappear :) Here’s how it should look now:
handle(Req, State) ->
{ok, _, Req1} = cowboy_http_req:body(Req),
Reply = <<"I'm reply">>,
{ok, Req2} = cowboy_http_req:reply(200, [], Reply, Req1),
{ok, Req2, State}.
Or, with new Cowboy’s code:
handle(Req, State) ->
{ok, _, Req1} = cowboy_req:body(Req),
Reply = <<"I'm reply">>,
{ok, Req2} = cowboy_req:reply(200, [], Reply, Req1),
{ok, Req2, State}.
This blog is about things I encounter while doing web and non-web software development.