rest-client 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.rspec +2 -0
  4. data/.rubocop-disables.yml +384 -0
  5. data/.rubocop.yml +3 -0
  6. data/.travis.yml +48 -0
  7. data/AUTHORS +98 -0
  8. data/Gemfile +11 -0
  9. data/LICENSE +21 -0
  10. data/README.md +784 -0
  11. data/Rakefile +132 -0
  12. data/bin/restclient +92 -0
  13. data/history.md +324 -0
  14. data/lib/rest-client.rb +2 -0
  15. data/lib/rest_client.rb +2 -0
  16. data/lib/restclient.rb +184 -0
  17. data/lib/restclient/abstract_response.rb +226 -0
  18. data/lib/restclient/exceptions.rb +244 -0
  19. data/lib/restclient/params_array.rb +72 -0
  20. data/lib/restclient/payload.rb +209 -0
  21. data/lib/restclient/platform.rb +49 -0
  22. data/lib/restclient/raw_response.rb +38 -0
  23. data/lib/restclient/request.rb +853 -0
  24. data/lib/restclient/resource.rb +168 -0
  25. data/lib/restclient/response.rb +80 -0
  26. data/lib/restclient/utils.rb +235 -0
  27. data/lib/restclient/version.rb +8 -0
  28. data/lib/restclient/windows.rb +8 -0
  29. data/lib/restclient/windows/root_certs.rb +105 -0
  30. data/rest-client.gemspec +31 -0
  31. data/rest-client.windows.gemspec +19 -0
  32. data/spec/helpers.rb +22 -0
  33. data/spec/integration/_lib.rb +1 -0
  34. data/spec/integration/capath_digicert/244b5494.0 +19 -0
  35. data/spec/integration/capath_digicert/81b9768f.0 +19 -0
  36. data/spec/integration/capath_digicert/README +8 -0
  37. data/spec/integration/capath_digicert/digicert.crt +19 -0
  38. data/spec/integration/capath_verisign/415660c1.0 +14 -0
  39. data/spec/integration/capath_verisign/7651b327.0 +14 -0
  40. data/spec/integration/capath_verisign/README +8 -0
  41. data/spec/integration/capath_verisign/verisign.crt +14 -0
  42. data/spec/integration/certs/digicert.crt +19 -0
  43. data/spec/integration/certs/verisign.crt +14 -0
  44. data/spec/integration/httpbin_spec.rb +87 -0
  45. data/spec/integration/integration_spec.rb +125 -0
  46. data/spec/integration/request_spec.rb +127 -0
  47. data/spec/spec_helper.rb +29 -0
  48. data/spec/unit/_lib.rb +1 -0
  49. data/spec/unit/abstract_response_spec.rb +145 -0
  50. data/spec/unit/exceptions_spec.rb +108 -0
  51. data/spec/unit/master_shake.jpg +0 -0
  52. data/spec/unit/params_array_spec.rb +36 -0
  53. data/spec/unit/payload_spec.rb +263 -0
  54. data/spec/unit/raw_response_spec.rb +18 -0
  55. data/spec/unit/request2_spec.rb +54 -0
  56. data/spec/unit/request_spec.rb +1250 -0
  57. data/spec/unit/resource_spec.rb +134 -0
  58. data/spec/unit/response_spec.rb +241 -0
  59. data/spec/unit/restclient_spec.rb +79 -0
  60. data/spec/unit/utils_spec.rb +147 -0
  61. data/spec/unit/windows/root_certs_spec.rb +22 -0
  62. metadata +282 -0
