File: error.rb

package info (click to toggle)
ruby-excon 1.3.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,240 kB
  • sloc: ruby: 7,970; makefile: 5
file content (229 lines) | stat: -rw-r--r-- 9,470 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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# frozen_string_literal: true
module Excon
  # Excon exception classes
  class Error < StandardError
    @default_status_error = :HTTPStatus

    class StubNotFound < Error; end
    class InvalidStub < Error; end
    class Warning < Error; end

    # Socket related errors
    class Socket < Error
      attr_reader :socket_error

      def initialize(socket_error = Excon::Error.new)
        if is_a?(Certificate) || is_a?(Excon::Errors::CertificateError)
          super
        else
          super("#{socket_error.message} (#{socket_error.class})")
          set_backtrace(socket_error.backtrace)
          @socket_error = socket_error
        end
      end
    end

    # Certificate related errors
    class Certificate < Socket
      def initialize(socket_error = Excon::Error.new)
        msg = <<-EOL
Unable to verify certificate. This may be an issue with the remote host or with Excon. Excon has certificates bundled, but these can be customized:

            `Excon.defaults[:ssl_ca_path] = path_to_certs`
            `ENV['SSL_CERT_DIR'] = path_to_certs`
            `Excon.defaults[:ssl_ca_file] = path_to_file`
            `ENV['SSL_CERT_FILE'] = path_to_file`
            `Excon.defaults[:ssl_verify_callback] = callback`
                (see OpenSSL::SSL::SSLContext#verify_callback)
or:
            `Excon.defaults[:ssl_verify_peer] = false` (less secure).
        EOL
        full_message = "#{socket_error.message} (#{socket_error.class})" +
                       ' ' + msg
        super(full_message)
        set_backtrace(socket_error.backtrace)
        @socket_error = socket_error
      end
    end

    class InvalidHeaderKey < Error; end
    class InvalidHeaderValue < Error; end
    class Timeout < Error; end
    class ResponseParse < Error; end

    class ProxyConnectionError < Error
      attr_reader :request, :response

      def initialize(msg, request = nil, response = nil)
        super(msg)
        @request = request
        @response = response
      end
    end

    class ProxyParse < Error; end
    class TooManyRedirects < Error; end

    # Base class for HTTP Error classes
    class HTTPStatus < Error
      attr_reader :request, :response

      def initialize(msg, request = nil, response = nil)
        super(msg)
        @request = request
        @response = response
      end
    end

    # HTTP Error classes
    class Informational < HTTPStatus; end
    class Success < HTTPStatus; end
    class Redirection < HTTPStatus; end
    class Client < HTTPStatus; end
    class Server < HTTPStatus; end

    class Continue < Informational; end                  # 100
    class SwitchingProtocols < Informational; end        # 101
    class OK < Success; end                              # 200
    class Created < Success; end                         # 201
    class Accepted < Success; end                        # 202
    class NonAuthoritativeInformation < Success; end     # 203
    class NoContent < Success; end                       # 204
    class ResetContent < Success; end                    # 205
    class PartialContent < Success; end                  # 206
    class MultipleChoices < Redirection; end             # 300
    class MovedPermanently < Redirection; end            # 301
    class Found < Redirection; end                       # 302
    class SeeOther < Redirection; end                    # 303
    class NotModified < Redirection; end                 # 304
    class UseProxy < Redirection; end                    # 305
    class TemporaryRedirect < Redirection; end           # 307
    class BadRequest < Client; end                       # 400
    class Unauthorized < Client; end                     # 401
    class PaymentRequired < Client; end                  # 402
    class Forbidden < Client; end                        # 403
    class NotFound < Client; end                         # 404
    class MethodNotAllowed < Client; end                 # 405
    class NotAcceptable < Client; end                    # 406
    class ProxyAuthenticationRequired < Client; end      # 407
    class RequestTimeout < Client; end                   # 408
    class Conflict < Client; end                         # 409
    class Gone < Client; end                             # 410
    class LengthRequired < Client; end                   # 411
    class PreconditionFailed < Client; end               # 412
    class RequestEntityTooLarge < Client; end            # 413
    class RequestURITooLong < Client; end                # 414
    class UnsupportedMediaType < Client; end             # 415
    class RequestedRangeNotSatisfiable < Client; end     # 416
    class ExpectationFailed < Client; end                # 417
    class UnprocessableEntity < Client; end              # 422
    class TooManyRequests < Client; end                  # 429
    class InternalServerError < Server; end              # 500
    class NotImplemented < Server; end                   # 501
    class BadGateway < Server; end                       # 502
    class ServiceUnavailable < Server; end               # 503
    class GatewayTimeout < Server; end                   # 504

    def self.status_errors
      @status_errors ||= {
        100 => [Excon::Error::Continue, 'Continue'],
        101 => [Excon::Error::SwitchingProtocols, 'Switching Protocols'],
        200 => [Excon::Error::OK, 'OK'],
        201 => [Excon::Error::Created, 'Created'],
        202 => [Excon::Error::Accepted, 'Accepted'],
        203 => [Excon::Error::NonAuthoritativeInformation, 'Non-Authoritative Information'],
        204 => [Excon::Error::NoContent, 'No Content'],
        205 => [Excon::Error::ResetContent, 'Reset Content'],
        206 => [Excon::Error::PartialContent, 'Partial Content'],
        300 => [Excon::Error::MultipleChoices, 'Multiple Choices'],
        301 => [Excon::Error::MovedPermanently, 'Moved Permanently'],
        302 => [Excon::Error::Found, 'Found'],
        303 => [Excon::Error::SeeOther, 'See Other'],
        304 => [Excon::Error::NotModified, 'Not Modified'],
        305 => [Excon::Error::UseProxy, 'Use Proxy'],
        307 => [Excon::Error::TemporaryRedirect, 'Temporary Redirect'],
        400 => [Excon::Error::BadRequest, 'Bad Request'],
        401 => [Excon::Error::Unauthorized, 'Unauthorized'],
        402 => [Excon::Error::PaymentRequired, 'Payment Required'],
        403 => [Excon::Error::Forbidden, 'Forbidden'],
        404 => [Excon::Error::NotFound, 'Not Found'],
        405 => [Excon::Error::MethodNotAllowed, 'Method Not Allowed'],
        406 => [Excon::Error::NotAcceptable, 'Not Acceptable'],
        407 => [Excon::Error::ProxyAuthenticationRequired, 'Proxy Authentication Required'],
        408 => [Excon::Error::RequestTimeout, 'Request Timeout'],
        409 => [Excon::Error::Conflict, 'Conflict'],
        410 => [Excon::Error::Gone, 'Gone'],
        411 => [Excon::Error::LengthRequired, 'Length Required'],
        412 => [Excon::Error::PreconditionFailed, 'Precondition Failed'],
        413 => [Excon::Error::RequestEntityTooLarge, 'Request Entity Too Large'],
        414 => [Excon::Error::RequestURITooLong, 'Request-URI Too Long'],
        415 => [Excon::Error::UnsupportedMediaType, 'Unsupported Media Type'],
        416 => [Excon::Error::RequestedRangeNotSatisfiable, 'Request Range Not Satisfiable'],
        417 => [Excon::Error::ExpectationFailed, 'Expectation Failed'],
        422 => [Excon::Error::UnprocessableEntity, 'Unprocessable Entity'],
        429 => [Excon::Error::TooManyRequests, 'Too Many Requests'],
        500 => [Excon::Error::InternalServerError, 'InternalServerError'],
        501 => [Excon::Error::NotImplemented, 'Not Implemented'],
        502 => [Excon::Error::BadGateway, 'Bad Gateway'],
        503 => [Excon::Error::ServiceUnavailable, 'Service Unavailable'],
        504 => [Excon::Error::GatewayTimeout, 'Gateway Timeout']
      }
    end

    # Messages for nicer exceptions, from rfc2616
    def self.status_error(request, response)
      error_class, error_message = status_errors[response[:status]]
      if error_class.nil?
        default_class = Excon::Error.const_get(@default_status_error)
        error_class, error_message = [default_class, 'Unknown']
      end
      message = StringIO.new
      str = "Expected(#{request[:expects].inspect}) <=>" +
            " Actual(#{response[:status]} #{error_message})"
      message.puts(str)
      if request[:debug_request]
        message.puts('excon.error.request')
        Excon::PrettyPrinter.pp(message, request)
      end

      if request[:debug_response]
        message.puts('excon.error.response')
        Excon::PrettyPrinter.pp(message, response.data)
      end
      message.rewind
      error_class.new(message.read, request, response)
    end
  end

  # Legacy
  module Errors
    Excon::Errors::Error = Excon::Error

    legacy_re = /
      \A
      Client
      |Server
      |Socket
      |Certificate
      |HTTPStatus
      |InternalServer
      \Z
    /x

    klasses = Excon::Error.constants.select do |c|
      Excon::Error.const_get(c).is_a? Class
    end

    klasses.each do |klass|
      class_name = klass.to_s
      unless class_name.match?(/Error\Z/)
        class_name = klass.to_s + 'Error' if class_name.match?(legacy_re)
      end
      Excon::Errors.const_set(class_name, Excon::Error.const_get(klass))
    end

    def self.status_error(request, response)
      Excon::Error.status_error(request, response)
    end
  end
end