1. b.93z.org
  2. Notes

Strange Cowboy server “bug”

One of my colleagues encountered a problem in Erlang code that uses Cowboy. When he POSTed 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 POSTed 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}.

© 2008–2017 93z.org