rest-client--rest-client/lib/restclient/exceptions.rb

270 lines
8.9 KiB
Ruby

module RestClient
# Hash of HTTP status code => message.
#
# ### HTTP status code families:
#
# - 1xx: Informational --- Request received, continuing process
# - 2xx: Success --- The action was successfully received, understood, and
# accepted
# - 3xx: Redirection --- Further action must be taken in order to complete
# the request
# - 4xx: Client Error --- The request contains bad syntax or cannot be
# fulfilled
# - 5xx: Server Error --- The server failed to fulfill an apparently valid
# request
#
# This hash is used to populate all of the individual response exception
# classes, which are collected in {RestClient::Exceptions::EXCEPTIONS_MAP}.
#
# @see
# http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
#
# **TODO:** Move these out of the top-level namespace and into {Exceptions}.
#
STATUSES = {100 => 'Continue',
101 => 'Switching Protocols',
102 => 'Processing', #WebDAV
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative Information', # http/1.1
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
207 => 'Multi-Status', #WebDAV
208 => 'Already Reported', # RFC5842
226 => 'IM Used', # RFC3229
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other', # http/1.1
304 => 'Not Modified',
305 => 'Use Proxy', # http/1.1
306 => 'Switch Proxy', # no longer used
307 => 'Temporary Redirect', # http/1.1
308 => 'Permanent Redirect', # RFC7538
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Timeout',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Payload Too Large', # RFC7231 (renamed, see below)
414 => 'URI Too Long', # RFC7231 (renamed, see below)
415 => 'Unsupported Media Type',
416 => 'Range Not Satisfiable', # RFC7233 (renamed, see below)
417 => 'Expectation Failed',
418 => 'I\'m A Teapot', #RFC2324
421 => 'Too Many Connections From This IP',
422 => 'Unprocessable Entity', #WebDAV
423 => 'Locked', #WebDAV
424 => 'Failed Dependency', #WebDAV
425 => 'Unordered Collection', #WebDAV
426 => 'Upgrade Required',
428 => 'Precondition Required', #RFC6585
429 => 'Too Many Requests', #RFC6585
431 => 'Request Header Fields Too Large', #RFC6585
449 => 'Retry With', #Microsoft
450 => 'Blocked By Windows Parental Controls', #Microsoft
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Timeout',
505 => 'HTTP Version Not Supported',
506 => 'Variant Also Negotiates',
507 => 'Insufficient Storage', #WebDAV
508 => 'Loop Detected', # RFC5842
509 => 'Bandwidth Limit Exceeded', #Apache
510 => 'Not Extended',
511 => 'Network Authentication Required', # RFC6585
}
# This Hash contains a mapping of aliases for the canonical HTTP status code
# classes that are preserved for backwards compatibility. For example,
# `RestClient::ResourceNotFound` is an alias for `RestClient::NotFound`.
#
# **TODO:** Move this out of the top-level namespace and into {Exceptions}.
STATUSES_COMPATIBILITY = {
# The RFCs all specify "Not Found", but "Resource Not Found" was used in
# earlier RestClient releases.
404 => ['ResourceNotFound'],
# HTTP 413 was renamed to "Payload Too Large" in RFC7231.
413 => ['RequestEntityTooLarge'],
# HTTP 414 was renamed to "URI Too Long" in RFC7231.
414 => ['RequestURITooLong'],
# HTTP 416 was renamed to "Range Not Satisfiable" in RFC7233.
416 => ['RequestedRangeNotSatisfiable'],
}
# This is the base RestClient exception class. Rescue it if you want to
# catch any exception that your request might raise. Note that the underlying
# network and socket libraries may raise other exceptions.
#
# You can get the status code with {#http_code}, or see anything about the
# response via {#response}.
#
# For more detailed information from the response, just call the
# corresponding methods on the response object (e.g. `e.response.history`).
#
class Exception < RuntimeError
attr_accessor :response
attr_accessor :original_exception
attr_writer :message
# @param response [RestClient::Response, RestClient::RawResponse]
#
def initialize response = nil, initial_response_code = nil
@response = response
@message = nil
@initial_response_code = initial_response_code
end
def http_code
# return integer for compatibility
if @response
@response.code.to_i
else
@initial_response_code
end
end
# @see Response#headers
# @return [Hash, nil]
def http_headers
@response.headers if @response
end
# @see Response#body
# @return [String, nil]
def http_body
@response.body if @response
end
def to_s
message
end
def message
@message || default_message
end
def default_message
self.class.name
end
end
# Compatibility
class ExceptionWithResponse < Exception
end
# The request failed with an error code not managed by the code
class RequestFailed < ExceptionWithResponse
def default_message
"HTTP status code #{http_code}"
end
def to_s
message
end
end
# RestClient exception classes. TODO: move all exceptions into this module.
#
# We will a create an exception for each status code, see
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
#
module Exceptions
# Map http status codes to the corresponding exception class.
# This Hash is populated when the library is loaded, so values won't appear
# in the YARD documentation.
EXCEPTIONS_MAP = {}
end
# Create HTTP status exception classes
STATUSES.each_pair do |code, message|
klass = Class.new(RequestFailed) do
send(:define_method, :default_message) {"#{http_code ? "#{http_code} " : ''}#{message}"}
end
klass_constant = const_set(message.delete(' \-\''), klass)
Exceptions::EXCEPTIONS_MAP[code] = klass_constant
end
# Create HTTP status exception classes used for backwards compatibility
STATUSES_COMPATIBILITY.each_pair do |code, compat_list|
klass = Exceptions::EXCEPTIONS_MAP.fetch(code)
compat_list.each do |old_name|
const_set(old_name, klass)
end
end
module Exceptions
# We have to split the Exceptions module like we do here because the
# EXCEPTIONS_MAP is under Exceptions, but we depend on
# RestClient::RequestTimeout below.
# Base class for request timeouts.
#
# NB: Previous releases of rest-client would raise RequestTimeout both for
# HTTP 408 responses and for actual connection timeouts.
class Timeout < RestClient::RequestTimeout
def initialize(message=nil, original_exception=nil)
super(nil, nil)
self.message = message if message
self.original_exception = original_exception if original_exception
end
end
# Timeout when connecting to a server. Typically wraps Net::OpenTimeout (in
# ruby 2.0 or greater).
class OpenTimeout < Timeout
def default_message
'Timed out connecting to server'
end
end
# Timeout when reading from a server. Typically wraps Net::ReadTimeout (in
# ruby 2.0 or greater).
class ReadTimeout < Timeout
def default_message
'Timed out reading data from server'
end
end
end
# The server broke the connection prior to the request completing. Usually
# this means it crashed, or sometimes that your network connection was
# severed before it could complete.
class ServerBrokeConnection < Exception
def initialize(message = 'Server broke connection')
super nil, nil
self.message = message
end
end
class SSLCertificateNotVerified < Exception
def initialize(message = 'SSL certificate not verified')
super nil, nil
self.message = message
end
end
end