rest-client 1.6.1 → 1.6.14

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rest-client might be problematic. Click here for more details.

Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +3 -0
  5. data/AUTHORS +75 -0
  6. data/Gemfile +7 -0
  7. data/README.rdoc +52 -21
  8. data/Rakefile +15 -35
  9. data/bin/restclient +45 -39
  10. data/history.md +67 -1
  11. data/lib/restclient.rb +11 -6
  12. data/lib/restclient/abstract_response.rb +6 -2
  13. data/lib/restclient/exceptions.rb +22 -5
  14. data/lib/restclient/net_http_ext.rb +41 -7
  15. data/lib/restclient/payload.rb +28 -8
  16. data/lib/restclient/platform.rb +29 -0
  17. data/lib/restclient/request.rb +96 -36
  18. data/lib/restclient/resource.rb +17 -0
  19. data/lib/restclient/response.rb +3 -1
  20. data/lib/restclient/version.rb +7 -0
  21. data/rest-client.gemspec +26 -0
  22. data/spec/abstract_response_spec.rb +28 -10
  23. data/spec/base.rb +1 -4
  24. data/spec/exceptions_spec.rb +31 -12
  25. data/spec/integration/capath_digicert/244b5494.0 +19 -0
  26. data/spec/integration/capath_digicert/81b9768f.0 +19 -0
  27. data/spec/integration/capath_digicert/README +8 -0
  28. data/spec/integration/capath_digicert/digicert.crt +19 -0
  29. data/spec/integration/certs/digicert.crt +19 -0
  30. data/spec/integration/certs/verisign.crt +14 -14
  31. data/spec/integration/request_spec.rb +54 -4
  32. data/spec/integration_spec.rb +9 -9
  33. data/spec/master_shake.jpg +0 -0
  34. data/spec/payload_spec.rb +60 -35
  35. data/spec/raw_response_spec.rb +4 -4
  36. data/spec/request2_spec.rb +22 -4
  37. data/spec/request_spec.rb +129 -130
  38. data/spec/resource_spec.rb +30 -18
  39. data/spec/response_spec.rb +48 -36
  40. data/spec/restclient_spec.rb +6 -1
  41. metadata +142 -74
  42. data/VERSION +0 -1
  43. data/spec/integration/certs/equifax.crt +0 -19
data/history.md CHANGED
@@ -1,3 +1,68 @@
1
+ # 1.6.14
2
+
3
+ - This release is unchanged from 1.6.9. It was published in order to supersede
4
+ the malicious 1.6.10-13 versions, even for users who are still pinning to the
5
+ legacy 1.6.x series. All users are encouraged to upgrade to rest-client 2.x.
6
+
7
+ # 1.6.10, 1.6.11, 1.6.12, 1.6.13 (CVE-2019-15224)
8
+
9
+ - These versions were pushed by a malicious actor and included a backdoor permitting
10
+ remote code execution in Rails environments.
11
+ - They were live for about five days before being yanked.
12
+ https://github.com/rest-client/rest-client/issues/713
13
+
14
+ # 1.6.9
15
+
16
+ - Move rdoc to a development dependency
17
+
18
+ # 1.6.8
19
+
20
+ - The 1.6.x series will be the last to support Ruby 1.8.7
21
+ - Pin mime-types to < 2.0 to maintain Ruby 1.8.7 support
22
+ - Add Gemfile, AUTHORS, add license to gemspec
23
+ - Point homepage at https://github.com/rest-client/rest-client
24
+ - Clean up and fix various tests and ruby warnings
25
+ - Backport `ssl_verify_callback` functionality from 1.7.0
26
+
27
+ # 1.6.7
28
+
29
+ - rebuild with 1.8.7 to avoid https://github.com/rubygems/rubygems/pull/57
30
+
31
+ # 1.6.6
32
+
33
+ - 1.6.5 was yanked
34
+
35
+ # 1.6.5
36
+
37
+ - RFC6265 requires single SP after ';' for separating parameters pairs in the 'Cookie:' header (patch provided by Hiroshi Nakamura)
38
+ - enable url parameters for all actions
39
+ - detect file parameters in arrays
40
+ - allow disabling the timeouts by passing -1 (patch provided by Sven Böhm)
41
+
42
+ # 1.6.4
43
+
44
+ - fix restclient script compatibility with 1.9.2
45
+ - fix unlinking temp file (patch provided by Evan Smith)
46
+ - monkeypatching ruby for http patch method (patch provided by Syl Turner)
47
+
48
+ # 1.6.3
49
+
50
+ - 1.6.2 was yanked
51
+
52
+ # 1.6.2
53
+
54
+ - add support for HEAD in resources (patch provided by tpresa)
55
+ - fix shell for 1.9.2
56
+ - workaround when some gem monkeypatch net/http (patch provided by Ian Warshak)
57
+ - DELETE requests should process parameters just like GET and HEAD
58
+ - adding :block_response parameter for manual processing
59
+ - limit number of redirections (patch provided by Chris Dinn)
60
+ - close and unlink the temp file created by playload (patch provided by Chris Green)
61
+ - make gemspec Rubygems 1.8 compatible (patch provided by David Backeus)
62
+ - added RestClient.reset_before_execution_procs (patch provided by Cloudify)
63
+ - added PATCH method (patch provided by Jeff Remer)
64
+ - hack for HTTP servers that use raw DEFLATE compression, see http://www.ruby-forum.com/topic/136825 (path provided by James Reeves)
65
+
1
66
  # 1.6.1
