Dmytro Shteflyuk created THRIFT-6155:
----------------------------------------
Summary: Ruby SimpleServer exits on zero-length framed messages
Key: THRIFT-6155
URL: https://issues.apache.org/jira/browse/THRIFT-6155
Project: Thrift
Issue Type: Bug
Components: Ruby - Library
Reporter: Dmytro Shteflyuk
Assignee: Dmytro Shteflyuk
h3. Problem
Ruby's {{FramedTransport}} accepts a frame header whose declared payload length
is zero. Its optimized read paths then attempt to read a byte from an empty
frame and return or operate on {{nil}} instead of raising a Thrift transport
error.
When this reaches {{CompactProtocol}}, the native implementation raises a Ruby
{{TypeError}} and the pure-Ruby implementation raises a {{NoMethodError}}.
{{SimpleServer}} treats typed transport and protocol exceptions as
connection-local failures, but these raw Ruby exceptions escape the serve loop
and close the listener.
h3. Client impact
A client connection that sends a zero-length frame can cause a Ruby
{{SimpleServer}} to stop accepting further connections. Other server
implementations may contain the failure to a connection worker, but callers
still receive implementation-dependent Ruby exceptions rather than a consistent
Thrift transport error.
h3. Reproduction
The transport-level behavior can be reproduced with:
{code:language=ruby}
require "thrift"
frame = [0].pack("N")
transport = Thrift::FramedTransport.new(
Thrift::MemoryBufferTransport.new(frame),
)
p transport.read_byte
{code}
Testing on master commit {{04c87e89ae25e759123b942d2d73e4cc3415c948}} produces:
{noformat}
nil
{noformat}
A deterministic loopback {{SimpleServer}} reproduction using framed Compact
protocol produced:
{noformat}
native=true
server_error=TypeError: no implicit conversion from nil to integer
listener_closed=true
{noformat}
With {{thrift_native}} deliberately disabled, the same reproduction produced:
{noformat}
native=false
server_error=NoMethodError: undefined method '>' for nil
listener_closed=true
{noformat}
h3. Expected behavior
{{FramedTransport}} should reject a zero-length frame with a typed transport
exception before any optimized reader accesses the empty payload. {{read}},
{{read_byte}}, and {{read_into_buffer}} should follow the same contract.
{{SimpleServer}} should close only the affected connection and continue
accepting subsequent valid requests.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)