class Aws::Plugins::ChecksumAlgorithm::ChecksumHandler
@api private
def add_verify_response_checksum_handlers(context)
This prevents the body from being read multiple times
Add events to the http_response to verify the checksum as its read
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
def apply_request_trailer_checksum(context, checksum_properties)
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
def calculate_request_checksum(context, checksum_properties)
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
def call(context)
def call(context) if should_calculate_request_checksum?(context) request_algorithm_input = ChecksumAlgorithm.request_algorithm_selection(context) 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
def checksum_request_in(context)
def checksum_request_in(context) if context.operation['authtype'].eql?('v4-unsigned-body') 'trailer' else 'header' end end
def response_header_to_verify(headers, validation_list)
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
def should_calculate_request_checksum?(context)
def should_calculate_request_checksum?(context) context.operation.http_checksum && ChecksumAlgorithm.request_algorithm_selection(context) end
def should_verify_response_checksum?(context)
def should_verify_response_checksum?(context) context[:http_checksum][:validation_list] && !context[:http_checksum][:validation_list].empty? end