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 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