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.
This commit is contained in:
HoneyryderChuck 2021-01-13 00:40:51 +00:00
parent 4987b2d583
commit fd91aca873

View File

@ -3,6 +3,8 @@
module HTTPX::Plugins module HTTPX::Plugins
module Multipart module Multipart
class Encoder class Encoder
attr_reader :bytesize
def initialize(form) def initialize(form)
@boundary = ("-" * 21) << SecureRandom.hex(21) @boundary = ("-" * 21) << SecureRandom.hex(21)
@part_index = 0 @part_index = 0
@ -15,16 +17,6 @@ module HTTPX::Plugins
"multipart/form-data; boundary=#{@boundary}" "multipart/form-data; boundary=#{@boundary}"
end 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) def read(length = nil, outbuf = nil)
data = outbuf.clear.force_encoding(Encoding::BINARY) if outbuf data = outbuf.clear.force_encoding(Encoding::BINARY) if outbuf
data ||= "".b data ||= "".b
@ -37,15 +29,27 @@ module HTTPX::Plugins
private private
def to_parts(form) def to_parts(form)
@bytesize = 0
params = form.each_with_object([]) do |(key, val), aux| params = form.each_with_object([]) do |(key, val), aux|
Multipart.normalize_keys(key, val) do |k, v| Multipart.normalize_keys(key, val) do |k, v|
value, content_type, filename = Part.call(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 << value
aux << StringIO.new("\r\n")
delimiter = StringIO.new("\r\n")
@bytesize += delimiter.size
aux << delimiter
end end
end end
params << StringIO.new("--#{@boundary}--\r\n") final_delimiter = StringIO.new("--#{@boundary}--\r\n")
@bytesize += final_delimiter.size
params << final_delimiter
params params
end end
@ -79,6 +83,8 @@ module HTTPX::Plugins
return chunk if chunk && !chunk.empty? return chunk if chunk && !chunk.empty?
part.close if part.respond_to?(:close)
@part_index += 1 @part_index += 1
nil nil