rest 2.7.2 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/Gemfile.lock +16 -18
- data/README.md +2 -0
- data/lib/rest.rb +3 -1
- data/lib/rest/client.rb +12 -6
- data/lib/rest/version.rb +1 -1
- data/lib/rest/wrappers/base_wrapper.rb +7 -9
- data/lib/rest/wrappers/excon_wrapper.rb +4 -4
- data/lib/rest/wrappers/internal_client/internal/abstract_response.rb +108 -0
- data/lib/rest/wrappers/internal_client/internal/exceptions.rb +194 -0
- data/lib/rest/wrappers/internal_client/internal/mimes.rb +54 -0
- data/lib/rest/wrappers/internal_client/internal/net_http_ext.rb +55 -0
- data/lib/rest/wrappers/internal_client/internal/payload.rb +237 -0
- data/lib/rest/wrappers/internal_client/internal/raw_response.rb +36 -0
- data/lib/rest/wrappers/internal_client/internal/request.rb +322 -0
- data/lib/rest/wrappers/internal_client/internal/resource.rb +173 -0
- data/lib/rest/wrappers/internal_client/internal/response.rb +28 -0
- data/lib/rest/wrappers/internal_client/internal_client.rb +177 -0
- data/lib/rest/wrappers/internal_client_wrapper.rb +127 -0
- data/rest.gemspec +4 -2
- data/test/test_base.rb +1 -1
- data/test/test_performance.rb +1 -1
- data/test/test_rest.rb +6 -4
- metadata +47 -36
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
YzdmYjM5NDBhYzMxZjgyZjMyOGE3ZGRiNDZlODI2N2RlNWNiNTI3MQ==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6c689e6d91135dd2ac6e0f4f0f63ad55ad77ecc2
|
4
|
+
data.tar.gz: 70b63a96e8d9f1bfc566207907359d8d2411af63
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
ZWZlYjk3M2E0OTRlMWQ5ZTE2MDZkMzQ4NWJmNjZiMWJjODhmZWJjMjE0NzAz
|
11
|
-
NjIzMWZhOWRhZDg2MzY3ZDVkMTBiZDI5NGJmZjdmMWFmOTNkZDY=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
MjAzNjYxMDljOTljNzQ1Y2RiNTRmMmI2NjlmYjYxN2MxOTM3OTlmZjlmMDFi
|
14
|
-
YWU3YWU2OGZmZWRhMTIyNzBiY2U1ZjE0Njk1MGY2M2FiNmFlMjVhMWNmOWE1
|
15
|
-
NDM3NzYxMDZiNzllZWEzMjM5MTg5N2EyMjBiMjZhZmI0MTA0ZGU=
|
6
|
+
metadata.gz: 3e50465d789d0d1f9628a15365ab78d619aab36d74dfc5c00e2f64622e2d875fe7d622840089da6c6629dcbbc13a12858157bebeb9d3108ac73bc8c03a970f83
|
7
|
+
data.tar.gz: d7c8edf6574d60b6f0209d069f56ce7e77166cb0db7df4f257aae20b417378e0394238df9ccd5f272b627fab00f87d499981d6fb832878d324bf3960dcd9fbd4
|
data/Gemfile.lock
CHANGED
@@ -1,30 +1,27 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rest (2.7.
|
5
|
-
net-http-persistent
|
6
|
-
rest_client (>= 1.7.1)
|
4
|
+
rest (2.7.1)
|
5
|
+
net-http-persistent (>= 2.9.1)
|
7
6
|
|
8
7
|
GEM
|
9
8
|
remote: https://rubygems.org/
|
10
9
|
specs:
|
11
|
-
ethon (0.
|
10
|
+
ethon (0.7.1)
|
12
11
|
ffi (>= 1.3.0)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
netrc (0.7.7)
|
12
|
+
excon (0.41.0)
|
13
|
+
ffi (1.9.6)
|
14
|
+
minitest (5.4.3)
|
15
|
+
net-http-persistent (2.9.4)
|
16
|
+
netrc (0.9.0)
|
17
|
+
power_assert (0.2.1)
|
20
18
|
quicky (0.4.0)
|
21
|
-
rake (10.
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
uber_config (1.1.0)
|
19
|
+
rake (10.3.2)
|
20
|
+
test-unit (3.0.7)
|
21
|
+
power_assert
|
22
|
+
typhoeus (0.6.9)
|
23
|
+
ethon (>= 0.7.1)
|
24
|
+
uber_config (1.1.1)
|
28
25
|
|
29
26
|
PLATFORMS
|
30
27
|
ruby
|
@@ -32,6 +29,7 @@ PLATFORMS
|
|
32
29
|
DEPENDENCIES
|
33
30
|
excon
|
34
31
|
minitest
|
32
|
+
netrc
|
35
33
|
quicky (>= 0.4.0)
|
36
34
|
rake
|
37
35
|
rest!
|
data/README.md
CHANGED
@@ -16,6 +16,7 @@ Features
|
|
16
16
|
* Chooses best client you have installed on your system based on what we have found performs the best.
|
17
17
|
* Currently net_http_persistent and typhoeus are nearly the same, but since net_http_persistent doesn't have a binary
|
18
18
|
dependency, it wins.
|
19
|
+
* You can run performance tests yourself by running: `ruby test/test_performance.rb`, quite a difference between the libs.
|
19
20
|
* Handles 503 errors with exponential backoff.
|
20
21
|
|
21
22
|
|
@@ -39,6 +40,7 @@ Supported http libraries are:
|
|
39
40
|
* rest_client
|
40
41
|
* net_http_persistent
|
41
42
|
* typhoeus
|
43
|
+
* internal - this gem's built in client.
|
42
44
|
|
43
45
|
Then use it:
|
44
46
|
|
data/lib/rest.rb
CHANGED
data/lib/rest/client.rb
CHANGED
@@ -14,8 +14,6 @@ require 'rest/errors'
|
|
14
14
|
|
15
15
|
module Rest
|
16
16
|
|
17
|
-
require 'rest/wrappers/base_wrapper'
|
18
|
-
|
19
17
|
@@logger = Logger.new(STDOUT)
|
20
18
|
@@logger.level = Logger::INFO
|
21
19
|
|
@@ -43,6 +41,7 @@ module Rest
|
|
43
41
|
@@backing_gems[:typhoeus] = BackingGem.new(:typhoeus, 'typhoeus')
|
44
42
|
@@backing_gems[:rest_client] = BackingGem.new(:rest_client, 'rest_client')
|
45
43
|
@@backing_gems[:net_http_persistent] = BackingGem.new(:net_http_persistent, 'net/http/persistent')
|
44
|
+
@@backing_gems[:internal] = BackingGem.new(:internal, 'internal_client')
|
46
45
|
|
47
46
|
def self.backing_gems
|
48
47
|
@@backing_gems
|
@@ -77,11 +76,16 @@ module Rest
|
|
77
76
|
require File.expand_path('wrappers/net_http_persistent_wrapper', File.dirname(__FILE__))
|
78
77
|
@wrapper = Rest::Wrappers::NetHttpPersistentWrapper.new(self)
|
79
78
|
@logger.debug "Using net-http-persistent gem."
|
80
|
-
|
79
|
+
elsif @gem == :rest_client
|
80
|
+
require File.expand_path('wrappers/rest_client_wrapper', File.dirname(__FILE__))
|
81
81
|
@wrapper = Rest::Wrappers::RestClientWrapper.new
|
82
82
|
hint = (options[:gem] ? "" : "NOTICE: Please install 'typhoeus' gem or upgrade to Ruby 2.X for optimal performance.")
|
83
83
|
puts hint
|
84
84
|
@logger.debug "Using rest-client gem. #{hint}"
|
85
|
+
else # use internal client
|
86
|
+
require File.expand_path('wrappers/internal_client_wrapper', File.dirname(__FILE__))
|
87
|
+
@wrapper = Rest::Wrappers::InternalClientWrapper.new
|
88
|
+
@logger.debug "Using rest internal client. #{hint}"
|
85
89
|
end
|
86
90
|
end
|
87
91
|
|
@@ -92,10 +96,12 @@ module Rest
|
|
92
96
|
gems_to_try << :net_http_persistent
|
93
97
|
gems_to_try << :typhoeus
|
94
98
|
gems_to_try << :rest_client
|
99
|
+
gems_to_try << :internal
|
95
100
|
else
|
96
101
|
# net-http-persistent has issues with ssl and keep-alive connections on ruby < 1.9.3p327
|
97
102
|
gems_to_try << :typhoeus
|
98
103
|
gems_to_try << :rest_client
|
104
|
+
gems_to_try << :internal
|
99
105
|
end
|
100
106
|
gems_to_try.each_with_index do |g, i|
|
101
107
|
bg = Rest.backing_gems[g]
|
@@ -165,11 +171,11 @@ module Rest
|
|
165
171
|
raise ex if current_retry == max_retries - 1
|
166
172
|
|
167
173
|
pow = (4 ** (current_retry)) * 100 # milliseconds
|
168
|
-
|
174
|
+
#puts 'pow=' + pow.to_s
|
169
175
|
s = rand * pow
|
170
|
-
|
176
|
+
#puts 's=' + s.to_s
|
171
177
|
sleep_secs = 1.0 * s / 1000.0
|
172
|
-
|
178
|
+
#puts 'sleep for ' + sleep_secs.to_s
|
173
179
|
current_retry += 1
|
174
180
|
@logger.debug "#{ex.code} Received. Retrying #{current_retry} out of #{max_retries} max in #{sleep_secs} seconds."
|
175
181
|
sleep sleep_secs
|
data/lib/rest/version.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# we need client for post_file
|
2
|
+
|
1
3
|
module Rest
|
2
4
|
class BaseWrapper
|
3
5
|
|
@@ -15,10 +17,10 @@ module Rest
|
|
15
17
|
req_hash.delete(:headers)
|
16
18
|
end
|
17
19
|
|
18
|
-
r2 =
|
19
|
-
response = Rest::Wrappers::
|
20
|
-
rescue
|
21
|
-
raise Rest::Wrappers::
|
20
|
+
r2 = Rest::InternalClient.post(url, req_hash, headers)
|
21
|
+
response = Rest::Wrappers::InternalClientResponseWrapper.new(r2)
|
22
|
+
rescue Rest::InternalClient::Exception => ex
|
23
|
+
raise Rest::Wrappers::InternalClientExceptionWrapper.new(ex)
|
22
24
|
end
|
23
25
|
response
|
24
26
|
end
|
@@ -40,7 +42,7 @@ module Rest
|
|
40
42
|
# Provide a headers_orig method in your wrapper to allow this to work
|
41
43
|
def headers
|
42
44
|
new_h = {}
|
43
|
-
headers_orig.each_pair do |k,v|
|
45
|
+
headers_orig.each_pair do |k, v|
|
44
46
|
if v.is_a?(Array) && v.size == 1
|
45
47
|
v = v[0]
|
46
48
|
end
|
@@ -51,7 +53,3 @@ module Rest
|
|
51
53
|
|
52
54
|
end
|
53
55
|
end
|
54
|
-
|
55
|
-
# we need it for post_file, ok as gem already depends on it
|
56
|
-
require 'rest/wrappers/rest_client_wrapper'
|
57
|
-
|
@@ -51,7 +51,7 @@ module Rest
|
|
51
51
|
req_hash[:query] = req_hash[:params] if req_hash[:params]
|
52
52
|
#p req_hash
|
53
53
|
response = excon_request(url, req_hash)
|
54
|
-
rescue RestClient::Exception => ex
|
54
|
+
rescue Rest::RestClient::Exception => ex
|
55
55
|
#p ex
|
56
56
|
raise ExconExceptionWrapper.new(ex)
|
57
57
|
end
|
@@ -75,7 +75,7 @@ module Rest
|
|
75
75
|
req_hash[:url] = url
|
76
76
|
to_json_parts(req_hash)
|
77
77
|
response = excon_request(url, req_hash)
|
78
|
-
rescue RestClient::Exception => ex
|
78
|
+
rescue Rest::RestClient::Exception => ex
|
79
79
|
raise HttpError.new(ex.response, ex.http_code)
|
80
80
|
end
|
81
81
|
response
|
@@ -87,7 +87,7 @@ module Rest
|
|
87
87
|
req_hash[:method] = :put
|
88
88
|
req_hash[:url] = url
|
89
89
|
response = excon_request(url, req_hash)
|
90
|
-
rescue RestClient::Exception => ex
|
90
|
+
rescue Rest::RestClient::Exception => ex
|
91
91
|
raise RestClientExceptionWrapper.new(ex)
|
92
92
|
end
|
93
93
|
response
|
@@ -111,7 +111,7 @@ module Rest
|
|
111
111
|
req_hash[:method] = :delete
|
112
112
|
req_hash[:url] = url
|
113
113
|
response = excon_request(url, req_hash)
|
114
|
-
rescue RestClient::Exception => ex
|
114
|
+
rescue Rest::RestClient::Exception => ex
|
115
115
|
raise RestClientExceptionWrapper.new(ex)
|
116
116
|
end
|
117
117
|
response
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module Rest
|
4
|
+
module InternalClient
|
5
|
+
|
6
|
+
module AbstractResponse
|
7
|
+
|
8
|
+
attr_reader :net_http_res, :args
|
9
|
+
|
10
|
+
# HTTP status code
|
11
|
+
def code
|
12
|
+
@code ||= @net_http_res.code.to_i
|
13
|
+
end
|
14
|
+
|
15
|
+
# A hash of the headers, beautified with symbols and underscores.
|
16
|
+
# e.g. "Content-type" will become :content_type.
|
17
|
+
def headers
|
18
|
+
@headers ||= AbstractResponse.beautify_headers(@net_http_res.to_hash)
|
19
|
+
end
|
20
|
+
|
21
|
+
# The raw headers.
|
22
|
+
def raw_headers
|
23
|
+
@raw_headers ||= @net_http_res.to_hash
|
24
|
+
end
|
25
|
+
|
26
|
+
# Hash of cookies extracted from response headers
|
27
|
+
def cookies
|
28
|
+
@cookies ||= (self.headers[:set_cookie] || {}).inject({}) do |out, cookie_content|
|
29
|
+
out.merge parse_cookie(cookie_content)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Return the default behavior corresponding to the response code:
|
34
|
+
# the response itself for code in 200..206, redirection for 301, 302 and 307 in get and head cases, redirection for 303 and an exception in other cases
|
35
|
+
def return! request = nil, result = nil, & block
|
36
|
+
if (200..207).include? code
|
37
|
+
self
|
38
|
+
elsif [301, 302, 307].include? code
|
39
|
+
unless [:get, :head].include? args[:method]
|
40
|
+
raise Exceptions::EXCEPTIONS_MAP[code].new(self, code)
|
41
|
+
else
|
42
|
+
follow_redirection(request, result, & block)
|
43
|
+
end
|
44
|
+
elsif code == 303
|
45
|
+
args[:method] = :get
|
46
|
+
args.delete :payload
|
47
|
+
follow_redirection(request, result, & block)
|
48
|
+
elsif Exceptions::EXCEPTIONS_MAP[code]
|
49
|
+
raise Exceptions::EXCEPTIONS_MAP[code].new(self, code)
|
50
|
+
else
|
51
|
+
raise RequestFailed.new(self, code)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_i
|
56
|
+
code
|
57
|
+
end
|
58
|
+
|
59
|
+
def description
|
60
|
+
"#{code} #{STATUSES[code]} | #{(headers[:content_type] || '').gsub(/;.*$/, '')} #{size} bytes\n"
|
61
|
+
end
|
62
|
+
|
63
|
+
# Follow a redirection
|
64
|
+
def follow_redirection request = nil, result = nil, & block
|
65
|
+
url = headers[:location]
|
66
|
+
if url !~ /^http/
|
67
|
+
url = URI.parse(args[:url]).merge(url).to_s
|
68
|
+
end
|
69
|
+
args[:url] = url
|
70
|
+
if request
|
71
|
+
if request.max_redirects == 0
|
72
|
+
raise MaxRedirectsReached
|
73
|
+
end
|
74
|
+
args[:password] = request.password
|
75
|
+
args[:user] = request.user
|
76
|
+
args[:headers] = request.headers
|
77
|
+
args[:max_redirects] = request.max_redirects - 1
|
78
|
+
# pass any cookie set in the result
|
79
|
+
if result && result['set-cookie']
|
80
|
+
args[:headers][:cookies] = (args[:headers][:cookies] || {}).merge(parse_cookie(result['set-cookie']))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
Request.execute args, &block
|
84
|
+
end
|
85
|
+
|
86
|
+
def AbstractResponse.beautify_headers(headers)
|
87
|
+
headers.inject({}) do |out, (key, value)|
|
88
|
+
out[key.gsub(/-/, '_').downcase.to_sym] = %w{ set-cookie }.include?(key.downcase) ? value : value.first
|
89
|
+
out
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
# Parse a cookie value and return its content in an Hash
|
96
|
+
def parse_cookie cookie_content
|
97
|
+
out = {}
|
98
|
+
CGI::Cookie::parse(cookie_content).each do |key, cookie|
|
99
|
+
unless ['expires', 'path'].include? key
|
100
|
+
out[CGI::escape(key)] = cookie.value[0] ? (CGI::escape(cookie.value[0]) || '') : ''
|
101
|
+
end
|
102
|
+
end
|
103
|
+
out
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
module Rest
|
2
|
+
module InternalClient
|
3
|
+
|
4
|
+
STATUSES = {100 => 'Continue',
|
5
|
+
101 => 'Switching Protocols',
|
6
|
+
102 => 'Processing', #WebDAV
|
7
|
+
|
8
|
+
200 => 'OK',
|
9
|
+
201 => 'Created',
|
10
|
+
202 => 'Accepted',
|
11
|
+
203 => 'Non-Authoritative Information', # http/1.1
|
12
|
+
204 => 'No Content',
|
13
|
+
205 => 'Reset Content',
|
14
|
+
206 => 'Partial Content',
|
15
|
+
207 => 'Multi-Status', #WebDAV
|
16
|
+
|
17
|
+
300 => 'Multiple Choices',
|
18
|
+
301 => 'Moved Permanently',
|
19
|
+
302 => 'Found',
|
20
|
+
303 => 'See Other', # http/1.1
|
21
|
+
304 => 'Not Modified',
|
22
|
+
305 => 'Use Proxy', # http/1.1
|
23
|
+
306 => 'Switch Proxy', # no longer used
|
24
|
+
307 => 'Temporary Redirect', # http/1.1
|
25
|
+
|
26
|
+
400 => 'Bad Request',
|
27
|
+
401 => 'Unauthorized',
|
28
|
+
402 => 'Payment Required',
|
29
|
+
403 => 'Forbidden',
|
30
|
+
404 => 'Resource Not Found',
|
31
|
+
405 => 'Method Not Allowed',
|
32
|
+
406 => 'Not Acceptable',
|
33
|
+
407 => 'Proxy Authentication Required',
|
34
|
+
408 => 'Request Timeout',
|
35
|
+
409 => 'Conflict',
|
36
|
+
410 => 'Gone',
|
37
|
+
411 => 'Length Required',
|
38
|
+
412 => 'Precondition Failed',
|
39
|
+
413 => 'Request Entity Too Large',
|
40
|
+
414 => 'Request-URI Too Long',
|
41
|
+
415 => 'Unsupported Media Type',
|
42
|
+
416 => 'Requested Range Not Satisfiable',
|
43
|
+
417 => 'Expectation Failed',
|
44
|
+
418 => 'I\'m A Teapot',
|
45
|
+
421 => 'Too Many Connections From This IP',
|
46
|
+
422 => 'Unprocessable Entity', #WebDAV
|
47
|
+
423 => 'Locked', #WebDAV
|
48
|
+
424 => 'Failed Dependency', #WebDAV
|
49
|
+
425 => 'Unordered Collection', #WebDAV
|
50
|
+
426 => 'Upgrade Required',
|
51
|
+
449 => 'Retry With', #Microsoft
|
52
|
+
450 => 'Blocked By Windows Parental Controls', #Microsoft
|
53
|
+
|
54
|
+
500 => 'Internal Server Error',
|
55
|
+
501 => 'Not Implemented',
|
56
|
+
502 => 'Bad Gateway',
|
57
|
+
503 => 'Service Unavailable',
|
58
|
+
504 => 'Gateway Timeout',
|
59
|
+
505 => 'HTTP Version Not Supported',
|
60
|
+
506 => 'Variant Also Negotiates',
|
61
|
+
507 => 'Insufficient Storage', #WebDAV
|
62
|
+
509 => 'Bandwidth Limit Exceeded', #Apache
|
63
|
+
510 => 'Not Extended'}
|
64
|
+
|
65
|
+
# Compatibility : make the Response act like a Net::HTTPResponse when needed
|
66
|
+
module ResponseForException
|
67
|
+
def method_missing symbol, *args
|
68
|
+
if net_http_res.respond_to? symbol
|
69
|
+
warn "[warning] The response contained in an InternalClient::Exception is now a InternalClient::Response instead of a Net::HTTPResponse, please update your code"
|
70
|
+
net_http_res.send symbol, *args
|
71
|
+
else
|
72
|
+
super
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# This is the base InternalClient exception class. Rescue it if you want to
|
78
|
+
# catch any exception that your request might raise
|
79
|
+
# You can get the status code by e.http_code, or see anything about the
|
80
|
+
# response via e.response.
|
81
|
+
# For example, the entire result body (which is
|
82
|
+
# probably an HTML error page) is e.response.
|
83
|
+
class Exception < RuntimeError
|
84
|
+
attr_accessor :response
|
85
|
+
attr_writer :message
|
86
|
+
|
87
|
+
def initialize response = nil, initial_response_code = nil
|
88
|
+
@response = response
|
89
|
+
@message = nil
|
90
|
+
@initial_response_code = initial_response_code
|
91
|
+
|
92
|
+
# compatibility: this make the exception behave like a Net::HTTPResponse
|
93
|
+
response.extend ResponseForException if response
|
94
|
+
end
|
95
|
+
|
96
|
+
def http_code
|
97
|
+
# return integer for compatibility
|
98
|
+
if @response
|
99
|
+
@response.code.to_i
|
100
|
+
else
|
101
|
+
@initial_response_code
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def http_body
|
106
|
+
@response.body if @response
|
107
|
+
end
|
108
|
+
|
109
|
+
def inspect
|
110
|
+
"#{message}: #{http_body}"
|
111
|
+
end
|
112
|
+
|
113
|
+
def to_s
|
114
|
+
inspect
|
115
|
+
end
|
116
|
+
|
117
|
+
def message
|
118
|
+
@message || self.class.name
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
# Compatibility
|
124
|
+
class ExceptionWithResponse < Exception
|
125
|
+
end
|
126
|
+
|
127
|
+
# The request failed with an error code not managed by the code
|
128
|
+
class RequestFailed < ExceptionWithResponse
|
129
|
+
|
130
|
+
def message
|
131
|
+
"HTTP status code #{http_code}"
|
132
|
+
end
|
133
|
+
|
134
|
+
def to_s
|
135
|
+
message
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# We will a create an exception for each status code, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
140
|
+
module Exceptions
|
141
|
+
# Map http status codes to the corresponding exception class
|
142
|
+
EXCEPTIONS_MAP = {}
|
143
|
+
end
|
144
|
+
|
145
|
+
STATUSES.each_pair do |code, message|
|
146
|
+
|
147
|
+
# Compatibility
|
148
|
+
superclass = ([304, 401, 404].include? code) ? ExceptionWithResponse : RequestFailed
|
149
|
+
klass = Class.new(superclass) do
|
150
|
+
send(:define_method, :message) { "#{http_code ? "#{http_code} " : ''}#{message}" }
|
151
|
+
end
|
152
|
+
klass_constant = const_set message.delete(' \-\''), klass
|
153
|
+
Exceptions::EXCEPTIONS_MAP[code] = klass_constant
|
154
|
+
end
|
155
|
+
|
156
|
+
# A redirect was encountered; caught by execute to retry with the new url.
|
157
|
+
class Redirect < Exception
|
158
|
+
|
159
|
+
def message
|
160
|
+
'Redirect'
|
161
|
+
end
|
162
|
+
|
163
|
+
attr_accessor :url
|
164
|
+
|
165
|
+
def initialize(url)
|
166
|
+
@url = url
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class MaxRedirectsReached < Exception
|
171
|
+
def message
|
172
|
+
'Maximum number of redirect reached'
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# The server broke the connection prior to the request completing. Usually
|
177
|
+
# this means it crashed, or sometimes that your network connection was
|
178
|
+
# severed before it could complete.
|
179
|
+
class ServerBrokeConnection < Exception
|
180
|
+
def initialize(message = 'Server broke connection')
|
181
|
+
super nil, nil
|
182
|
+
self.message = message
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
class SSLCertificateNotVerified < Exception
|
187
|
+
def initialize(message)
|
188
|
+
super nil, nil
|
189
|
+
self.message = message
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|