2
67
 
3
68
  - add response body in Exception#inspect
@@ -6,6 +71,7 @@
6
71
  - block passing in Resource#[] (patch provided by Niko Dittmann)
7
72
  - cookies set in a response should be kept in a redirect
8
73
  - HEAD requests should process parameters just like GET (patch provided by Rob Eanes)
74
+ - exception message should never be nil (patch provided by Michael Klett)
9
75
 
10
76
  # 1.6.0
11
77
 
@@ -91,4 +157,4 @@ The only breaking change should be the exception classes, but as the new classes
91
157
 
92
158
  All changes exept the last one should be fully compatible with the previous version.
93
159
 
94
- NOTE: due to a dependency problem and to the last change, heroku users should update their heroku gem to >= 1.5.3 to be able to use this version.
160
+ NOTE: due to a dependency problem and to the last change, heroku users should update their heroku gem to >= 1.5.3 to be able to use this version.
@@ -9,6 +9,8 @@ rescue LoadError => e
9
9
  raise LoadError, "no such file to load -- net/https. Try running apt-get install libopenssl-ruby"
10
10
  end
11
11
 
12
+ require File.dirname(__FILE__) + '/restclient/version'
13
+ require File.dirname(__FILE__) + '/restclient/platform'
12
14
  require File.dirname(__FILE__) + '/restclient/exceptions'
13
15
  require File.dirname(__FILE__) + '/restclient/request'
14
16
  require File.dirname(__FILE__) + '/restclient/abstract_response'
@@ -72,6 +74,10 @@ module RestClient
72
74
  Request.execute(:method => :post, :url => url, :payload => payload, :headers => headers, &block)
73
75
  end
74
76
 
77
+ def self.patch(url, payload, headers={}, &block)
78
+ Request.execute(:method => :patch, :url => url, :payload => payload, :headers => headers, &block)
79
+ end
80
+
75
81
  def self.put(url, payload, headers={}, &block)
76
82
  Request.execute(:method => :put, :url => url, :payload => payload, :headers => headers, &block)
77
83
  end
@@ -99,12 +105,6 @@ module RestClient
99
105
  @@log = create_log log
100
106
  end
101
107
 
102
- def self.version
103
- version_path = File.dirname(__FILE__) + "/../VERSION"
104
- return File.read(version_path).chomp if File.file?(version_path)
105
- "0.0.0"
106
- end
107
-
108
108
  # Create a log that respond to << like a logger
109
109
  # param can be 'stdout', 'stderr', a string (then we will log to that file) or a logger (then we return it)
110
110
  def self.create_log param
@@ -158,6 +158,11 @@ module RestClient
158
158
  @@before_execution_procs << proc
159
159
  end
160
160
 
161
+ # Reset the procs to be called before each request is executed.
162
+ def self.reset_before_execution_procs
163
+ @@before_execution_procs = []
164
+ end
165
+
161
166
  def self.before_execution_procs # :nodoc:
