rest 2.7.2 → 3.0.0

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.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ZWJlYTZlYTNkZmFjZGRiNTVlOTgwYmEzY2RmZWUxODU3MzA2MDNiMw==
5
- data.tar.gz: !binary |-
6
- YzdmYjM5NDBhYzMxZjgyZjMyOGE3ZGRiNDZlODI2N2RlNWNiNTI3MQ==
2
+ SHA1:
3
+ metadata.gz: 6c689e6d91135dd2ac6e0f4f0f63ad55ad77ecc2
4
+ data.tar.gz: 70b63a96e8d9f1bfc566207907359d8d2411af63
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- NTAwZTBkODBhMTg3MmVlMGE0ZWViNjZhMTk2Y2FmZDc5N2QyYzAxYzJmYWE0
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.0)
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.6.2)
10
+ ethon (0.7.1)
12
11
  ffi (>= 1.3.0)
13
- mime-types (~> 1.18)
14
- excon (0.31.0)
15
- ffi (1.9.3)
16
- mime-types (1.25.1)
17
- minitest (5.2.1)
18
- net-http-persistent (2.9)
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.1.1)
22
- rest_client (1.7.2)
23
- netrc (~> 0.7.7)
24
- test-unit (2.5.5)
25
- typhoeus (0.6.7)
26
- ethon (~> 0.6.2)
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
@@ -13,4 +13,6 @@ if Rest.ruby_major == 1 && Rest.ruby_minor == 8
13
13
  gem 'json'
14
14
  end
15
15
 
16
- require File.expand_path('rest/client', File.dirname(__FILE__))
16
+ require 'rest/errors'
17
+ require 'rest/wrappers/base_wrapper'
18
+ require 'rest/client'
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
- else
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
- #puts 'pow=' + pow.to_s
174
+ #puts 'pow=' + pow.to_s
169
175
  s = rand * pow
170
- #puts 's=' + s.to_s
176
+ #puts 's=' + s.to_s
171
177
  sleep_secs = 1.0 * s / 1000.0
172
- #puts 'sleep for ' + sleep_secs.to_s
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,3 @@
1
1
  module Rest
2
- VERSION = "2.7.2"
2
+ VERSION = "3.0.0"
3
3
  end
@@ -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 = RestClient.post(url, req_hash, headers)
19
- response = Rest::Wrappers::RestClientResponseWrapper.new(r2)
20
- rescue RestClient::Exception => ex
21
- raise Rest::Wrappers::RestClientExceptionWrapper.new(ex)
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