class AWS::Core::Signers::Version4::ChunkSignedStream

Constants

CHUNK_SIGNATURE_HEADER

@api private

CHUNK_STRING_TO_SIGN_PREFIX

@api private

CLRF

@api private

DEFAULT_CHUNK_SIZE

@api private

MAX_BUFFER_SIZE

@api private

SIGNATURE_LENGTH

@api private

Attributes

size[R]

@return [Integer] the size of the final (signed) stream

Public Class Methods

new(stream, stream_size, key, key_path, datetime, signature) click to toggle source

@param [IO] stream The original http request body stream. @param [Integer] stream_size Size of the original stream in bytes.

This must be greater than 0.

@param [String] key The derived sigv4 signing key. @param [String] key_path The scope of the derived key. @param [String] datetime The iso8601 formatted datetime. @param [String] signature The computed signature of the request headers. @return [IO] Returns an IO-like object.

# File lib/aws/core/signers/version_4/chunk_signed_stream.rb, line 48
def initialize stream, stream_size, key, key_path, datetime, signature
  @stream = stream || StringIO.new('')
  @size = self.class.signed_size(stream_size)
  @key = key
  @key_path = key_path
  @datetime = datetime
  @prev_chunk_signature = signature
  reset
end

Private Class Methods

header_length(size) click to toggle source

Computes the size of a header that prefixes a chunk. The size appears in the header as a string. @param [Integer] size @return [Integer]

# File lib/aws/core/signers/version_4/chunk_signed_stream.rb, line 177
def header_length size
  size.to_s(16).length +
  CHUNK_SIGNATURE_HEADER.length +
  SIGNATURE_LENGTH +
  CLRF.length +
  size +
  CLRF.length
end
signed_size(size) click to toggle source

Computes the final size of a chunked signed stream. @param [Integer] size Size of the original, unsigned stream. @return [Integer]

# File lib/aws/core/signers/version_4/chunk_signed_stream.rb, line 161
def signed_size size
  full_sized_chunks = size / DEFAULT_CHUNK_SIZE
  trailing_bytes = size % DEFAULT_CHUNK_SIZE
  length = 0
  length += full_sized_chunks * header_length(DEFAULT_CHUNK_SIZE)
  length += trailing_bytes > 0 ? header_length(trailing_bytes) : 0
  length += header_length(0)
  length
end

Public Instance Methods

read(bytes = nil, output_buffer = nil) click to toggle source

@param [Integer] bytes (nil) @param [String] output_buffer (nil) @return [String,nil]

# File lib/aws/core/signers/version_4/chunk_signed_stream.rb, line 64
def read bytes = nil, output_buffer = nil
  data = read_bytes(bytes || @size)
  if output_buffer
    output_buffer.replace(data || '')
  else
    (data.nil? and bytes.nil?) ? '' : data
  end
end
rewind() click to toggle source

@return [Integer]

# File lib/aws/core/signers/version_4/chunk_signed_stream.rb, line 74
def rewind
  @stream.rewind
  reset
end

Private Instance Methods

fill_buffer(num_bytes) click to toggle source

Fills the internal buffer at least num_bytes of data. @param [Integer] num_bytes

# File lib/aws/core/signers/version_4/chunk_signed_stream.rb, line 97
def fill_buffer num_bytes
  while @buffer.bytesize < num_bytes && more_chunks?
    @buffer << next_chunk
  end
end
hash(value) click to toggle source
# File lib/aws/core/signers/version_4/chunk_signed_stream.rb, line 152
def hash value
  OpenSSL::Digest::SHA256.new.update(value).hexdigest
end
more_chunks?() click to toggle source
# File lib/aws/core/signers/version_4/chunk_signed_stream.rb, line 103
def more_chunks?
  @more_chunks
end
next_chunk() click to toggle source
# File lib/aws/core/signers/version_4/chunk_signed_stream.rb, line 107
def next_chunk
  chunk = @stream.read(DEFAULT_CHUNK_SIZE)
  if chunk.nil?
    chunk = ''
    @more_chunks = false
  end
  sign_chunk(chunk)
end
next_chunk_signature(chunk) click to toggle source

@param [String] chunk @return [String]

# File lib/aws/core/signers/version_4/chunk_signed_stream.rb, line 133
def next_chunk_signature chunk
  string_to_sign = [
    "AWS4-HMAC-SHA256-PAYLOAD",
    @datetime,
    @key_path,
    @prev_chunk_signature,
    hash(''),
    hash(chunk),
  ].join("\n")
  signature = sign(string_to_sign)
  @prev_chunk_signature = signature
  signature
end
read_bytes(num_bytes) click to toggle source

@param [Integer] num_bytes The maximum number of bytes to return. @return [String,nil] `nil` once the complete stream has been read

# File lib/aws/core/signers/version_4/chunk_signed_stream.rb, line 88
def read_bytes num_bytes
  fill_buffer(num_bytes)
  bytes = @buffer[0,num_bytes]
  @buffer = @buffer[num_bytes..-1] || '' # flatten the buffer
  bytes == '' ? nil : bytes
end
reset() click to toggle source
# File lib/aws/core/signers/version_4/chunk_signed_stream.rb, line 81
def reset
  @buffer = ''
  @more_chunks = true
end
sign(value) click to toggle source
# File lib/aws/core/signers/version_4/chunk_signed_stream.rb, line 147
def sign value
  @digest ||= OpenSSL::Digest.new('sha256')
  OpenSSL::HMAC.hexdigest(@digest, @key, value)
end
sign_chunk(chunk) click to toggle source

Given a chunk of the original stream, this method returns a signed chunk with the prefixed header. @param [String] chunk @return [String]

# File lib/aws/core/signers/version_4/chunk_signed_stream.rb, line 120
def sign_chunk chunk
  [
    chunk.bytesize.to_s(16),
    CHUNK_SIGNATURE_HEADER,
    next_chunk_signature(chunk),
    CLRF,
    chunk,
    CLRF,
  ].join
end