[ 
https://issues.apache.org/jira/browse/THRIFT-6144?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Dmytro Shteflyuk resolved THRIFT-6144.
--------------------------------------
    Fix Version/s: 0.25.0
       Resolution: Fixed

> 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
>            Priority: Major
>             Fix For: 0.25.0
>
>          Time Spent: 20m
>  Remaining Estimate: 0h
>
> 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)

Reply via email to