diff --git a/rebar.config b/rebar.config index 615cccd1..8327fd7a 100644 --- a/rebar.config +++ b/rebar.config @@ -1,5 +1,7 @@ % -*- mode: erlang -*- -{erl_opts, [debug_info]}. +{erl_opts, [debug_info, + {platform_define, "(R14|R16)", 'gen_tcp_fix'} + ]}. {cover_enabled, true}. {eunit_opts, [verbose, {report,{eunit_surefire,[{dir,"."}]}}]}. {dialyzer_opts, [{warnings, [no_return, diff --git a/scripts/check_for_gen_tcp_fix.erl b/scripts/check_for_gen_tcp_fix.erl new file mode 100755 index 00000000..646b548e --- /dev/null +++ b/scripts/check_for_gen_tcp_fix.erl @@ -0,0 +1,28 @@ +#!/usr/bin/env escript +%% -*- mode: erlang -*- +%%! -pa ../ebin +-export([main/1]). + +main([]) -> + application:start (inets), + mochiweb_http:start([{port, 5678}, + {loop, + fun(Req) -> + Req:respond({ 200, + [ {"Content-Type", "text/html"} ], + [ "Hello" ] + }) + end}]), + + io:format ("~p~n",[not has_bug(1000) and not has_bug(10000)]). + +has_bug (Len) -> + case + httpc:request (get, {"http://127.0.0.1:5678/", + [{"X-Random", [$a || _ <- lists:seq(1,Len)]}]}, [], []) + of + {error,socket_closed_remotely} -> true; + {ok,{{"HTTP/1.1",200,"OK"}, _, "Hello"}} -> false; + {ok,{{"HTTP/1.1",400,"Bad Request"}, _, []}} -> false; + R -> io:format ("don't know what to make of ~p~n",[R]), undefined + end. diff --git a/src/mochiweb_http.erl b/src/mochiweb_http.erl index 4f7e947a..bdfd0476 100644 --- a/src/mochiweb_http.erl +++ b/src/mochiweb_http.erl @@ -50,6 +50,16 @@ loop(Socket, Body) -> ok = mochiweb_socket:setopts(Socket, [{packet, http}]), request(Socket, Body). +-ifndef(gen_tcp_fix). +-define(R15B_GEN_TCP_FIX, {tcp_error,_,emsgsize} -> + % R15B02 returns this then closes the socket, so close and exit + mochiweb_socket:close(Socket), + exit(normal); + ). +-else. +-define(R15B_GEN_TCP_FIX,). +-endif. + request(Socket, Body) -> ok = mochiweb_socket:setopts(Socket, [{active, once}]), receive @@ -66,10 +76,7 @@ request(Socket, Body) -> {ssl_closed, _} -> mochiweb_socket:close(Socket), exit(normal); - {tcp_error,_,emsgsize} -> - % R15B02 returns this then closes the socket, so close and exit - mochiweb_socket:close(Socket), - exit(normal); + ?R15B_GEN_TCP_FIX _Other -> handle_invalid_request(Socket) after ?REQUEST_RECV_TIMEOUT -> @@ -99,10 +106,7 @@ headers(Socket, Request, Headers, Body, HeaderCount) -> {tcp_closed, _} -> mochiweb_socket:close(Socket), exit(normal); - {tcp_error,_,emsgsize} -> - % R15B02 returns this then closes the socket, so close and exit - mochiweb_socket:close(Socket), - exit(normal); + ?R15B_GEN_TCP_FIX _Other -> handle_invalid_request(Socket, Request, Headers) after ?HEADERS_RECV_TIMEOUT -> diff --git a/src/mochiweb_socket_server.erl b/src/mochiweb_socket_server.erl index 029f1952..e6e9fc9d 100644 --- a/src/mochiweb_socket_server.erl +++ b/src/mochiweb_socket_server.erl @@ -166,6 +166,7 @@ init(State=#mochiweb_socket_server{ip=Ip, port=Port, backlog=Backlog, nodelay=No {packet, 0}, {backlog, Backlog}, {recbuf, ?RECBUF_SIZE}, + {exit_on_close, false}, {active, false}, {nodelay, NoDelay}], Opts = case Ip of