rest-client 1.8.0-x64-mingw32 → 2.0.0.rc1-x64-mingw32

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.
@@ -26,7 +26,7 @@ module RestClient
26
26
  401 => 'Unauthorized',
27
27
  402 => 'Payment Required',
28
28
  403 => 'Forbidden',
29
- 404 => 'Resource Not Found',
29
+ 404 => 'Not Found',
30
30
  405 => 'Method Not Allowed',
31
31
  406 => 'Not Acceptable',
32
32
  407 => 'Proxy Authentication Required',
@@ -66,18 +66,6 @@ module RestClient
66
66
  511 => 'Network Authentication Required', # RFC6585
67
67
  }
68
68
 
69
- # Compatibility : make the Response act like a Net::HTTPResponse when needed
70
- module ResponseForException
71
- def method_missing symbol, *args
72
- if net_http_res.respond_to? symbol
73
- warn "[warning] The response contained in an RestClient::Exception is now a RestClient::Response instead of a Net::HTTPResponse, please update your code"
74
- net_http_res.send symbol, *args
75
- else
76
- super
77
- end
78
- end
79
- end
80
-
81
69
  # This is the base RestClient exception class. Rescue it if you want to
82
70
  # catch any exception that your request might raise
83
71
  # You can get the status code by e.http_code, or see anything about the
@@ -86,15 +74,13 @@ module RestClient
86
74
  # probably an HTML error page) is e.response.
87
75
  class Exception < RuntimeError
88
76
  attr_accessor :response
77
+ attr_accessor :original_exception
89
78
  attr_writer :message
90
79
 
91
80
  def initialize response = nil, initial_response_code = nil
92
81
  @response = response
93
82
  @message = nil
94
83
  @initial_response_code = initial_response_code
95
-
96
- # compatibility: this make the exception behave like a Net::HTTPResponse
97
- response.extend ResponseForException if response
98
84
  end
99
85
 
100
86
  def http_code
@@ -106,6 +92,10 @@ module RestClient
106
92
  end
107
93
  end
108
94
 
95
+ def http_headers
96
+ @response.headers if @response
97
+ end
98
+
109
99
  def http_body
110
100
  @response.body if @response
111
101
  end
@@ -119,9 +109,12 @@ module RestClient
119
109
  end
120
110
 
121
111
  def message
122
- @message || self.class.name
112
+ @message || self.class.default_message
123
113
  end
124
114
 
115
+ def self.default_message
116
+ self.name
117
+ end
125
118
  end
126
119
 
127
120
  # Compatibility
@@ -140,10 +133,41 @@ module RestClient
140
133
  end
141
134
  end
142
135
 
143
- # We will a create an exception for each status code, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
136
+ # RestClient exception classes. TODO: move all exceptions into this module.
137
+ #
138
+ # We will a create an exception for each status code, see
139
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
140
+ #
144
141
  module Exceptions
145
142
  # Map http status codes to the corresponding exception class
146
143
  EXCEPTIONS_MAP = {}
144
+
145
+ # Base class for request timeouts.
146
+ # NB: Previous releases of rest-client would raise RequestTimeout both for
147
+ # HTTP 408 responses and for actual connection timeouts.
148
+ class Timeout < RestClient::Exception
149
+ def initialize(message=nil, original_exception=nil)
150
+ super(nil, nil)
151
+ self.message = message if message
152
+ self.original_exception = original_exception if original_exception
153
+ end
154
+ end
155
+
156
+ # Timeout when connecting to a server. Typically wraps Net::OpenTimeout (in
157
+ # ruby 2.0 or greater).
158
+ class OpenTimeout < Timeout
159
+ def self.default_message
160
+ 'Timed out connecting to server'
161
+ end
162
+ end
163
+
164
+ # Timeout when reading from a server. Typically wraps Net::ReadTimeout (in
165
+ # ruby 2.0 or greater).
166
+ class ReadTimeout < Timeout
167
+ def self.default_message
168
+ 'Timed out reading data from server'
169
+ end
170
+ end
147
171
  end
148
172
 
149
173
  STATUSES.each_pair do |code, message|
@@ -157,25 +181,8 @@ module RestClient
157
181
  Exceptions::EXCEPTIONS_MAP[code] = klass_constant
158
182
  end
159
183
 
160
- # A redirect was encountered; caught by execute to retry with the new url.
161
- class Redirect < Exception
162
-
163
- def message
164
- 'Redirect'
165
- end
166
-
167
- attr_accessor :url
168
-
169
- def initialize(url)
170
- @url = url
171
- end
172
- end
173
-
174
- class MaxRedirectsReached < Exception
175
- def message
176
- 'Maximum number of redirect reached'
177
- end
178
- end
184
+ # Backwards compatibility. "Not Found" is the actual text in the RFCs.
185
+ ResourceNotFound = NotFound
179
186
 
