From fd91aca87342a85e7eb7e5a016201d27fdcc947f Mon Sep 17 00:00:00 2001 From: HoneyryderChuck Date: Wed, 13 Jan 2021 00:40:51 +0000 Subject: [PATCH] closing descriptors as they're flushed by the request. this wasn't as easy due to reliance on Request#bytesize, which was calling File#size on the closed file descriptors, which raised an IOError caught by the selector. Caching fixes it, and removes the recalculations from the hot path as well. --- lib/httpx/plugins/multipart/encoder.rb | 32 +++++++++++++++----------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/lib/httpx/plugins/multipart/encoder.rb b/lib/httpx/plugins/multipart/encoder.rb index fca237d5..f725937b 100644 --- a/lib/httpx/plugins/multipart/encoder.rb +++ b/lib/httpx/plugins/multipart/encoder.rb @@ -3,6 +3,8 @@ module HTTPX::Plugins module Multipart class Encoder + attr_reader :bytesize + def initialize(form) @boundary = ("-" * 21) << SecureRandom.hex(21) @part_index = 0 @@ -15,16 +17,6 @@ module HTTPX::Plugins "multipart/form-data; boundary=#{@boundary}" end - if RUBY_VERSION > "2.3" - def bytesize - @parts.map(&:size).sum - end - else - def bytesize - @parts.map(&:size).reduce(0, :+) - end - end - def read(length = nil, outbuf = nil) data = outbuf.clear.force_encoding(Encoding::BINARY) if outbuf data ||= "".b @@ -37,15 +29,27 @@ module HTTPX::Plugins private def to_parts(form) + @bytesize = 0 params = form.each_with_object([]) do |(key, val), aux| Multipart.normalize_keys(key, val) do |k, v| value, content_type, filename = Part.call(v) - aux << header_part(k, content_type, filename) + + header = header_part(k, content_type, filename) + @bytesize += header.size + aux << header + + @bytesize += value.size aux << value - aux << StringIO.new("\r\n") + + delimiter = StringIO.new("\r\n") + @bytesize += delimiter.size + aux << delimiter end end - params << StringIO.new("--#{@boundary}--\r\n") + final_delimiter = StringIO.new("--#{@boundary}--\r\n") + @bytesize += final_delimiter.size + params << final_delimiter + params end @@ -79,6 +83,8 @@ module HTTPX::Plugins return chunk if chunk && !chunk.empty? + part.close if part.respond_to?(:close) + @part_index += 1 nil