Dmytro Shteflyuk created THRIFT-6132:
----------------------------------------
Summary: Ruby HeaderTransport retains stale metadata after legacy
frames
Key: THRIFT-6132
URL: https://issues.apache.org/jira/browse/THRIFT-6132
Project: Thrift
Issue Type: Bug
Components: Ruby - Library
Reporter: Dmytro Shteflyuk
Assignee: Dmytro Shteflyuk
h3. Problem
{{HeaderTransport}} exposes key-value metadata from the most recently parsed
Header frame through {{get_headers}}. When the same connection subsequently
receives a framed or unframed Binary or Compact message, the transport does not
clear that metadata because the reset currently occurs only while parsing
another Header frame.
As a result, metadata from an earlier Header message remains visible while
processing a later legacy message that did not carry any headers. The same
stale state can remain visible when parsing the following frame fails before
Header metadata is reset.
h3. Client impact
Applications that use Header metadata for logging, tracing, routing, or request
context can associate values from an earlier request with a later request on
the same connection. The stale values remain visible until another valid Header
frame replaces them.
This affects HeaderTransport's supported protocol auto-detection paths for
framed and unframed Binary and Compact messages.
h3. Reproduction
The following reproduction constructs a Header frame containing a request ID
followed by a framed Binary message with no Header metadata:
{code:ruby}
require "thrift"
def header_frame(payload, headers)
buffer = Thrift::MemoryBufferTransport.new
writer = Thrift::HeaderTransport.new(buffer)
headers.each { |key, value| writer.set_header(key, value) }
writer.write(payload)
writer.flush
buffer.read(buffer.available)
end
binary = [
Thrift::BinaryProtocol::VERSION_1 | Thrift::MessageTypes::CALL
].pack("N")
bytes = header_frame("A", "request-id" => "first")
bytes << [binary.bytesize].pack("N")
bytes << binary
transport = Thrift::HeaderTransport.new(
Thrift::MemoryBufferTransport.new(bytes)
)
transport.read(1)
puts "after Header: #{transport.get_headers.inspect}"
transport.reset_protocol
transport.read(4)
puts "after framed Binary: #{transport.get_headers.inspect}"
{code}
Run from {{lib/rb}} with:
{code:bash}
bundle exec ruby -Ilib reproduction.rb
{code}
Testing on master commit {{f69c2078b7c11c09aa4f8b8879d8b41342145461}} produces:
{code}
after Header: {"request-id" => "first"}
after framed Binary: {"request-id" => "first"}
{code}
h3. Expected behavior
Header metadata should be reset when parsing begins for every new frame, before
protocol detection or validation. Legacy Binary and Compact messages should
expose an empty header map, malformed following frames should not leave
metadata from the previous message visible, and a later valid Header frame
should expose only its own metadata.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)