180
187
  # The server broke the connection prior to the request completing. Usually
181
188
  # this means it crashed, or sometimes that your network connection was
@@ -194,10 +201,3 @@ module RestClient
194
201
  end
195
202
  end
196
203
  end
197
-
198
- class RestClient::Request
199
- # backwards compatibility
200
- Redirect = RestClient::Redirect
201
- Unauthorized = RestClient::Unauthorized
202
- RequestFailed = RestClient::RequestFailed
203
- end
@@ -58,8 +58,8 @@ module RestClient
58
58
  @stream.seek(0)
59
59
  end
60
60
 
61
- def read(bytes=nil)
62
- @stream.read(bytes)
61
+ def read(*args)
62
+ @stream.read(*args)
63
63
  end
64
64
 
65
65
  alias :to_s :read
@@ -1,3 +1,5 @@
1
+ require 'rbconfig'
2
+
1
3
  module RestClient
2
4
  module Platform
3
5
  # Return true if we are running on a darwin-based Ruby platform. This will
@@ -26,5 +28,22 @@ module RestClient
26
28
  # defined on mri >= 1.9
27
29
  RUBY_ENGINE == 'jruby'
28
30
  end
31
+
32
+ def self.architecture
33
+ "#{RbConfig::CONFIG['host_os']} #{RbConfig::CONFIG['host_cpu']}"
34
+ end
35
+
36
+ def self.ruby_agent_version
37
+ case RUBY_ENGINE
38
+ when 'jruby'
39
+ "jruby/#{JRUBY_VERSION} (#{RUBY_VERSION}p#{RUBY_PATCHLEVEL})"
40
+ else
41
+ "#{RUBY_ENGINE}/#{RUBY_VERSION}p#{RUBY_PATCHLEVEL}"
42
+ end
43
+ end
44
+
45
+ def self.default_user_agent
46
+ "rest-client/#{VERSION} (#{architecture}) #{ruby_agent_version}"
47
+ end
29
48
  end
30
49
  end
@@ -15,6 +15,10 @@ module RestClient
15
15
 
16
16
  attr_reader :file, :request
17
17
 
18
+ def inspect
19
+ "<RestClient::RawResponse @code=#{code.inspect}, @file=#{file.inspect}, @request=#{request.inspect}>"
20
+ end
21
+
18
22
  def initialize(tempfile, net_http_res, args, request)
19
23
  @net_http_res = net_http_res
20
24
  @args = args
@@ -21,29 +21,40 @@ module RestClient
21
21
  # * :block_response call the provided block with the HTTPResponse as parameter
22
22
  # * :raw_response return a low-level RawResponse instead of a Response
23
23
  # * :max_redirects maximum number of redirections (default to 10)
24
+ # * :proxy An HTTP proxy URI to use for this request. Any value here
25
+ # (including nil) will override RestClient.proxy.
24
26
  # * :verify_ssl enable ssl verification, possible values are constants from
25
27
  # OpenSSL::SSL::VERIFY_*, defaults to OpenSSL::SSL::VERIFY_PEER
26
- # * :timeout and :open_timeout are how long to wait for a response and to
27
- # open a connection, in seconds. Pass nil to disable the timeout.
28
+ # * :read_timeout and :open_timeout are how long to wait for a response and
29
+ # to open a connection, in seconds. Pass nil to disable the timeout.
30
+ # * :timeout can be used to set both timeouts
28
31
  # * :ssl_client_cert, :ssl_client_key, :ssl_ca_file, :ssl_ca_path,
29
32
  # :ssl_cert_store, :ssl_verify_callback, :ssl_verify_callback_warnings
30
33
  # * :ssl_version specifies the SSL version for the underlying Net::HTTP connection
31
34
  # * :ssl_ciphers sets SSL ciphers for the connection. See
32
35
  # OpenSSL::SSL::SSLContext#ciphers=
36
+ # * :before_execution_proc a Proc to call before executing the request. This
37
+ # proc, like procs from RestClient.before_execution_procs, will be
38
+ # called with the HTTP request and request params.
33
39
  class Request
34
40
 
35
- attr_reader :method, :url, :headers, :cookies,
36
- :payload, :user, :password, :timeout, :max_redirects,
41
+ # TODO: rename timeout to read_timeout
42
+
43
+ attr_reader :method, :url, :headers, :cookies, :payload, :proxy,
44
+ :user, :password, :read_timeout, :max_redirects,
37
45
  :open_timeout, :raw_response, :processed_headers, :args,