162
167
  @@before_execution_procs
163
168
  end
@@ -31,7 +31,7 @@ module RestClient
31
31
 
32
32
  # Return the default behavior corresponding to the response code:
33
33
  # 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
34
- def return! request = nil, result = nil, & block
34
+ def return! request = nil, result = nil, & block
35
35
  if (200..207).include? code
36
36
  self
37
37
  elsif [301, 302, 307].include? code
@@ -47,7 +47,7 @@ module RestClient
47
47
  elsif Exceptions::EXCEPTIONS_MAP[code]
48
48
  raise Exceptions::EXCEPTIONS_MAP[code].new(self, code)
49
49
  else
50
- raise RequestFailed self
50
+ raise RequestFailed.new(self, code)
51
51
  end
52
52
  end
53
53
 
@@ -67,9 +67,13 @@ module RestClient
67
67
  end
68
68
  args[:url] = url
69
69
  if request
70
+ if request.max_redirects == 0
71
+ raise MaxRedirectsReached
72
+ end
70
73
  args[:password] = request.password
71
74
  args[:user] = request.user
72
75
  args[:headers] = request.headers
76
+ args[:max_redirects] = request.max_redirects - 1
73
77
  # pass any cookie set in the result
74
78
  if result && result['set-cookie']
75
79
  args[:headers][:cookies] = (args[:headers][:cookies] || {}).merge(parse_cookie(result['set-cookie']))
@@ -21,7 +21,7 @@ module RestClient
21
21
  305 => 'Use Proxy', # http/1.1
22
22
  306 => 'Switch Proxy', # no longer used
23
23
  307 => 'Temporary Redirect', # http/1.1
24
-
24
+
25
25
  400 => 'Bad Request',
26
26
  401 => 'Unauthorized',
27
27
  402 => 'Payment Required',
@@ -46,7 +46,7 @@ module RestClient
46
46
  423 => 'Locked', #WebDAV
47
47
  424 => 'Failed Dependency', #WebDAV
48
48
  425 => 'Unordered Collection', #WebDAV
49
- 426 => 'Upgrade Required',
49
+ 426 => 'Upgrade Required',
50
50
  449 => 'Retry With', #Microsoft
51
51
  450 => 'Blocked By Windows Parental Controls', #Microsoft
52
52
 
@@ -80,10 +80,12 @@ module RestClient
80
80
  # For example, the entire result body (which is
81
81
  # probably an HTML error page) is e.response.
82
82
  class Exception < RuntimeError
83
- attr_accessor :message, :response
83
+ attr_accessor :response
84
+ attr_writer :message
84
85
 
85
86
  def initialize response = nil, initial_response_code = nil
86
87
  @response = response
88
+ @message = nil
87
89
  @initial_response_code = initial_response_code
88
90
 
89
91
  # compatibility: this make the exception behave like a Net::HTTPResponse
@@ -111,6 +113,10 @@ module RestClient
111
113
  inspect
112
114
  end
113
115
 
116
+ def message
117
+ @message || self.class.name
118
+ end
119
+
114
120
  end
115
121
 
116
122
  # Compatibility
@@ -149,7 +155,9 @@ module RestClient
149
155
  # A redirect was encountered; caught by execute to retry with the new url.
150
156
  class Redirect < Exception
151
157
 
152
- message = 'Redirect'
158
+ def message
159
+ 'Redirect'
160
+ end
153
161
 
154
162
  attr_accessor :url
155
163
 
@@ -158,11 +166,20 @@ module RestClient
158
166
  end
159
167
  end
160
168
 
169
+ class MaxRedirectsReached < Exception
170
+ def message
171
+ 'Maximum number of redirect reached'
172
+ end
173
+ end
174
+
161
175
  # The server broke the connection prior to the request completing. Usually
162
176
  # this means it crashed, or sometimes that your network connection was
163
177
  # severed before it could complete.
164
178
  class ServerBrokeConnection < Exception
165
- message = 'Server broke connection'
179
+ def initialize(message = 'Server broke connection')
180
+ super nil, nil
181
+ self.message = message
182
+ end
166
183
  end
167
184
 
168
185
  class SSLCertificateNotVerified < Exception
