class Aws::Plugins::ChecksumAlgorithm::ChecksumHandler

@api private

Public Instance Methods

call(context) click to toggle source
# File lib/aws-sdk-core/plugins/checksum_algorithm.rb, line 118
def call(context)
  if should_calculate_request_checksum?(context)
    request_algorithm_input = ChecksumAlgorithm.request_algorithm_selection(context) ||
                              context[:default_request_checksum_algorithm]
    context[:checksum_algorithms] = request_algorithm_input

    request_checksum_property = {
      'algorithm' => request_algorithm_input,
      'in' => checksum_request_in(context),
      'name' => "x-amz-checksum-#{request_algorithm_input.downcase}"
    }

    calculate_request_checksum(context, request_checksum_property)
  end

  if should_verify_response_checksum?(context)
    add_verify_response_checksum_handlers(context)
  end

  @handler.call(context)
end

Private Instance Methods

add_verify_response_checksum_handlers(context) click to toggle source

Add events to the http_response to verify the checksum as its read This prevents the body from being read multiple times verification is done only once a successful response has completed

# File lib/aws-sdk-core/plugins/checksum_algorithm.rb, line 194
def add_verify_response_checksum_handlers(context)
  http_response = context.http_response
  checksum_context = { }
  http_response.on_headers do |_status, headers|
    header_name, algorithm = response_header_to_verify(headers, context[:http_checksum][:validation_list])
    if header_name
      expected = headers[header_name]

      unless context[:http_checksum][:skip_on_suffix] && /-[\d]+$/.match(expected)
        checksum_context[:algorithm] = algorithm
        checksum_context[:header_name] = header_name
        checksum_context[:digest] = ChecksumAlgorithm.digest_for_algorithm(algorithm)
        checksum_context[:expected] = expected
      end
    end
  end

  http_response.on_data do |chunk|
    checksum_context[:digest].update(chunk) if checksum_context[:digest]
  end

  http_response.on_success do
    if checksum_context[:digest] &&
      (computed = checksum_context[:digest].base64digest)

      if computed != checksum_context[:expected]
        raise Aws::Errors::ChecksumError,
              "Checksum validation failed on #{checksum_context[:header_name]} "\
              "computed: #{computed}, expected: #{checksum_context[:expected]}"
      end

      context[:http_checksum][:validated] = checksum_context[:algorithm]
    end
  end
end
apply_request_trailer_checksum(context, checksum_properties) click to toggle source
# File lib/aws-sdk-core/plugins/checksum_algorithm.rb, line 166
def apply_request_trailer_checksum(context, checksum_properties)
  location_name = checksum_properties['name']

  # set required headers
  headers = context.http_request.headers
  headers['Content-Encoding'] = 'aws-chunked'
  headers['X-Amz-Content-Sha256'] = 'STREAMING-UNSIGNED-PAYLOAD-TRAILER'
  headers['X-Amz-Trailer'] = location_name

  # We currently always compute the size in the modified body wrapper - allowing us
  # to set the Content-Length header (set by content_length plugin).
  # This means we cannot use Transfer-Encoding=chunked

  if !context.http_request.body.respond_to?(:size)
    raise Aws::Errors::ChecksumError, 'Could not determine length of the body'
  end
  headers['X-Amz-Decoded-Content-Length'] = context.http_request.body.size

  context.http_request.body = AwsChunkedTrailerDigestIO.new(
    context.http_request.body,
    checksum_properties['algorithm'],
    location_name
  )
end
calculate_request_checksum(context, checksum_properties) click to toggle source
# File lib/aws-sdk-core/plugins/checksum_algorithm.rb, line 152
def calculate_request_checksum(context, checksum_properties)
  case checksum_properties['in']
  when 'header'
    header_name = checksum_properties['name']
    body = context.http_request.body_contents
    if body
      context.http_request.headers[header_name] ||=
        ChecksumAlgorithm.calculate_checksum(checksum_properties['algorithm'], body)
    end
  when 'trailer'
    apply_request_trailer_checksum(context, checksum_properties)
  end
end
checksum_request_in(context) click to toggle source

determine where (header vs trailer) a request checksum should be added

# File lib/aws-sdk-core/plugins/checksum_algorithm.rb, line 240
def checksum_request_in(context)
  if context.operation['unsignedPayload'] ||
     context.operation['authtype'] == 'v4-unsigned-body'
    'trailer'
  else
    'header'
  end
end
response_header_to_verify(headers, validation_list) click to toggle source

returns nil if no headers to verify

# File lib/aws-sdk-core/plugins/checksum_algorithm.rb, line 231
def response_header_to_verify(headers, validation_list)
  validation_list.each do |algorithm|
    header_name = "x-amz-checksum-#{algorithm}"
    return [header_name, algorithm] if headers[header_name]
  end
  nil
end
should_calculate_request_checksum?(context) click to toggle source
# File lib/aws-sdk-core/plugins/checksum_algorithm.rb, line 142
def should_calculate_request_checksum?(context)
  context.operation.http_checksum &&
    (ChecksumAlgorithm.request_algorithm_selection(context) ||
      context[:default_request_checksum_algorithm])
end
should_verify_response_checksum?(context) click to toggle source
# File lib/aws-sdk-core/plugins/checksum_algorithm.rb, line 148
def should_verify_response_checksum?(context)
  context[:http_checksum][:validation_list] && !context[:http_checksum][:validation_list].empty?
end