38
46
  :ssl_opts
39
47
 
48
+ # An array of previous redirection responses
49
+ attr_accessor :redirection_history
50
+
40
51
  def self.execute(args, & block)
41
52
  new(args).execute(& block)
42
53
  end
43
54
 
44
- # This is similar to the list now in ruby core, but adds HIGH and RC4-MD5
45
- # for better compatibility (similar to Firefox) and moves AES-GCM cipher
46
- # suites above DHE/ECDHE CBC suites (similar to Chromium).
55
+ # This is similar to the list now in ruby core, but adds HIGH for better
56
+ # compatibility (similar to Firefox) and moves AES-GCM cipher suites above
57
+ # DHE/ECDHE CBC suites (similar to Chromium).
47
58
  # https://github.com/ruby/ruby/commit/699b209cf8cf11809620e12985ad33ae33b119ee
48
59
  #
49
60
  # This list will be used by default if the Ruby global OpenSSL default
@@ -91,7 +102,6 @@ module RestClient
91
102
 
92
103
  HIGH
93
104
  +RC4
94
- RC4-MD5
95
105
  }.join(":")
96
106
 
97
107
  # A set of weak default ciphers that we will override by default.
@@ -102,9 +112,13 @@ module RestClient
102
112
  SSLOptionList = %w{client_cert client_key ca_file ca_path cert_store
103
113
  version ciphers verify_callback verify_callback_warnings}
104
114
 
115
+ def inspect
116
+ "<RestClient::Request @method=#{@method.inspect}, @url=#{@url.inspect}>"
117
+ end
118
+
105
119
  def initialize args
106
120
  @method = args[:method] or raise ArgumentError, "must pass :method"
107
- @headers = args[:headers] || {}
121
+ @headers = (args[:headers] || {}).dup
108
122
  if args[:url]
109
123
  @url = process_url_params(args[:url], headers)
110
124
  else
@@ -115,7 +129,11 @@ module RestClient
115
129
  @user = args[:user]
116
130
  @password = args[:password]
117
131
  if args.include?(:timeout)
118
- @timeout = args[:timeout]
132
+ @read_timeout = args[:timeout]
133
+ @open_timeout = args[:timeout]
134
+ end
135
+ if args.include?(:read_timeout)
136
+ @read_timeout = args[:read_timeout]
119
137
  end
120
138
  if args.include?(:open_timeout)
121
139
  @open_timeout = args[:open_timeout]
@@ -123,6 +141,8 @@ module RestClient
123
141
  @block_response = args[:block_response]
124
142
  @raw_response = args[:raw_response] || false
125
143
 
144
+ @proxy = args.fetch(:proxy) if args.include?(:proxy)
145
+
126
146
  @ssl_opts = {}
127
147
 
128
148
  if args.include?(:verify_ssl)
@@ -169,11 +189,17 @@ module RestClient
169
189
  @max_redirects = args[:max_redirects] || 10
170
190
  @processed_headers = make_headers headers
171
191
  @args = args
192
+
193
+ @before_execution_proc = args[:before_execution_proc]
172
194
  end
173
195
 
174
196
  def execute & block
175
197
  uri = parse_url_with_auth(url)
176
- transmit uri, net_http_request_class(method).new(uri.request_uri, processed_headers), payload, & block
198
+
199
+ # With 2.0.0+, net/http accepts URI objects in requests and handles wrapping
200
+ # IPv6 addresses in [] for use in the Host request header.
201
+ request_uri = RUBY_VERSION >= "2.0.0" ? uri : uri.request_uri
202
+ transmit uri, net_http_request_class(method).new(request_uri, processed_headers), payload, & block
177
203
  ensure
178
204
  payload.close if payload
179
205
  end
@@ -249,12 +275,44 @@ module RestClient
249
275
  ! Regexp.new('[\x0-\x1f\x7f,;]').match(value)
250
276
  end
251
277
 
252
- def net_http_class
253
- if RestClient.proxy
254
- proxy_uri = URI.parse(RestClient.proxy)
255
- Net::HTTP::Proxy(proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password)
278
+ # The proxy URI for this request. If `:proxy` was provided on this request,
279
+ # use it over `RestClient.proxy`.
280
+ #
281
+ # Return false if a proxy was explicitly set and is falsy.
282
+ #
283
+ # @return [URI, false, nil]
284
+ #
285
+ def proxy_uri
286
+ if defined?(@proxy)
287
+ if @proxy
288
+ URI.parse(@proxy)
289
+ else
290
+ false
291
+ end
292
+ elsif RestClient.proxy_set?
293
+ if RestClient.proxy
294
+ URI.parse(RestClient.proxy)
295
+ else
296
+ false
297
+ end
256
298
  else