@@ -0,0 +1,2 @@
1
+ # More logical way to require 'rest-client'
2
+ require File.dirname(__FILE__) + '/restclient'
@@ -0,0 +1,2 @@
1
+ # This file exists for backward compatbility with require 'rest_client'
2
+ require File.dirname(__FILE__) + '/restclient'
@@ -0,0 +1,184 @@
1
+ require 'net/http'
2
+ require 'openssl'
3
+ require 'stringio'
4
+ require 'uri'
5
+ require 'zlib'
6
+
7
+ require File.dirname(__FILE__) + '/restclient/version'
8
+ require File.dirname(__FILE__) + '/restclient/platform'
9
+ require File.dirname(__FILE__) + '/restclient/exceptions'
10
+ require File.dirname(__FILE__) + '/restclient/utils'
11
+ require File.dirname(__FILE__) + '/restclient/request'
12
+ require File.dirname(__FILE__) + '/restclient/abstract_response'
13
+ require File.dirname(__FILE__) + '/restclient/response'
14
+ require File.dirname(__FILE__) + '/restclient/raw_response'
15
+ require File.dirname(__FILE__) + '/restclient/resource'
16
+ require File.dirname(__FILE__) + '/restclient/params_array'
17
+ require File.dirname(__FILE__) + '/restclient/payload'
18
+ require File.dirname(__FILE__) + '/restclient/windows'
19
+
20
+ # This module's static methods are the entry point for using the REST client.
21
+ #
22
+ # # GET
23
+ # xml = RestClient.get 'http://example.com/resource'
24
+ # jpg = RestClient.get 'http://example.com/resource', :accept => 'image/jpg'
25
+ #
26
+ # # authentication and SSL
27
+ # RestClient.get 'https://user:password@example.com/private/resource'
28
+ #
29
+ # # POST or PUT with a hash sends parameters as a urlencoded form body
30
+ # RestClient.post 'http://example.com/resource', :param1 => 'one'
31
+ #
32
+ # # nest hash parameters
33
+ # RestClient.post 'http://example.com/resource', :nested => { :param1 => 'one' }
34
+ #
35
+ # # POST and PUT with raw payloads
36
+ # RestClient.post 'http://example.com/resource', 'the post body', :content_type => 'text/plain'
37
+ # RestClient.post 'http://example.com/resource.xml', xml_doc
38
+ # RestClient.put 'http://example.com/resource.pdf', File.read('my.pdf'), :content_type => 'application/pdf'
39
+ #
40
+ # # DELETE
41
+ # RestClient.delete 'http://example.com/resource'
42
+ #
43
+ # # retreive the response http code and headers
44
+ # res = RestClient.get 'http://example.com/some.jpg'
45
+ # res.code # => 200
46
+ # res.headers[:content_type] # => 'image/jpg'
47
+ #
48
+ # # HEAD
49
+ # RestClient.head('http://example.com').headers
50
+ #
51
+ # To use with a proxy, just set RestClient.proxy to the proper http proxy:
52
+ #
53
+ # RestClient.proxy = "http://proxy.example.com/"
54
+ #
55
+ # Or inherit the proxy from the environment:
56
+ #
57
+ # RestClient.proxy = ENV['http_proxy']
58
+ #
59
+ # For live tests of RestClient, try using http://rest-test.heroku.com, which echoes back information about the rest call:
60
+ #
61
+ # >> RestClient.put 'http://rest-test.heroku.com/resource', :foo => 'baz'
62
+ # => "PUT http://rest-test.heroku.com/resource with a 7 byte payload, content type application/x-www-form-urlencoded {\"foo\"=>\"baz\"}"
63
+ #
64
+ module RestClient
65
+
66
+ def self.get(url, headers={}, &block)
67
+ Request.execute(:method => :get, :url => url, :headers => headers, &block)
68
+ end
69
+
70
+ def self.post(url, payload, headers={}, &block)
71
+ Request.execute(:method => :post, :url => url, :payload => payload, :headers => headers, &block)
72
+ end
73
+
74
+ def self.patch(url, payload, headers={}, &block)
75
+ Request.execute(:method => :patch, :url => url, :payload => payload, :headers => headers, &block)
76
+ end
77
+
78
+ def self.put(url, payload, headers={}, &block)
79
+ Request.execute(:method => :put, :url => url, :payload => payload, :headers => headers, &block)
80
+ end
81
+
82
+ def self.delete(url, headers={}, &block)
83
+ Request.execute(:method => :delete, :url => url, :headers => headers, &block)
84
+ end
85
+
86
+ def self.head(url, headers={}, &block)
87
+ Request.execute(:method => :head, :url => url, :headers => headers, &block)
88
+ end
89
+
90
+ def self.options(url, headers={}, &block)
91
+ Request.execute(:method => :options, :url => url, :headers => headers, &block)
92
+ end
93
+
94
+ # A global proxy URL to use for all requests. This can be overridden on a
95
+ # per-request basis by passing `:proxy` to RestClient::Request.
96
+ def self.proxy
97
+ @proxy ||= nil
98
+ end
99
+
100
+ def self.proxy=(value)
101
+ @proxy = value
102
+ @proxy_set = true
103
+ end
104
+
105
+ # Return whether RestClient.proxy was set explicitly. We use this to
106
+ # differentiate between no value being set and a value explicitly set to nil.
107
+ #
108
+ # @return [Boolean]
109
+ #
110
+ def self.proxy_set?
111
+ @proxy_set ||= false
112
+ end
113
+
114
+ # Setup the log for RestClient calls.
115
+ # Value should be a logger but can can be stdout, stderr, or a filename.
116
+ # You can also configure logging by the environment variable RESTCLIENT_LOG.
117
+ def self.log= log
118
+ @@log = create_log log
119
+ end
120
+
121
+ # Create a log that respond to << like a logger
122
+ # param can be 'stdout', 'stderr', a string (then we will log to that file) or a logger (then we return it)
123
+ def self.create_log param
124
+ if param
125
+ if param.is_a? String
126
+ if param == 'stdout'
127
+ stdout_logger = Class.new do
128
+ def << obj
129
+ STDOUT.puts obj
130
+ end
131
+ end
132
+ stdout_logger.new
133
+ elsif param == 'stderr'
134
+ stderr_logger = Class.new do
135
+ def << obj
136
+ STDERR.puts obj
137
+ end
138
+ end
139
+ stderr_logger.new
140
+ else
141
+ file_logger = Class.new do
142
+ attr_writer :target_file
143
+
144
+ def << obj
145
+ File.open(@target_file, 'a') { |f| f.puts obj }
146
+ end
147
+ end
148
+ logger = file_logger.new
149
+ logger.target_file = param
150
+ logger
151
+ end
152
+ else
153
+ param
154
+ end
155
+ end
156
+ end
157
+
158
+ @@env_log = create_log ENV['RESTCLIENT_LOG']
159
+
160
+ @@log = nil
161
+
162
+ def self.log # :nodoc:
163
+ @@env_log || @@log
164
+ end
165
+
166
+ @@before_execution_procs = []
167
+
168
+ # Add a Proc to be called before each request in executed.
169
+ # The proc parameters will be the http request and the request params.
170
+ def self.add_before_execution_proc &proc
171
+ raise ArgumentError.new('block is required') unless proc
172
+ @@before_execution_procs << proc
173
+ end
174
+
175
+ # Reset the procs to be called before each request is executed.
176
+ def self.reset_before_execution_procs
177
+ @@before_execution_procs = []
178
+ end
179
+
180
+ def self.before_execution_procs # :nodoc:
181
+ @@before_execution_procs
182
+ end
183
+
184
+ end
@@ -0,0 +1,226 @@
1
+ require 'cgi'
2
+ require 'http-cookie'
3
+
4
+ module RestClient
5
+
6
+ module AbstractResponse
7
+
8
+ attr_reader :net_http_res, :request
9
+
10
+ def inspect
11
+ raise NotImplementedError.new('must override in subclass')
12
+ end
13
+
14
+ # HTTP status code
15
+ def code
16
+ @code ||= @net_http_res.code.to_i
17
+ end
18
+
19
+ def history
20
+ @history ||= request.redirection_history || []
21
+ end
22
+
23
+ # A hash of the headers, beautified with symbols and underscores.
24
+ # e.g. "Content-type" will become :content_type.
25
+ def headers
26
+ @headers ||= AbstractResponse.beautify_headers(@net_http_res.to_hash)
27
+ end
28
+
29
+ # The raw headers.
30
+ def raw_headers
31
+ @raw_headers ||= @net_http_res.to_hash
32
+ end
33
+
34
+ def response_set_vars(net_http_res, request)
35
+ @net_http_res = net_http_res
36
+ @request = request
37
+
38
+ # prime redirection history
39
+ history
40
+ end
41
+
42
+ # Hash of cookies extracted from response headers.
43
+ #
44
+ # NB: This will return only cookies whose domain matches this request, and
45
+ # may not even return all of those cookies if there are duplicate names.
46
+ # Use the full cookie_jar for more nuanced access.
47
+ #
48
+ # @see #cookie_jar
49
+ #
50
+ # @return [Hash]
51
+ #
52
+ def cookies
53
+ hash = {}
54
+
55
+ cookie_jar.cookies(@request.uri).each do |cookie|
56
+ hash[cookie.name] = cookie.value
57
+ end
58
+
59
+ hash
60
+ end
61
+
62
+ # Cookie jar extracted from response headers.
63
+ #
64
+ # @return [HTTP::CookieJar]
65
+ #
66
+ def cookie_jar
67
+ return @cookie_jar if defined?(@cookie_jar) && @cookie_jar
68
+
69
+ jar = @request.cookie_jar.dup
70
+ headers.fetch(:set_cookie, []).each do |cookie|
71
+ jar.parse(cookie, @request.uri)
72
+ end
73
+
74
+ @cookie_jar = jar
75
+ end
76
+
77
+ # Return the default behavior corresponding to the response code:
78
+ #
79
+ # For 20x status codes: return the response itself
80
+ #
81
+ # For 30x status codes:
82
+ # 301, 302, 307: redirect GET / HEAD if there is a Location header
83
+ # 303: redirect, changing method to GET, if there is a Location header
84
+ #
85
+ # For all other responses, raise a response exception
86
+ #
87
+ def return!(&block)
88
+ case code
89
+ when 200..207
90
+ self
91
+ when 301, 302, 307
92
+ case request.method
93
+ when 'get', 'head'
94
+ check_max_redirects
95
+ follow_redirection(&block)
96
+ else
97
+ raise exception_with_response
98
+ end
99
+ when 303
100
+ check_max_redirects
101
+ follow_get_redirection(&block)
102
+ else
103
+ raise exception_with_response
104
+ end
105
+ end
106
+
107
+ def to_i
108
+ warn('warning: calling Response#to_i is not recommended')
109
+ super
110
+ end
111
+
112
+ def description
113
+ "#{code} #{STATUSES[code]} | #{(headers[:content_type] || '').gsub(/;.*$/, '')} #{size} bytes\n"
114
+ end
115
+
116
+ # Follow a redirection response by making a new HTTP request to the
117
+ # redirection target.
118
+ def follow_redirection(&block)
119
+ _follow_redirection(request.args.dup, &block)
120
+ end
121
+
122
+ # Follow a redirection response, but change the HTTP method to GET and drop
123
+ # the payload from the original request.
124
+ def follow_get_redirection(&block)
125
+ new_args = request.args.dup
126
+ new_args[:method] = :get
127
+ new_args.delete(:payload)
128
+
129
+ _follow_redirection(new_args, &block)
130
+ end
131
+
132
+ # Convert headers hash into canonical form.
133
+ #
134
+ # Header names will be converted to lowercase symbols with underscores
135
+ # instead of hyphens.
136
+ #
137
+ # Headers specified multiple times will be joined by comma and space,
138
+ # except for Set-Cookie, which will always be an array.
139
+ #
140
+ # Per RFC 2616, if a server sends multiple headers with the same key, they
141
+ # MUST be able to be joined into a single header by a comma. However,
142
+ # Set-Cookie (RFC 6265) cannot because commas are valid within cookie
143
+ # definitions. The newer RFC 7230 notes (3.2.2) that Set-Cookie should be
144
+ # handled as a special case.
145
+ #
146
+ # http://tools.ietf.org/html/rfc2616#section-4.2
147
+ # http://tools.ietf.org/html/rfc7230#section-3.2.2
148
+ # http://tools.ietf.org/html/rfc6265
149
+ #
150
+ # @param headers [Hash]
151
+ # @return [Hash]
152
+ #
153
+ def self.beautify_headers(headers)
154
+ headers.inject({}) do |out, (key, value)|
155
+ key_sym = key.tr('-', '_').downcase.to_sym
156
+
157
+ # Handle Set-Cookie specially since it cannot be joined by comma.
158
+ if key.downcase == 'set-cookie'
159
+ out[key_sym] = value
160
+ else
161
+ out[key_sym] = value.join(', ')
162
+ end
163
+
164
+ out
165
+ end
166
+ end
167
+
168
+ private
169
+
170
+ # Follow a redirection
171
+ #
172
+ # @param new_args [Hash] Start with this hash of arguments for the
173
+ # redirection request. The hash will be mutated, so be sure to dup any
174
+ # existing hash that should not be modified.
175
+ #
176
+ def _follow_redirection(new_args, &block)
177
+
178
+ # parse location header and merge into existing URL
179
+ url = headers[:location]
180
+
181
+ # cannot follow redirection if there is no location header
182
+ unless url
183
+ raise exception_with_response
184
+ end
185
+
186
+ # handle relative redirects
187
+ unless url.start_with?('http')
188
+ url = URI.parse(request.url).merge(url).to_s
189
+ end
190
+ new_args[:url] = url
191
+
192
+ new_args[:password] = request.password
193
+ new_args[:user] = request.user
194
+ new_args[:headers] = request.headers
195
+ new_args[:max_redirects] = request.max_redirects - 1
196
+
197
+ # pass through our new cookie jar
198
+ new_args[:cookies] = cookie_jar
199
+
200
+ # prepare new request
201
+ new_req = Request.new(new_args)
202
+
203
+ # append self to redirection history
204
+ new_req.redirection_history = history + [self]
205
+
206
+ # execute redirected request
207
+ new_req.execute(&block)
208
+ end
209
+
210
+ def check_max_redirects
211
+ if request.max_redirects <= 0
212
+ raise exception_with_response
213
+ end
214
+ end
215
+
216
+ def exception_with_response
217
+ begin
218
+ klass = Exceptions::EXCEPTIONS_MAP.fetch(code)
219
+ rescue KeyError
220
+ raise RequestFailed.new(self, code)
221
+ end
222
+
223
+ raise klass.new(self, code)
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,244 @@
1
+ module RestClient
2
+
3
+ # Hash of HTTP status code => message.
4
+ #
5
+ # 1xx: Informational - Request received, continuing process
6
+ # 2xx: Success - The action was successfully received, understood, and
7
+ # accepted
8
+ # 3xx: Redirection - Further action must be taken in order to complete the
9
+ # request
10
+ # 4xx: Client Error - The request contains bad syntax or cannot be fulfilled
11
+ # 5xx: Server Error - The server failed to fulfill an apparently valid
12
+ # request
13
+ #
14
+ # @see
15
+ # http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
16
+ #
17
+ STATUSES = {100 => 'Continue',
18
+ 101 => 'Switching Protocols',
19
+ 102 => 'Processing', #WebDAV
20
+
21
+ 200 => 'OK',
22
+ 201 => 'Created',
23
+ 202 => 'Accepted',
24
+ 203 => 'Non-Authoritative Information', # http/1.1
25
+ 204 => 'No Content',
26
+ 205 => 'Reset Content',
27
+ 206 => 'Partial Content',
28
+ 207 => 'Multi-Status', #WebDAV
29
+ 208 => 'Already Reported', # RFC5842
30
+ 226 => 'IM Used', # RFC3229
31
+
32
+ 300 => 'Multiple Choices',
33
+ 301 => 'Moved Permanently',
34
+ 302 => 'Found',
35
+ 303 => 'See Other', # http/1.1
36
+ 304 => 'Not Modified',
37
+ 305 => 'Use Proxy', # http/1.1
38
+ 306 => 'Switch Proxy', # no longer used
39
+ 307 => 'Temporary Redirect', # http/1.1
40
+ 308 => 'Permanent Redirect', # RFC7538
41
+
42
+ 400 => 'Bad Request',
43
+ 401 => 'Unauthorized',
44
+ 402 => 'Payment Required',
45
+ 403 => 'Forbidden',
46
+ 404 => 'Not Found',
47
+ 405 => 'Method Not Allowed',
48
+ 406 => 'Not Acceptable',
49
+ 407 => 'Proxy Authentication Required',
50
+ 408 => 'Request Timeout',
51
+ 409 => 'Conflict',
52
+ 410 => 'Gone',
53
+ 411 => 'Length Required',
54
+ 412 => 'Precondition Failed',
55
+ 413 => 'Payload Too Large', # RFC7231 (renamed, see below)
56
+ 414 => 'URI Too Long', # RFC7231 (renamed, see below)
57
+ 415 => 'Unsupported Media Type',
58
+ 416 => 'Range Not Satisfiable', # RFC7233 (renamed, see below)
59
+ 417 => 'Expectation Failed',
60
+ 418 => 'I\'m A Teapot', #RFC2324
61
+ 421 => 'Too Many Connections From This IP',
62
+ 422 => 'Unprocessable Entity', #WebDAV
63
+ 423 => 'Locked', #WebDAV
64
+ 424 => 'Failed Dependency', #WebDAV
65
+ 425 => 'Unordered Collection', #WebDAV
66
+ 426 => 'Upgrade Required',
67
+ 428 => 'Precondition Required', #RFC6585
68
+ 429 => 'Too Many Requests', #RFC6585
69
+ 431 => 'Request Header Fields Too Large', #RFC6585
70
+ 449 => 'Retry With', #Microsoft
71
+ 450 => 'Blocked By Windows Parental Controls', #Microsoft
72
+
73
+ 500 => 'Internal Server Error',
74
+ 501 => 'Not Implemented',
75
+ 502 => 'Bad Gateway',
76
+ 503 => 'Service Unavailable',
77
+ 504 => 'Gateway Timeout',
78
+ 505 => 'HTTP Version Not Supported',
79
+ 506 => 'Variant Also Negotiates',
80
+ 507 => 'Insufficient Storage', #WebDAV
81
+ 508 => 'Loop Detected', # RFC5842
82
+ 509 => 'Bandwidth Limit Exceeded', #Apache
83
+ 510 => 'Not Extended',
84
+ 511 => 'Network Authentication Required', # RFC6585
85
+ }
86
+
87
+ STATUSES_COMPATIBILITY = {
88
+ # The RFCs all specify "Not Found", but "Resource Not Found" was used in
89
+ # earlier RestClient releases.
90
+ 404 => ['ResourceNotFound'],
91
+
92
+ # HTTP 413 was renamed to "Payload Too Large" in RFC7231.
93
+ 413 => ['RequestEntityTooLarge'],
94
+
95
+ # HTTP 414 was renamed to "URI Too Long" in RFC7231.
96
+ 414 => ['RequestURITooLong'],
97
+
98
+ # HTTP 416 was renamed to "Range Not Satisfiable" in RFC7233.
99
+ 416 => ['RequestedRangeNotSatisfiable'],
100
+ }
101
+
102
+
103
+ # This is the base RestClient exception class. Rescue it if you want to
104
+ # catch any exception that your request might raise
105
+ # You can get the status code by e.http_code, or see anything about the
106
+ # response via e.response.
107
+ # For example, the entire result body (which is
108
+ # probably an HTML error page) is e.response.
109
+ class Exception < RuntimeError
110
+ attr_accessor :response
111
+ attr_accessor :original_exception
112
+ attr_writer :message
113
+
114
+ def initialize response = nil, initial_response_code = nil
115
+ @response = response
116
+ @message = nil
117
+ @initial_response_code = initial_response_code
118
+ end
119
+
120
+ def http_code
121
+ # return integer for compatibility
122
+ if @response
123
+ @response.code.to_i
124
+ else
125
+ @initial_response_code
126
+ end
127
+ end
128
+
129
+ def http_headers
130
+ @response.headers if @response
131
+ end
132
+
133
+ def http_body
134
+ @response.body if @response
135
+ end
136
+
137
+ def to_s
138
+ message
139
+ end
140
+
141
+ def message
142
+ @message || default_message
143
+ end
144
+
145
+ def default_message
146
+ self.class.name
147
+ end
148
+ end
149
+
150
+ # Compatibility
151
+ class ExceptionWithResponse < Exception
152
+ end
153
+
154
+ # The request failed with an error code not managed by the code
155
+ class RequestFailed < ExceptionWithResponse
156
+
157
+ def default_message
158
+ "HTTP status code #{http_code}"
159
+ end
160
+
161
+ def to_s
162
+ message
163
+ end
164
+ end
165
+
166
+ # RestClient exception classes. TODO: move all exceptions into this module.
167
+ #
168
+ # We will a create an exception for each status code, see
169
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
170
+ #
171
+ module Exceptions
172
+ # Map http status codes to the corresponding exception class
173
+ EXCEPTIONS_MAP = {}
174
+ end
175
+
176
+ # Create HTTP status exception classes
177
+ STATUSES.each_pair do |code, message|
178
+ klass = Class.new(RequestFailed) do
179
+ send(:define_method, :default_message) {"#{http_code ? "#{http_code} " : ''}#{message}"}
180
+ end
181
+ klass_constant = const_set(message.delete(' \-\''), klass)
182
+ Exceptions::EXCEPTIONS_MAP[code] = klass_constant
183
+ end
184
+
185
+ # Create HTTP status exception classes used for backwards compatibility
186
+ STATUSES_COMPATIBILITY.each_pair do |code, compat_list|
187
+ klass = Exceptions::EXCEPTIONS_MAP.fetch(code)
188
+ compat_list.each do |old_name|
189
+ const_set(old_name, klass)
190
+ end
191
+ end
192
+
193
+ module Exceptions
194
+ # We have to split the Exceptions module like we do here because the
195
+ # EXCEPTIONS_MAP is under Exceptions, but we depend on
196
+ # RestClient::RequestTimeout below.
197
+
198
+ # Base class for request timeouts.
199
+ #
200
+ # NB: Previous releases of rest-client would raise RequestTimeout both for
201
+ # HTTP 408 responses and for actual connection timeouts.
202
+ class Timeout < RestClient::RequestTimeout
203
+ def initialize(message=nil, original_exception=nil)
204
+ super(nil, nil)
205
+ self.message = message if message
206
+ self.original_exception = original_exception if original_exception
207
+ end
208
+ end
209
+
210
+ # Timeout when connecting to a server. Typically wraps Net::OpenTimeout (in
211
+ # ruby 2.0 or greater).
212
+ class OpenTimeout < Timeout
213
+ def default_message
214
+ 'Timed out connecting to server'
215
+ end
216
+ end
217
+
218
+ # Timeout when reading from a server. Typically wraps Net::ReadTimeout (in
219
+ # ruby 2.0 or greater).
220
+ class ReadTimeout < Timeout
221
+ def default_message
222
+ 'Timed out reading data from server'
223
+ end
224
+ end
225
+ end
226
+
227
+
228
+ # The server broke the connection prior to the request completing. Usually
229
+ # this means it crashed, or sometimes that your network connection was
230
+ # severed before it could complete.
231
+ class ServerBrokeConnection < Exception
232
+ def initialize(message = 'Server broke connection')
233
+ super nil, nil
234
+ self.message = message
235
+ end
236
+ end
237
+
238
+ class SSLCertificateNotVerified < Exception
239
+ def initialize(message = 'SSL certificate not verified')
240
+ super nil, nil
241
+ self.message = message
242
+ end
243
+ end
244
+ end