* Fix a bug that the last CRLF of chunked body may be used in the next request
The last CRLF of chunked body is checked by #1607. But it's
incomplete. If a client sends the last CRLF (or just LF) after Puma
processes "0\r\n" line, the last CRLF (or just LF) isn't dropped in
the "0\r\n" process:
675344e860/lib/puma/client.rb (L183-L192)
if line.end_with?("\r\n")
len = line.strip.to_i(16)
if len == 0
@body.rewind
rest = io.read
# rest is "" with no the last CRLF case and
# "\r" with no last LF case.
# rest.start_with?("\r\n") returns false for
# Both of these cases.
rest = rest[2..-1] if rest.start_with?("\r\n")
@buffer = rest.empty? ? nil : rest
set_ready
return true
end
The unprocessed last CRLF (or LF) is used as the first data in the
next request. Because Puma::Client#reset sets `@parsed_bytes`
to 0.
675344e860/lib/puma/client.rb (L100-L109)
def reset(fast_check=true)
@parsed_bytes = 0
It means that data in `@buffer` (it's "\r" in no the last LF case) and
unread data in input socket (it's "\r\n" in no the last CRLF case and
"\n" in no the last LF case) are used used as the first data in the
next request.
This change fixes these cases by the followings:
* Ensures reading the last CRLF by setting `@partial_part_left` when
CRLF isn't read in processing "0\r\n" line.
* Introduces a `@in_last_chunk` new state to detect whether the last
CRLF is waiting or not. It's reset in Puma::Client#reset.
* Remove unnecessary returns
https://github.com/puma/puma/pull/1812#discussion_r307806310 is the
location where this rule is made.
* Add missing last CRLF for chunked request in tests