257
- Net::HTTP
299
+ nil
300
+ end
301
+ end
302
+
303
+ def net_http_object(hostname, port)
304
+ p_uri = proxy_uri
305
+
306
+ if p_uri.nil?
307
+ # no proxy set
308
+ Net::HTTP.new(hostname, port)
309
+ elsif !p_uri
310
+ # proxy explicitly set to none
311
+ Net::HTTP.new(hostname, port, nil, nil, nil, nil)
312
+ else
313
+ Net::HTTP.new(hostname, port,
314
+ p_uri.hostname, p_uri.port, p_uri.user, p_uri.password)
315
+
258
316
  end
259
317
  end
260
318
 
@@ -263,7 +321,7 @@ module RestClient
263
321
  end
264
322
 
265
323
  def net_http_do_request(http, req, body=nil, &block)
266
- if body != nil && body.respond_to?(:read)
324
+ if body && body.respond_to?(:read)
267
325
  req.body_stream = body
268
326
  return http.request(req, nil, &block)
269
327
  else
@@ -271,8 +329,22 @@ module RestClient
271
329
  end
272
330
  end
273
331
 
332
+ # Parse a string into a URI object. If the string has no HTTP-like scheme
333
+ # (i.e. scheme followed by '//'), a scheme of 'http' will be added. This
334
+ # mimics the behavior of browsers and user agents like cURL.
335
+ #
336
+ # @param url [String] A URL string.
337
+ #
338
+ # @return [URI]
339
+ #
340
+ # @raise URI::InvalidURIError on invalid URIs
341
+ #
274
342
  def parse_url(url)
