Skip to content

Commit 06053e6

Browse files
nateberkopecevanphx
andcommitted
Merge pull request from GHSA-7xx3-m584-x994
could monopolize a thread. Previously, this could make a DoS attack more severe. Co-authored-by: Evan Phoenix <[email protected]>
1 parent 461c9e9 commit 06053e6

File tree

2 files changed

+22
-1
lines changed

2 files changed

+22
-1
lines changed

lib/puma/const.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,13 @@ module Const
118118
# sending data back
119119
WRITE_TIMEOUT = 10
120120

121+
# How many requests to attempt inline before sending a client back to
122+
# the reactor to be subject to normal ordering. The idea here is that
123+
# we amortize the cost of going back to the reactor for a well behaved
124+
# but very "greedy" client across 10 requests. This prevents a not
125+
# well behaved client from monopolizing the thread forever.
126+
MAX_FAST_INLINE = 10
127+
121128
# The original URI requested by the client.
122129
REQUEST_URI= 'REQUEST_URI'.freeze
123130
REQUEST_PATH = 'REQUEST_PATH'.freeze

lib/puma/server.rb

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,8 @@ def process_client(client, buffer)
470470
clean_thread_locals = @options[:clean_thread_locals]
471471
close_socket = true
472472

473+
requests = 0
474+
473475
while true
474476
case handle_request(client, buffer)
475477
when false
@@ -483,7 +485,19 @@ def process_client(client, buffer)
483485

484486
ThreadPool.clean_thread_locals if clean_thread_locals
485487

486-
unless client.reset(@status == :run)
488+
requests += 1
489+
490+
check_for_more_data = @status == :run
491+
492+
if requests >= MAX_FAST_INLINE
493+
# This will mean that reset will only try to use the data it already
494+
# has buffered and won't try to read more data. What this means is that
495+
# every client, independent of their request speed, gets treated like a slow
496+
# one once every MAX_FAST_INLINE requests.
497+
check_for_more_data = false
498+
end
499+
500+
unless client.reset(check_for_more_data)
487501
close_socket = false
488502
client.set_timeout @persistent_timeout
489503
@reactor.add client

0 commit comments

Comments
 (0)