File Manager
Viewing File: file_part.rb
# frozen_string_literal: true
require 'stringio'
# multipart-post gem
require 'composite_io'
require 'parts'
module Faraday
# Multipart value used to POST a binary data from a file or
#
# @example
# payload = { file: Faraday::FilePart.new("file_name.ext", "content/type") }
# http.post("/upload", payload)
#
# @!method initialize(filename_or_io, content_type, filename = nil, opts = {})
#
# @param filename_or_io [String, IO] Either a String filename to a local
# file or an open IO object.
# @param content_type [String] String content type of the file data.
# @param filename [String] Optional String filename, usually to add context
# to a given IO object.
# @param opts [Hash] Optional Hash of String key/value pairs to describethis
# this uploaded file. Expected Header keys include:
# * Content-Transfer-Encoding - Defaults to "binary"
# * Content-Disposition - Defaults to "form-data"
# * Content-Type - Defaults to the content_type argument.
# * Content-ID - Optional.
#
# @return [Faraday::FilePart]
#
# @!attribute [r] content_type
# The uploaded binary data's content type.
#
# @return [String]
#
# @!attribute [r] original_filename
# The base filename, taken either from the filename_or_io or filename
# arguments in #initialize.
#
# @return [String]
#
# @!attribute [r] opts
# Extra String key/value pairs to make up the header for this uploaded file.
#
# @return [Hash]
#
# @!attribute [r] io
# The open IO object for the uploaded file.
#
# @return [IO]
FilePart = ::UploadIO
# Multipart value used to POST a file.
#
# @deprecated Use FilePart instead of this class. It behaves identically, with
# a matching name to ParamPart.
UploadIO = ::UploadIO
Parts = ::Parts
# Similar to, but not compatible with CompositeReadIO provided by the
# multipart-post gem.
# https://github.com/nicksieger/multipart-post/blob/master/lib/composite_io.rb
class CompositeReadIO
def initialize(*parts)
@parts = parts.flatten
@ios = @parts.map(&:to_io)
@index = 0
end
# @return [Integer] sum of the lengths of all the parts
def length
@parts.inject(0) { |sum, part| sum + part.length }
end
# Rewind each of the IOs and reset the index to 0.
#
# @return [void]
def rewind
@ios.each(&:rewind)
@index = 0
end
# Read from IOs in order until `length` bytes have been received.
#
# @param length [Integer, nil]
# @param outbuf [String, nil]
def read(length = nil, outbuf = nil)
got_result = false
outbuf = outbuf ? (+outbuf).replace('') : +''
while (io = current_io)
if (result = io.read(length))
got_result ||= !result.nil?
result.force_encoding('BINARY') if result.respond_to?(:force_encoding)
outbuf << result
length -= result.length if length
break if length&.zero?
end
advance_io
end
!got_result && length ? nil : outbuf
end
# Close each of the IOs.
#
# @return [void]
def close
@ios.each(&:close)
end
def ensure_open_and_readable
# Rubinius compatibility
end
private
def current_io
@ios[@index]
end
def advance_io
@index += 1
end
end
end