275
- url = "http://#{url}" unless url.match(/^http/)
343
+ # Prepend http:// unless the string already contains an RFC 3986 scheme
344
+ # followed by two forward slashes. (The slashes are not part of the URI
345
+ # RFC, but specified by the URL RFC 1738.)
346
+ # https://tools.ietf.org/html/rfc3986#section-3.1
347
+ url = 'http://' + url unless url.match(%r{\A[a-z][a-z0-9+.-]*://}i)
276
348
  URI.parse(url)
277
349
  end
278
350
 
@@ -281,7 +353,7 @@ module RestClient
281
353
  @user = CGI.unescape(uri.user) if uri.user
282
354
  @password = CGI.unescape(uri.password) if uri.password
283
355
  if !@user && !@password
284
- @user, @password = Netrc.read[uri.host]
356
+ @user, @password = Netrc.read[uri.hostname]
285
357
  end
286
358
  uri
287
359
  end
@@ -347,9 +419,14 @@ module RestClient
347
419
  end
348
420
 
349
421
  def transmit uri, req, payload, & block
422
+
423
+ # We set this to true in the net/http block so that we can distinguish
424
+ # read_timeout from open_timeout. This isn't needed in Ruby >= 2.0.
425
+ established_connection = false
426
+
350
427
  setup_credentials req
351
428
 
352
- net = net_http_class.new(uri.host, uri.port)
429
+ net = net_http_object(uri.hostname, uri.port)
353
430
  net.use_ssl = uri.is_a?(URI::HTTPS)
354
431
  net.ssl_version = ssl_version if ssl_version
355
432
  net.ciphers = ssl_ciphers if ssl_ciphers
@@ -388,16 +465,16 @@ module RestClient
388
465
  warn('Try passing :verify_ssl => false instead.')
389
466
  end
390
467
 
391
- if defined? @timeout
392
- if @timeout == -1
393
- warn 'To disable read timeouts, please set timeout to nil instead of -1'
394
- @timeout = nil
468
+ if defined? @read_timeout
469
+ if @read_timeout == -1
470
+ warn 'Deprecated: to disable timeouts, please use nil instead of -1'
471
+ @read_timeout = nil
395
472
  end
396
- net.read_timeout = @timeout
473
+ net.read_timeout = @read_timeout
397
474
  end
398
475
  if defined? @open_timeout
399
476
  if @open_timeout == -1
400
- warn 'To disable open timeouts, please set open_timeout to nil instead of -1'
477
+ warn 'Deprecated: to disable timeouts, please use nil instead of -1'
401
478
  @open_timeout = nil
402
479
  end
403
480
  net.open_timeout = @open_timeout
@@ -407,24 +484,45 @@ module RestClient
407
484
  before_proc.call(req, args)
408
485
  end
409
486
 
487
+ if @before_execution_proc
488
+ @before_execution_proc.call(req, args)
489
+ end
490
+
410
491
  log_request
411
492
 
412
493
 
413
494
  net.start do |http|
495
+ established_connection = true
496
+
414
497
  if @block_response
415
- net_http_do_request(http, req, payload ? payload.to_s : nil,
416
- &@block_response)
498
+ net_http_do_request(http, req, payload, &@block_response)
417
499
  else
418
- res = net_http_do_request(http, req, payload ? payload.to_s : nil) \
419
- { |http_response| fetch_body(http_response) }
500
+ res = net_http_do_request(http, req, payload) { |http_response|
501
+ fetch_body(http_response)
502
+ }
420
503
  log_response res
421
504
  process_result res, & block
422
505
  end
423
506
  end
424
507
  rescue EOFError
425
508
  raise RestClient::ServerBrokeConnection
426
- rescue Timeout::Error, Errno::ETIMEDOUT
427
- raise RestClient::RequestTimeout
509
+ rescue Timeout::Error, Errno::ETIMEDOUT => err
510
+ # Net::HTTP has OpenTimeout, ReadTimeout in Ruby >= 2.0
511
+ if defined?(Net::OpenTimeout)
512
+ case err
513
+ when Net::OpenTimeout
514
+ raise RestClient::Exceptions::OpenTimeout.new(nil, err)
515
+ when Net::ReadTimeout
516
+ raise RestClient::Exceptions::ReadTimeout.new(nil, err)
517
+ end
518
+ end
519
+
520
+ # compatibility for Ruby 1.9.3, handling for non-Net::HTTP timeouts
521
+ if established_connection
522
+ raise RestClient::Exceptions::ReadTimeout.new(nil, err)
523
+ else
524
+ raise RestClient::Exceptions::OpenTimeout.new(nil, err)
525
+ end
428
526
 
429
527
  rescue OpenSSL::SSL::SSLError => error
430
528
  # TODO: deprecate and remove RestClient::SSLCertificateNotVerified and just
@@ -449,7 +547,7 @@ module RestClient
449
547
  end
450
548
 
451
549
  def setup_credentials(req)
452
- req.basic_auth(user, password) if user
550
+ req.basic_auth(user, password) if user && !headers.has_key?("Authorization")
453
551
  end
454
552
 
455
553
  def fetch_body(http_response)
@@ -457,7 +555,7 @@ module RestClient
457
555
  # Taken from Chef, which as in turn...
458
556
  # Stolen from http://www.ruby-forum.com/topic/166423
459
557
  # Kudos to _why!
460
- @tf = Tempfile.new("rest-client")
558
+ @tf = Tempfile.new('rest-client.')
461
559
  @tf.binmode
462
560
  size, total = 0, http_response.header['Content-Length'].to_i
463
561
  http_response.read_body do |chunk|
@@ -486,13 +584,14 @@ module RestClient
486
584
  # We don't decode raw requests
487
585
  response = RawResponse.new(@tf, res, args, self)
488
586
  else
489
- response = Response.create(Request.decode(res['content-encoding'], res.body), res, args, self)
587
+ decoded = Request.decode(res['content-encoding'], res.body)
588
+ response = Response.create(decoded, res, args, self)
490
589
  end
491
590
 
492
591
  if block_given?
493
592
  block.call(response, self, res, & block)
494
593
  else
495
- response.return!(self, res, & block)
594
+ response.return!(&block)
496
595
  end
497
596
 
498
597
  end
@@ -552,7 +651,7 @@ module RestClient
552
651
  def stringify_headers headers
553
652
  headers.inject({}) do |result, (key, value)|
554
653
  if key.is_a? Symbol
555
- key = key.to_s.split(/_/).map { |w| w.capitalize }.join('-')
654
+ key = key.to_s.split(/_/).map(&:capitalize).join('-')
556
655
  end
557
656
  if 'CONTENT-TYPE' == key.upcase
558
657
  result[key] = maybe_convert_extension(value.to_s)
@@ -574,7 +673,11 @@ module RestClient
574
673
  end
575
674
 
576
675
  def default_headers
577
- {:accept => '*/*; q=0.5, application/xml', :accept_encoding => 'gzip, deflate'}
676
+ {
677
+ :accept => '*/*',
678
+ :accept_encoding => 'gzip, deflate',
679
+ :user_agent => RestClient::Platform.default_user_agent,
680
+ }
578
681
  end
579
682
 
580
683
  private