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 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