[erlang-bugs] Crashing bug in inets http client in R13B.

Per Melin per.melin@REDACTED
Sat May 9 21:32:53 CEST 2009


PROBLEM 1:
The documentation for http:set_options/1,2 describes the option
{max_keep_alive_length, MaxKeepAlive} as
"Maximum number of outstanding requests on the same connection to a
host. Default is 2."

1> http:set_options([{max_keep_alive_length, 10}]).
{error,{not_an_option,{max_keep_alive_length,10}}}

http:validate_options/1 is missing a check for max_keep_alive_length.
Instead it has two identical checks for max_pipeline_length.

PROBLEM 2:
The documentation says the default for max_keep_alive_length is 2, but
it's actually 5.

PROBLEM 3:
Looking at the code, I see that it checks that
#tcp_session{queue_length} never exceeds max_keep_alive_length. But
when pipelining is disabled queue_length is always just either 0 or 1.

When pipelining is disabled requests will still be unwittingly
pipelined, which can cause requests to be lost and if the server
actually supports pipelining the handler will crash.

SCENARIO 1:

Eshell V5.7.1  (abort with ^G)
1> inets:start().
ok
2> URL = "http://www.erlang.org/".
"http://www.erlang.org/"
3> http:request(get, {URL, []}, [], []),
3> http:request(get, {URL, []}, [], [{sync, false}]),
3> http:request(get, {URL, []}, [], [{sync, false}]),
3> http:request(get, {URL, []}, [], [{sync, false}]),
3> ok.
ok
4>
=ERROR REPORT==== 9-May-2009::20:50:49 ===
** Generic server <0.48.0> terminating
** Last message in was {tcp,#Port<0.955>, ...

4> process_info(self(), message_queue_len).
{message_queue_len,1}

SCENARIO 2:

Eshell V5.7.1  (abort with ^G)
1> inets:start().
ok
2> URL = "http://www.erlang.org/".
"http://www.erlang.org/"
3> F = fun() -> http:request(get, {URL, []}, [], []) end,
3> F(),
3> spawn(F),
3> spawn(F),
3> spawn(F),
3> ok.
ok
4>
=ERROR REPORT==== 9-May-2009::20:52:52 ===
** Generic server <0.48.0> terminating
** Last message in was {tcp,#Port<0.955>, ...

In both cases the first request will create a handler and a keep-alive
session. The second request will reuse the connection. But so will the
third and fourth request, before the second has finished.

The handler doesn't think it's pipelining and when the response from
the third request comes back it doesn't know what to do with it and
crashes.

I'm probably wrong, but from reading the code it seems to me that the
implementation of keep-alive requests without pipelining is only
halfway done.



More information about the erlang-bugs mailing list