class Aws::Plugins::ChecksumAlgorithm::AwsChunkedTrailerDigestIO

chunking with Digest computed on chunks + added as a trailer
Wrapper for request body that implements application-layer

def initialize(io, algorithm, location_name)

def initialize(io, algorithm, location_name)
  @io = io
  @location_name = location_name
  @algorithm = algorithm
  @digest = ChecksumAlgorithm.digest_for_algorithm(algorithm)
  @trailer_io = nil
end

def read(length, buf = nil)

def read(length, buf = nil)
  # account for possible leftover bytes at the end, if we have trailer bytes, send them
  if @trailer_io
    return @trailer_io.read(length, buf)
  end
  chunk = @io.read(length)
  if chunk
    @digest.update(chunk)
    application_chunked = "#{chunk.bytesize.to_s(16)}\r\n#{chunk}\r\n"
    return StringIO.new(application_chunked).read(application_chunked.size, buf)
  else
    trailers = {}
    trailers[@location_name] = @digest.base64digest
    trailers = trailers.map { |k,v| "#{k}:#{v}"}.join("\r\n")
    @trailer_io = StringIO.new("0\r\n#{trailers}\r\n\r\n")
    chunk = @trailer_io.read(length, buf)
  end
  chunk
end

def rewind

def rewind
  @io.rewind
end

def size

the size of the application layer aws-chunked + trailer body
def size
  # compute the number of chunks
  # a full chunk has 4 + 4 bytes overhead, a partial chunk is len.to_s(16).size + 4
  orig_body_size = @io.size
  n_full_chunks = orig_body_size / CHUNK_SIZE
  partial_bytes = orig_body_size % CHUNK_SIZE
  chunked_body_size = n_full_chunks * (CHUNK_SIZE + 8)
  chunked_body_size += partial_bytes.to_s(16).size + partial_bytes + 4 unless  partial_bytes.zero?
  trailer_size = ChecksumAlgorithm.trailer_length(@algorithm, @location_name)
  chunked_body_size + trailer_size
end