corrected equality comparison of response bodies

This commit is contained in:
HoneyryderChuck 2025-04-09 10:36:27 +01:00
parent 339af65cc1
commit 69f9557780
4 changed files with 50 additions and 39 deletions

View File

@ -11,6 +11,9 @@ module HTTPX
# Array of encodings contained in the response "content-encoding" header.
attr_reader :encodings
attr_reader :buffer
protected :buffer
# initialized with the corresponding HTTPX::Response +response+ and HTTPX::Options +options+.
def initialize(response, options)
@response = response
@ -148,13 +151,12 @@ module HTTPX
end
def ==(other)
object_id == other.object_id || begin
if other.respond_to?(:read)
_with_same_buffer_pos { FileUtils.compare_stream(@buffer, other) }
else
to_s == other.to_s
end
end
super || case other
when Response::Body
@buffer == other.buffer
else
@buffer = other
end
end
# :nocov:
@ -226,19 +228,6 @@ module HTTPX
@state = nextstate
end
def _with_same_buffer_pos # :nodoc:
return yield unless @buffer && @buffer.respond_to?(:pos)
# @type ivar @buffer: StringIO | Tempfile
current_pos = @buffer.pos
@buffer.rewind
begin
yield
ensure
@buffer.pos = current_pos
end
end
class << self
def initialize_inflater_by_encoding(encoding, response, **kwargs) # :nodoc:
case encoding

View File

@ -7,6 +7,9 @@ require "tempfile"
module HTTPX
# wraps and delegates to an internal buffer, which can be a StringIO or a Tempfile.
class Response::Buffer < SimpleDelegator
attr_reader :buffer
protected :buffer
# initializes buffer with the +threshold_size+ over which the payload gets buffer to a tempfile,
# the initial +bytesize+, and the +encoding+.
def initialize(threshold_size:, bytesize: 0, encoding: Encoding::BINARY)
@ -20,7 +23,14 @@ module HTTPX
def initialize_dup(other)
super
@buffer = other.instance_variable_get(:@buffer).dup
# create new descriptor in READ-ONLY mode
@buffer =
case other.buffer
when StringIO
StringIO.new(other.buffer.string, mode: File::RDONLY)
else
other.buffer.class.new(other.buffer.path, encoding: Encoding::BINARY, mode: File::RDONLY)
end
end
# size in bytes of the buffered content.
@ -46,7 +56,7 @@ module HTTPX
end
when Tempfile
rewind
content = _with_same_buffer_pos { @buffer.read }
content = @buffer.read
begin
content.force_encoding(@encoding)
rescue ArgumentError # ex: unknown encoding name - utf
@ -61,6 +71,30 @@ module HTTPX
@buffer.unlink if @buffer.respond_to?(:unlink)
end
def ==(other)
super || begin
return false unless other.is_a?(Response::Buffer)
if @buffer.nil?
other.buffer.nil?
elsif @buffer.respond_to?(:read) &&
other.respond_to?(:read)
buffer_pos = @buffer.pos
other_pos = other.buffer.pos
@buffer.rewind
other.buffer.rewind
begin
FileUtils.compare_stream(@buffer, other.buffer)
ensure
@buffer.pos = buffer_pos
other.buffer.pos = other_pos
end
else
to_s == other.to_s
end
end
end
private
# initializes the buffer into a StringIO, or turns it into a Tempfile when the threshold
@ -82,15 +116,5 @@ module HTTPX
__setobj__(@buffer)
end
def _with_same_buffer_pos # :nodoc:
current_pos = @buffer.pos
@buffer.rewind
begin
yield
ensure
@buffer.pos = current_pos
end
end
end
end

View File

@ -7,14 +7,15 @@ module HTTPX
attr_reader encoding: Encoding
attr_reader encodings: Array[String]
attr_reader buffer: Response::Buffer?
@response: Response
@headers: Headers
@options: Options
@state: :idle | :memory | :buffer | :closed
@window_size: Integer
@length: Integer
@buffer: StringIO | Tempfile | nil
@reader: StringIO | Tempfile | nil
@reader: Response::Buffer?
@inflaters: Array[Transcoder::_Inflater]
def initialize: (Response, Options) -> void
@ -47,7 +48,5 @@ module HTTPX
def decode_chunk: (String chunk) -> String
def transition: (Symbol nextstate) -> void
def _with_same_buffer_pos: [A] () { () -> A } -> A
end
end

View File

@ -1,9 +1,10 @@
module HTTPX
class Response::Buffer
attr_reader buffer: StringIO | Tempfile
@threshold_size: Integer
@bytesize: Integer
@encoding: Encoding
@buffer: StringIO | Tempfile
def initialize: (threshold_size: Integer, ?bytesize: Integer, ?encoding: Encoding) -> void
@ -18,7 +19,5 @@ module HTTPX
private
def try_upgrade_buffer: () -> void
def _with_same_buffer_pos: () { () -> void } -> void
end
end