From 69f9557780147a06d40d3df329d5a9f8501a6aac Mon Sep 17 00:00:00 2001 From: HoneyryderChuck Date: Wed, 9 Apr 2025 10:36:27 +0100 Subject: [PATCH] corrected equality comparison of response bodies --- lib/httpx/response/body.rb | 29 +++++++--------------- lib/httpx/response/buffer.rb | 48 +++++++++++++++++++++++++++--------- sig/response/body.rbs | 7 +++--- sig/response/buffer.rbs | 5 ++-- 4 files changed, 50 insertions(+), 39 deletions(-) diff --git a/lib/httpx/response/body.rb b/lib/httpx/response/body.rb index 78aa6ae2..c5f9f990 100644 --- a/lib/httpx/response/body.rb +++ b/lib/httpx/response/body.rb @@ -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 diff --git a/lib/httpx/response/buffer.rb b/lib/httpx/response/buffer.rb index 820c374e..43bdec21 100644 --- a/lib/httpx/response/buffer.rb +++ b/lib/httpx/response/buffer.rb @@ -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 diff --git a/sig/response/body.rbs b/sig/response/body.rbs index 5106cc87..4c15a909 100644 --- a/sig/response/body.rbs +++ b/sig/response/body.rbs @@ -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 \ No newline at end of file diff --git a/sig/response/buffer.rbs b/sig/response/buffer.rbs index 708e71e1..ff6d8d6d 100644 --- a/sig/response/buffer.rbs +++ b/sig/response/buffer.rbs @@ -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 \ No newline at end of file