@@ -1,12 +1,46 @@
1
- #
2
- # Replace the request method in Net::HTTP to sniff the body type
3
- # and set the stream if appropriate
4
- #
5
- # Taken from:
6
- # http://www.missiondata.com/blog/ruby/29/streaming-data-to-s3-with-ruby/
7
-
8
1
  module Net
9
2
  class HTTP
3
+
4
+ # Adding the patch method if it doesn't exist (rest-client issue: https://github.com/archiloque/rest-client/issues/79)
5
+ if !defined?(Net::HTTP::Patch)
6
+ # Code taken from this commit: https://github.com/ruby/ruby/commit/ab70e53ac3b5102d4ecbe8f38d4f76afad29d37d#lib/net/http.rb
7
+ class Protocol
8
+ # Sends a PATCH request to the +path+ and gets a response,
9
+ # as an HTTPResponse object.
10
+ def patch(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
11
+ send_entity(path, data, initheader, dest, Patch, &block)
12
+ end
13
+
14
+ # Executes a request which uses a representation
15
+ # and returns its body.
16
+ def send_entity(path, data, initheader, dest, type, &block)
17
+ res = nil
18
+ request(type.new(path, initheader), data) {|r|
19
+ r.read_body dest, &block
20
+ res = r
21
+ }
22
+ unless @newimpl
23
+ res.value
24
+ return res, res.body
25
+ end
26
+ res
27
+ end
28
+ end
29
+
30
+ class Patch < HTTPRequest
31
+ METHOD = 'PATCH'
32
+ REQUEST_HAS_BODY = true
33
+ RESPONSE_HAS_BODY = true
34
+ end
35
+ end
36
+
37
+ #
38
+ # Replace the request method in Net::HTTP to sniff the body type
39
+ # and set the stream if appropriate
40
+ #
41
+ # Taken from:
42
+ # http://www.missiondata.com/blog/ruby/29/streaming-data-to-s3-with-ruby/
43
+
10
44
  alias __request__ request
11
45
 
12
46
  def request(req, body=nil, &block)
@@ -9,14 +9,14 @@ module RestClient
9
9
  def generate(params)
10
10
  if params.is_a?(String)
11
11
  Base.new(params)
12
- elsif params.respond_to?(:read)
13
- Streamed.new(params)
14
- elsif params
12
+ elsif params.is_a?(Hash)
15
13
  if params.delete(:multipart) == true || has_file?(params)
16
14
  Multipart.new(params)
17
15
  else
18
16
  UrlEncoded.new(params)
19
17
  end
18
+ elsif params.respond_to?(:read)
19
+ Streamed.new(params)
20
20
  else
21
21
  nil
22
22
  end
@@ -27,6 +27,21 @@ module RestClient
27
27
  case v
28
28
  when Hash
29
29
  has_file?(v)
30
+ when Array
31
+ has_file_array?(v)
32
+ else
33
+ v.respond_to?(:path) && v.respond_to?(:read)
34
+ end
35
+ end
36
+ end
37
+
38
+ def has_file_array?(params)
39
+ params.any? do |v|
40
+ case v
41
+ when Hash
42
+ has_file?(v)
43
+ when Array
44
+ has_file_array?(v)
30
45
  else
31
46
  v.respond_to?(:path) && v.respond_to?(:read)
32
47
  end
@@ -70,7 +85,7 @@ module RestClient
70
85
  result = []
71
86
  value.each do |elem|
72
87
  if elem.is_a? Hash
73
- result += flatten_params(elem, calculated_key)
88
+ result += flatten_params(elem, calculated_key)
74
89
  elsif elem.is_a? Array
75
90
  result += flatten_params_array(elem, calculated_key)
76
91
  else
@@ -91,7 +106,7 @@ module RestClient
91
106
  alias :length :size
92
107
 
93
108
  def close
94
- @stream.close
109
+ @stream.close unless @stream.closed?
95
110
  end
96
111
 
97
112
  def inspect
@@ -132,12 +147,17 @@ module RestClient
132
147
 
133
148
  # for UrlEncoded escape the keys
134
149
  def handle_key key
135
- URI.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
150
+ parser.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
136
151
  end
137
152
 
138
153
  def headers
139
154
  super.merge({'Content-Type' => 'application/x-www-form-urlencoded'})
140
155
  end
156
+
157
+ private
158
+ def parser
159
+ URI.const_defined?(:Parser) ? URI::Parser.new : URI
160
+ end
141
161
  end
142
162
 
143
163
  class Multipart < Base
@@ -190,7 +210,7 @@ module RestClient
190
210
  s.write(data)
191
211
  end
192
212
  ensure
193
- v.close
213
+ v.close if v.respond_to?(:close)
194
214
  end
195
215
  end
196
216
 
@@ -213,7 +233,7 @@ module RestClient
213
233
  end
214
234
 
215
235
  def close
216
- @stream.close
236
+ @stream.close!
217
237
  end
218
238
  end
219
239
  end
@@ -0,0 +1,29 @@
1
+ module RestClient
2
+ module Platform
3
+ # Return true if we are running on a darwin-based Ruby platform. This will
4
+ # be false for jruby even on OS X.
5
+ #
6
+ # @return [Boolean]
7
+ def self.mac?
8
+ RUBY_PLATFORM.include?('darwin')
9
+ end
10
+
11
+ # Return true if we are running on Windows.
12
+ #
13
+ # @return [Boolean]
14
+ #
15
+ def self.windows?
16
+ # Ruby only sets File::ALT_SEPARATOR on Windows, and the Ruby standard
17
+ # library uses that to test what platform it's on.
18
+ !!File::ALT_SEPARATOR
19
+ end
20
+
21
+ # Return true if we are running on jruby.
22
+ #
23
+ # @return [Boolean]
24
+ #
25
+ def self.jruby?
26
+ RUBY_PLATFORM == 'java'
27
+ end
28
+ end
29
+ end
@@ -16,16 +16,20 @@ module RestClient
16
16
  # * :headers a hash containing the request headers
17
17
  # * :cookies will replace possible cookies in the :headers
18
18
  # * :user and :password for basic auth, will be replaced by a user/password available in the :url
19
+ # * :block_response call the provided block with the HTTPResponse as parameter
19
20
  # * :raw_response return a low-level RawResponse instead of a Response
21
+ # * :max_redirects maximum number of redirections (default to 10)
20
22
  # * :verify_ssl enable ssl verification, possible values are constants from OpenSSL::SSL
21
- # * :timeout and :open_timeout
23
+ # * :timeout and :open_timeout passing in -1 will disable the timeout by setting the corresponding net timeout values to nil
22
24
  # * :ssl_client_cert, :ssl_client_key, :ssl_ca_file
25
+ # * :ssl_verify_callback, :ssl_verify_callback_warnings
23
26
  class Request
24
27
 
25
28
  attr_reader :method, :url, :headers, :cookies,
26
- :payload, :user, :password, :timeout,
29
+ :payload, :user, :password, :timeout, :max_redirects,
27
30
  :open_timeout, :raw_response, :verify_ssl, :ssl_client_cert,
28
- :ssl_client_key, :ssl_ca_file, :processed_headers, :args
31
+ :ssl_client_key, :ssl_ca_file, :processed_headers, :args,
32
+ :ssl_verify_callback, :ssl_verify_callback_warnings
29
33
 
30
34
  def self.execute(args, & block)
31
35
  new(args).execute(& block)
@@ -35,7 +39,7 @@ module RestClient
35
39
  @method = args[:method] or raise ArgumentError, "must pass :method"
36
40
  @headers = args[:headers] || {}
37
41
  if args[:url]
38
- @url = process_get_params(args[:url], headers)
42
+ @url = process_url_params(args[:url], headers)
39
43
  else
40
44
  raise ArgumentError, "must pass :url"
41
45
  end
@@ -45,12 +49,16 @@ module RestClient
45
49
  @password = args[:password]
46
50
  @timeout = args[:timeout]
47
51
  @open_timeout = args[:open_timeout]
52
+ @block_response = args[:block_response]
48
53
  @raw_response = args[:raw_response] || false
49
54
  @verify_ssl = args[:verify_ssl] || false
50
55
  @ssl_client_cert = args[:ssl_client_cert] || nil
51
56
  @ssl_client_key = args[:ssl_client_key] || nil
52
57
  @ssl_ca_file = args[:ssl_ca_file] || nil
58
+ @ssl_verify_callback = args[:ssl_verify_callback] || nil
59
+ @ssl_verify_callback_warnings = args.fetch(:ssl_verify_callback, true)
53
60
  @tf = nil # If you are a raw request, this is your tempfile
61
+ @max_redirects = args[:max_redirects] || 10
54
62
  @processed_headers = make_headers headers
55
63
  @args = args
56
64
  end
@@ -58,26 +66,24 @@ module RestClient
58
66
  def execute & block
59
67
  uri = parse_url_with_auth(url)
60
68
  transmit uri, net_http_request_class(method).new(uri.request_uri, processed_headers), payload, & block
69
+ ensure
70
+ payload.close if payload
61
71
  end
62
72
 
63
- # Extract the query parameters for get request and append them to the url
64
- def process_get_params url, headers
65
- if [:get, :head].include? method
66
- get_params = {}
67
- headers.delete_if do |key, value|
68
- if 'params' == key.to_s.downcase && value.is_a?(Hash)
69
- get_params.merge! value
70
- true
71
- else
72
- false
73
- end
74
- end
75
- unless get_params.empty?
76
- query_string = get_params.collect { |k, v| "#{k.to_s}=#{CGI::escape(v.to_s)}" }.join('&')
77
- url + "?#{query_string}"
73
+ # Extract the query parameters and append them to the url
74
+ def process_url_params url, headers
75
+ url_params = {}
76
+ headers.delete_if do |key, value|
77
+ if 'params' == key.to_s.downcase && value.is_a?(Hash)
78
+ url_params.merge! value
79
+ true
78
80
  else
79
- url
81
+ false
80
82
  end
83
+ end
84
+ unless url_params.empty?
85
+ query_string = url_params.collect { |k, v| "#{k.to_s}=#{CGI::escape(v.to_s)}" }.join('&')
86
+ url + "?#{query_string}"
81
87
  else
82
88
  url
83
89
  end
@@ -85,7 +91,7 @@ module RestClient
85
91
 
86
92
  def make_headers user_headers
87
93
  unless @cookies.empty?
88
- user_headers[:cookie] = @cookies.map { |(key, val)| "#{key.to_s}=#{CGI::unescape(val)}" }.sort.join(';')
94
+ user_headers[:cookie] = @cookies.map { |(key, val)| "#{key.to_s}=#{CGI::unescape(val)}" }.sort.join('; ')
89
95
  end
90
96
  headers = stringify_headers(default_headers).merge(stringify_headers(user_headers))
91
97
  headers.merge!(@payload.headers) if @payload
@@ -127,29 +133,40 @@ module RestClient
127
133
  if p[k].is_a? Hash
128
134
  process_payload(p[k], key)
129
135
  else
130
- value = URI.escape(p[k].to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
136
+ value = parser.escape(p[k].to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
131
137
  "#{key}=#{value}"
132
138
  end
133
139
  end.join("&")
134
140
  end
135
141
  end
136
142
 
143
+ def print_verify_callback_warnings
144
+ warned = false
145
+ if RestClient::Platform.mac?
146
+ warn('warning: ssl_verify_callback return code is ignored on OS X')
147
+ warned = true
148
+ end
149
+ if RestClient::Platform.jruby?
150
+ warn('warning: SSL verify_callback may not work correctly in jruby')
151
+ warn('see https://github.com/jruby/jruby/issues/597')
152
+ warned = true
153
+ end
154
+ warned
155
+ end
156
+
137
157
  def transmit uri, req, payload, & block
138
158
  setup_credentials req
139
159
 
140
160
  net = net_http_class.new(uri.host, uri.port)
141
161
  net.use_ssl = uri.is_a?(URI::HTTPS)
142
- if @verify_ssl == false
143
- net.verify_mode = OpenSSL::SSL::VERIFY_NONE
144
- elsif @verify_ssl.is_a? Integer
145
- net.verify_mode = @verify_ssl
146
- net.verify_callback = lambda do |preverify_ok, ssl_context|
147
- if (!preverify_ok) || ssl_context.error != 0
148
- err_msg = "SSL Verification failed -- Preverify: #{preverify_ok}, Error: #{ssl_context.error_string} (#{ssl_context.error})"
149
- raise SSLCertificateNotVerified.new(err_msg)
150
- end
151
- true
162
+ if @verify_ssl
163
+ if @verify_ssl.is_a? Integer
164
+ net.verify_mode = @verify_ssl
165
+ else
166
+ net.verify_mode = OpenSSL::SSL::VERIFY_PEER
152
167
  end
168
+ else
169
+ net.verify_mode = OpenSSL::SSL::VERIFY_NONE
153
170
  end
154
171
  net.cert = @ssl_client_cert if @ssl_client_cert
155
172
  net.key = @ssl_client_key if @ssl_client_key
@@ -157,6 +174,29 @@ module RestClient
157
174
  net.read_timeout = @timeout if @timeout
158
175
  net.open_timeout = @open_timeout if @open_timeout
159
176
 
177
+ # disable the timeout if the timeout value is -1
178
+ net.read_timeout = nil if @timeout == -1
179
+ net.open_timeout = nil if @open_timeout == -1
180
+
181
+ # verify_callback isn't well supported on all platforms, but do allow
182
+ # users to set one if they want.
183
+ if ssl_verify_callback
184
+ net.verify_callback = ssl_verify_callback
185
+
186
+ # Hilariously, jruby only calls the callback when cert_store is set to
187
+ # something, so make sure to set one.
188
+ # https://github.com/jruby/jruby/issues/597
189
+ if RestClient::Platform.jruby?
190
+ net.cert_store ||= OpenSSL::X509::Store.new
191
+ end
192
+
193
+ if ssl_verify_callback_warnings != false
194
+ if print_verify_callback_warnings
195
+ warn('pass :ssl_verify_callback_warnings => false to silence this')
196
+ end
197
+ end
198
+ end
199
+
160
200
  RestClient.before_execution_procs.each do |before_proc|
161
201
  before_proc.call(req, args)
162
202
  end
@@ -164,14 +204,23 @@ module RestClient
164
204
  log_request
165
205
 
166
206
  net.start do |http|
167
- res = http.request(req, payload) { |http_response| fetch_body(http_response) }
168
- log_response res
169
- process_result res, & block
207
+ if @block_response
208
+ http.request(req, payload ? payload.to_s : nil, & @block_response)
209
+ else
210
+ res = http.request(req, payload ? payload.to_s : nil) { |http_response| fetch_body(http_response) }
211
+ log_response res
212
+ process_result res, & block
213
+ end
170
214
  end
171
215
  rescue EOFError
172
216
  raise RestClient::ServerBrokeConnection
173
217
  rescue Timeout::Error
174
218
  raise RestClient::RequestTimeout
219
+ rescue OpenSSL::SSL::SSLError => error
220
+ # UGH. Not sure if this is needed at all. SSLCertificateNotVerified is not being used internally.
221
+ # I think it would be better to leave SSLError processing to the client (they'd have to do that anyway...)
222
+ raise SSLCertificateNotVerified.new(error.message) if error.message.include?("certificate verify failed")
223
+ raise error
175
224
  end
176
225
 
177
226
  def setup_credentials(req)
@@ -228,7 +277,13 @@ module RestClient
228
277
  elsif content_encoding == 'gzip'
229
278
  Zlib::GzipReader.new(StringIO.new(body)).read
230
279
  elsif content_encoding == 'deflate'
231
- Zlib::Inflate.new.inflate body
280
+ begin
281
+ Zlib::Inflate.new.inflate body
282
+ rescue Zlib::DataError
283
+ # No luck with Zlib decompression. Let's try with raw deflate,
284
+ # like some broken web servers do.
285
+ Zlib::Inflate.new(-Zlib::MAX_WBITS).inflate body
286
+ end
232
287
  else
233
288
  body
234
289
  end
@@ -279,6 +334,11 @@ module RestClient
279
334
  {:accept => '*/*; q=0.5, application/xml', :accept_encoding => 'gzip, deflate'}
280
335
  end
281
336
 
337
+ private
338
+ def parser
339
+ URI.const_defined?(:Parser) ? URI::Parser.new : URI
340
+ end
341
+
282
342
  end
283
343
  end
284
344