135 lines
4.0 KiB
Ruby
135 lines
4.0 KiB
Ruby
# Copyright 2015 Google Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
|
|
module Google
|
|
module Apis
|
|
module Core
|
|
# Part of a multipart request for holding JSON data
|
|
#
|
|
# @private
|
|
class JsonPart
|
|
|
|
# @param [String] value
|
|
# JSON content
|
|
# @param [Hash] header
|
|
# Additional headers
|
|
def initialize(value, header = {})
|
|
@value = value
|
|
@header = header
|
|
end
|
|
|
|
def to_io(boundary)
|
|
part = ''
|
|
part << "--#{boundary}\r\n"
|
|
part << "Content-Type: application/json\r\n"
|
|
@header.each do |(k, v)|
|
|
part << "#{k}: #{v}\r\n"
|
|
end
|
|
part << "\r\n"
|
|
part << "#{@value}\r\n"
|
|
StringIO.new(part)
|
|
end
|
|
|
|
end
|
|
|
|
# Part of a multipart request for holding arbitrary content.
|
|
#
|
|
# @private
|
|
class FilePart
|
|
# @param [IO] io
|
|
# IO stream
|
|
# @param [Hash] header
|
|
# Additional headers
|
|
def initialize(io, header = {})
|
|
@io = io
|
|
@header = header
|
|
@length = io.respond_to?(:size) ? io.size : nil
|
|
end
|
|
|
|
def to_io(boundary)
|
|
head = ''
|
|
head << "--#{boundary}\r\n"
|
|
@header.each do |(k, v)|
|
|
head << "#{k}: #{v}\r\n"
|
|
end
|
|
head << "Content-Length: #{@length}\r\n" unless @length.nil?
|
|
head << "Content-Transfer-Encoding: binary\r\n"
|
|
head << "\r\n"
|
|
Google::Apis::Core::CompositeIO.new(StringIO.new(head), @io, StringIO.new("\r\n"))
|
|
end
|
|
end
|
|
|
|
# Helper for building multipart requests
|
|
class Multipart
|
|
MULTIPART_RELATED = 'multipart/related'
|
|
|
|
# @return [String]
|
|
# Content type header
|
|
attr_reader :content_type
|
|
|
|
# @param [String] content_type
|
|
# Content type for the multipart request
|
|
# @param [String] boundary
|
|
# Part delimiter
|
|
|
|
def initialize(content_type: MULTIPART_RELATED, boundary: nil)
|
|
@parts = []
|
|
@boundary = boundary || Digest::SHA1.hexdigest(SecureRandom.random_bytes(8))
|
|
@content_type = "#{content_type}; boundary=#{@boundary}"
|
|
end
|
|
|
|
# Append JSON data part
|
|
#
|
|
# @param [String] body
|
|
# JSON text
|
|
# @param [String] content_id
|
|
# Optional unique ID of this part
|
|
# @return [self]
|
|
def add_json(body, content_id: nil)
|
|
header = {}
|
|
header['Content-ID'] = content_id unless content_id.nil?
|
|
@parts << Google::Apis::Core::JsonPart.new(body, header).to_io(@boundary)
|
|
self
|
|
end
|
|
|
|
# Append arbitrary data as a part
|
|
#
|
|
# @param [IO] upload_io
|
|
# IO stream
|
|
# @param [String] content_id
|
|
# Optional unique ID of this part
|
|
# @return [self]
|
|
def add_upload(upload_io, content_type: nil, content_id: nil)
|
|
header = {
|
|
'Content-Type' => content_type || 'application/octet-stream'
|
|
}
|
|
header['Content-Id'] = content_id unless content_id.nil?
|
|
@parts << Google::Apis::Core::FilePart.new(upload_io,
|
|
header).to_io(@boundary)
|
|
self
|
|
end
|
|
|
|
# Assemble the multipart requests
|
|
#
|
|
# @return [IO]
|
|
# IO stream
|
|
def assemble
|
|
@parts << StringIO.new("--#{@boundary}--\r\n\r\n")
|
|
Google::Apis::Core::CompositeIO.new(*@parts)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end |