-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Closed
Labels
Description
Describe the bug
It seems like there's a bug in this optimization where after handling a request it tries to read the next request from the socket:
https://github.com/puma/puma/blob/v6.4.3/lib/puma/server.rb#L475-L486.
In this code specifically:
begin
if fast_check && @to_io.wait_readable(FAST_TRACK_KA_TIMEOUT)
return try_to_finish
end
rescue IOError
# swallow it
end
If the request parsing fails, try_to_finish
raises a Puma::HttpParserError
which inherits IOError
and it causes the invalid request to be swallowed and to time out after 20 seconds.
To Reproduce
Copy this into a file called hello.ru
:
run lambda { |env| [200, {"Content-Type" => "text/plain"}, ["Hello World"]] }
Run it with:
bundle exec puma hello.ru
Run this curl command:
curl -v --keepalive-time 30 "http://localhost:9292" --next "http://localhost:9292/$(printf 'a%.0s' {1..9000})"
This will send 2 requests sequentially in the same TCP connection:
- The first request succeeds with status code 200
- The second request is invalid - its path is longer than the allowed length (8192) - it hangs for 20 seconds and then the connection dies 💥
Expected behavior
The second request should return 400 immediately with the following error:
HTTP parse error, malformed request ("GET " - (-)): #<Puma::HttpParserError: HTTP element REQUEST_PATH is longer than the (8192) allowed length (was 9001)>
Desktop (please complete the following information):
- Puma Version 6.4.3