Skip to content

Commit 23903ed

Browse files
authored
Close idle zero byte connections silently instead of answering 408 (#689)
1 parent 6dec055 commit 23903ed

2 files changed

Lines changed: 22 additions & 1 deletion

File tree

lib/bandit/initial_handler.ex

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ defmodule Bandit.InitialHandler do
4141
{true, _, :no_match, {:no_match, data}} ->
4242
{:switch, Bandit.HTTP1.Handler, data, state}
4343

44+
{_, _, _, :idle_timeout} ->
45+
# The connection sent no bytes at all within the read timeout (an idle probe, port
46+
# scan or similar). Close silently rather than handing an empty buffer to the HTTP/1
47+
# handler, which would block for a second read timeout and then answer with an
48+
# unsolicited 408
49+
{:close, state}
50+
4451
_other ->
4552
{:close, state}
4653
end
@@ -63,14 +70,15 @@ defmodule Bandit.InitialHandler do
6370
@spec sniff_wire(ThousandIsland.Socket.t()) ::
6471
Bandit.HTTP2.Handler
6572
| :likely_tls
73+
| :idle_timeout
6674
| {:no_match, binary()}
6775
| {:error, :closed | :timeout | :inet.posix()}
6876
defp sniff_wire(socket) do
6977
case ThousandIsland.Socket.recv(socket, 3) do
7078
{:ok, "PRI" = buffer} -> sniff_wire_for_http2(socket, buffer)
7179
{:ok, <<22::8, 3::8, minor::8>>} when minor in [1, 3] -> :likely_tls
7280
{:ok, data} -> {:no_match, data}
73-
{:error, :timeout} -> {:no_match, <<>>}
81+
{:error, :timeout} -> :idle_timeout
7482
{:error, error} -> {:error, error}
7583
end
7684
end

test/bandit/initial_handler_test.exs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,19 @@ defmodule InitialHandlerTest do
8888
end
8989
end
9090

91+
describe "idle connections" do
92+
setup :http_server
93+
94+
test "closes silently when no data is sent before the read timeout", context do
95+
client = SimpleHTTP1Client.tcp_client(context)
96+
97+
# Expect a silent close after the server's read timeout: no unsolicited 408
98+
# response bytes and no error logged
99+
assert Transport.recv(client, 0) == {:error, :closed}
100+
refute_receive {:log, %{level: :error}}
101+
end
102+
end
103+
91104
describe "unknown protocols" do
92105
setup :http_server
93106
setup :req_http1_client

0 commit comments

Comments
 (0)