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)

Reply via email to