Dmytro Shteflyuk created THRIFT-6144:
----------------------------------------
Summary: Ruby BaseTransport read_all should report EOF when reads
make no progress
Key: THRIFT-6144
URL: https://issues.apache.org/jira/browse/THRIFT-6144
Project: Thrift
Issue Type: Bug
Components: Ruby - Library
Reporter: Dmytro Shteflyuk
Assignee: Dmytro Shteflyuk
h3. Problem
{{BaseTransport#read_all}} repeatedly calls {{read}} until it has received the
requested number of bytes. It currently assumes that every call returns a
non-empty string.
That assumption does not hold for every Ruby transport. {{IOStreamTransport}}
delegates to Ruby {{IO#read}}, which returns {{nil}} at end of file, while
layered transports can return an empty string when no bytes remain. An empty
result makes {{read_all}} repeat forever without making progress. A {{nil}}
result instead escapes as a raw {{NoMethodError}}.
h3. Client impact
A client reading a truncated or exhausted input through an affected transport
can hang indefinitely when the transport returns an empty string. If the
transport returns {{nil}}, the client receives an implementation-level Ruby
exception rather than a typed Thrift transport exception.
Normal partial reads are also affected when the input ends after some, but not
all, of the requested bytes have been received.
h3. Reproduction
Testing on master commit {{c2def39207a73394420088da9b4b105571dd9036}} produces:
{code:bash}
bundle exec ruby -Ilib -e '
require "timeout"
require "thrift"
[["empty string", ""], ["nil", nil]].each do |label, result|
transport = Thrift::BaseTransport.new
transport.define_singleton_method(:read) { |_| result }
begin
Timeout.timeout(0.1) { transport.read_all(1) }
rescue => error
puts "#{label}: #{error.class}: #{error.message}"
end
end
'
{code}
{code}
empty string: Timeout::Error: execution expired
nil: NoMethodError: undefined method 'encoding' for nil
{code}
h3. Expected behavior
{{read_all(size)}} should continue across partial reads while each read returns
at least one byte. If a positive-size read returns {{nil}} or an empty string
before the requested size is satisfied, it should stop immediately and raise
{{TransportException::END_OF_FILE}}.
A zero-size read should continue to return an empty binary string without
invoking the underlying transport.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)