1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
# frozen_string_literal: true
require 'stringio'
module Faraday
# Rubocop doesn't seem to understand that this is an extension to the
# Multipart module, so let's add a nodoc
# #:nodoc:
module Multipart
# 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]
if ::Gem::Requirement.new('>= 2.2.0').satisfied_by?(multipart_post_version)
require 'multipart/post'
FilePart = ::Multipart::Post::UploadIO
Parts = ::Multipart::Post::Parts
else
require 'composite_io'
require 'parts'
FilePart = ::UploadIO
Parts = ::Parts
end
# 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
end
|