class Google::Apis::Core::StorageUploadCommand

Base upload command. Not intended to be used directly @private

Constants

CHUNK_SIZE
CONTENT_LENGTH_HEADER
CONTENT_RANGE_HEADER
CONTENT_TYPE_HEADER
LOCATION_HEADER
OK_STATUS
RESUMABLE
UPLOAD_CONTENT_TYPE_HEADER

Attributes

upload_content_type[RW]

Content type of the upload material @return [String]

upload_io[RW]

Content, as UploadIO @return [Google::Apis::Core::UploadIO]

upload_source[RW]

File name or IO containing the content to upload @return [String, File, read]

Public Instance Methods

execute(client) click to toggle source

Execute the command, retrying as necessary

@param [HTTPClient] client

HTTP client

@yield [result, err] Result or error if block supplied @return [Object] @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification @raise [Google::Apis::AuthorizationError] Authorization is required

# File lib/google/apis/core/storage_upload.rb, line 91
def execute(client)
  prepare!
  opencensus_begin_span

  do_retry :initiate_resumable_upload, client
  while @upload_incomplete
    res = do_retry :send_upload_command, client
  end
  res
ensure
  opencensus_end_span
  @http_res = nil
  release!
end
initiate_resumable_upload(client) click to toggle source
# File lib/google/apis/core/storage_upload.rb, line 106
def initiate_resumable_upload(client)
  logger.debug { sprintf('Intiating resumable upload command to %s', url) }

  request_header = header.dup
  apply_request_options(request_header)

  request_query = query.dup
  request_query['uploadType'] = RESUMABLE

  request_header[CONTENT_LENGTH_HEADER] = upload_io.size.to_s
  request_header[CONTENT_TYPE_HEADER] = JSON_CONTENT_TYPE
  request_header[UPLOAD_CONTENT_TYPE_HEADER] = upload_content_type unless upload_content_type.nil?

  response = client.post(url.to_s, query: request_query,
                 body: body,
                 header: request_header,
                 follow_redirect: true)
  result = process_response(response.status_code, response.header, response.body)
  success(result)
rescue => e
  error(e, rethrow: true)
end
prepare!() click to toggle source

Ensure the content is readable and wrapped in an IO instance.

@return [void] @raise [Google::Apis::ClientError] if upload source is invalid

Calls superclass method Google::Apis::Core::ApiCommand#prepare!
# File lib/google/apis/core/storage_upload.rb, line 52
def prepare!
  @upload_url = nil
  @offset = 0
  @upload_incomplete = true
  # Prevent the command from populating the body with form encoding, by
  # asserting that it already has a body. Form encoding is never used
  # by upload requests.
  self.body = '' unless self.body

  super
  if streamable?(upload_source)
    self.upload_io = upload_source
    @close_io_on_finish = false
  elsif self.upload_source.is_a?(String)
    self.upload_io = File.new(upload_source, 'r')
    if self.upload_content_type.nil?
      type = MiniMime.lookup_by_filename(upload_source)
      self.upload_content_type = type&.content_type
    end
    @close_io_on_finish = true
  else
    fail Google::Apis::ClientError, 'Invalid upload source'
  end
end
process_response(status, header, body) click to toggle source

Check the to see if the upload is complete or needs to be resumed.

@param [Integer] status

HTTP status code of response

@param [HTTP::Message::Headers] header

Response headers

@param [String, read] body

Response body

@return [Object]

Response object

@raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification @raise [Google::Apis::AuthorizationError] Authorization is required

Calls superclass method
# File lib/google/apis/core/storage_upload.rb, line 170
def process_response(status, header, body)
  @upload_url = header[LOCATION_HEADER].first unless header[LOCATION_HEADER].empty?
  super(status, header, body)
end
release!() click to toggle source

Close IO stream when command done. Only closes the stream if it was opened by the command.

# File lib/google/apis/core/storage_upload.rb, line 78
def release!
  upload_io.close if @close_io_on_finish
end
send_upload_command(client) click to toggle source

Send the actual content

@param [HTTPClient] client

HTTP client

@return [HTTP::Message] @raise [Google::Apis::ServerError] Unable to send the request

# File lib/google/apis/core/storage_upload.rb, line 135
def send_upload_command(client)
  logger.debug { sprintf('Sending upload command to %s', @upload_url) }

  remaining_content_size = upload_io.size - @offset
  current_chunk_size = remaining_content_size < CHUNK_SIZE ? remaining_content_size : CHUNK_SIZE

  request_header = header.dup
  request_header[CONTENT_RANGE_HEADER] = sprintf('bytes %d-%d/%d', @offset, @offset+current_chunk_size-1, upload_io.size)
  request_header[CONTENT_LENGTH_HEADER] = current_chunk_size
  chunk_body = upload_io.read(current_chunk_size)

  response = client.put(@upload_url, body: chunk_body, header: request_header, follow_redirect: true)

  result = process_response(response.status_code, response.header, response.body)
  @upload_incomplete = false if response.status_code.eql? OK_STATUS
  @offset += current_chunk_size if @upload_incomplete
  success(result)
rescue => e
  upload_io.pos = @offset
  error(e, rethrow: true)
end
streamable?(upload_source) click to toggle source
# File lib/google/apis/core/storage_upload.rb, line 175
def streamable?(upload_source)
  upload_source.is_a?(IO) || upload_source.is_a?(StringIO) || upload_source.is_a?(Tempfile)
end