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

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

> Ruby client leaves transports reusable after uncertain request sends
> --------------------------------------------------------------------
>
>                 Key: THRIFT-6125
>                 URL: https://issues.apache.org/jira/browse/THRIFT-6125
>             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
> The Ruby client closes its output transport when argument serialization 
> fails, but not when writing the message envelope, finishing the message, or 
> flushing the transport fails.
> Once message writing has begun, an exception does not reliably indicate 
> whether zero, some, or all request bytes reached the underlying connection. 
> Leaving that connection open allows a later call to reuse transport state 
> whose wire outcome is unknown. A buffered transport may still contain request 
> data, while an unbuffered transport may already have emitted part or all of 
> the request.
> Argument construction is different: when creating or assigning the generated 
> arguments fails before message writing starts, no bytes have been published 
> and the connection remains safe to reuse.
> h3. Client impact
> After a write or flush error, an application may catch the exception and make 
> another call with the same generated client. Because the Ruby client 
> currently leaves the transport open, that later request can follow incomplete 
> or retained data from the failed request. This can desynchronize the client 
> and server or make it unclear which request a subsequent response belongs to.
> The behavior affects both ordinary calls and oneway calls. For ordinary 
> calls, a failed send must also not add a sequence ID to the pending-reply 
> queue.
> h3. Reproduction
> The following example uses a transport that accepts request bytes but fails 
> during flush:
> {code:ruby}
> require "thrift"
> class FailingFlushTransport < Thrift::BaseTransport
>   attr_reader :closed
>   def write(_data)
>   end
>   def flush
>     raise Thrift::TransportException.new(
>       Thrift::TransportException::UNKNOWN,
>       "flush failed"
>     )
>   end
>   def close
>     @closed = true
>   end
> end
> class EmptyArgs
>   def write(_protocol)
>   end
> end
> class ExampleClient
>   include Thrift::Client
> end
> transport = FailingFlushTransport.new
> protocol = Thrift::BinaryProtocol.new(transport)
> client = ExampleClient.new(protocol)
> begin
>   client.send_message("example", EmptyArgs)
> rescue Thrift::TransportException => error
>   puts "#{error.message}; closed=#{transport.closed.inspect}"
> end
> {code}
> The current implementation prints:
> {noformat}
> flush failed; closed=nil
> {noformat}
> The transport therefore remains available for another request even though 
> delivery of the failed request is uncertain.
> h3. Expected behavior
> The client should construct and assign arguments before beginning message 
> output. Failures at that stage should leave the transport open and should not 
> consume a sequence ID.
> After message output begins, an exception from the envelope, argument 
> serialization, message end, or flush should close the output transport and 
> re-raise the original exception. A failure while closing must not replace the 
> original send error. Ordinary calls should enter the pending-reply queue only 
> after a successful flush, and oneway calls should follow the same 
> transport-closing rule.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to