File: error_handler.rb

package info (click to toggle)
ruby-aws-sdk-core 3.212.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,232 kB
  • sloc: ruby: 17,533; makefile: 4
file content (85 lines) | stat: -rw-r--r-- 2,659 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# frozen_string_literal: true

module Aws
  module RpcV2
    class ErrorHandler < Aws::ErrorHandler

      def call(context)
        # Malformed responses should throw an http based error, so we check
        # 200 range for error handling only for this case.
        @handler.call(context).on(200..599) do |response|
          if !valid_response?(context)
            code, message, data = http_status_error(context)
            response.error = build_error(context, code, message, data)
          elsif (300..599).cover?(context.http_response.status_code)
            response.error = error(context)
          end
          response.data = nil
        end
      end

      private

      def valid_response?(context)
        req_header = context.http_request.headers['smithy-protocol']
        resp_header = context.http_response.headers['smithy-protocol']
        req_header == resp_header
      end

      def extract_error(body, context)
        data = RpcV2.decode(body)
        code = error_code(data, context)
        message = data['message']
        data = parse_error_data(context, body, code)
        [code, message, data]
      rescue Cbor::Error
        [http_status_error_code(context), '', EmptyStructure.new]
      end

      def error_code(data, context)
        code =
          if aws_query_error?(context)
            query_header = context.http_response.headers['x-amzn-query-error']
            error, _type = query_header.split(';') # type not supported
            remove_prefix(error, context)
          else
            data['__type']
          end
        if code
          code.split('#').last
        else
          http_status_error_code(context)
        end
      end

      def parse_error_data(context, body, code)
        data = EmptyStructure.new
        if (error_rules = context.operation.errors)
          error_rules.each do |rule|
            # match modeled shape name with the type(code) only
            # some type(code) might contains invalid characters
            # such as ':' (efs) etc
            match = rule.shape.name == code.gsub(/[^^a-zA-Z0-9]/, '')
            next unless match && rule.shape.members.any?

            data = Parser.new(rule).parse(body)
          end
        end
        data
      end

      def aws_query_error?(context)
        context.config.api.metadata['awsQueryCompatible'] &&
          context.http_response.headers['x-amzn-query-error']
      end

      def remove_prefix(error_code, context)
        if (prefix = context.config.api.metadata['errorPrefix'])
          error_code.sub(/^#{prefix}/, '')
        else
          error_code
        end
      end
    end
  end
end