rest-client 1.6.1 → 1.6.14
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.
Potentially problematic release.
This version of rest-client might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/.travis.yml +3 -0
- data/AUTHORS +75 -0
- data/Gemfile +7 -0
- data/README.rdoc +52 -21
- data/Rakefile +15 -35
- data/bin/restclient +45 -39
- data/history.md +67 -1
- data/lib/restclient.rb +11 -6
- data/lib/restclient/abstract_response.rb +6 -2
- data/lib/restclient/exceptions.rb +22 -5
- data/lib/restclient/net_http_ext.rb +41 -7
- data/lib/restclient/payload.rb +28 -8
- data/lib/restclient/platform.rb +29 -0
- data/lib/restclient/request.rb +96 -36
- data/lib/restclient/resource.rb +17 -0
- data/lib/restclient/response.rb +3 -1
- data/lib/restclient/version.rb +7 -0
- data/rest-client.gemspec +26 -0
- data/spec/abstract_response_spec.rb +28 -10
- data/spec/base.rb +1 -4
- data/spec/exceptions_spec.rb +31 -12
- data/spec/integration/capath_digicert/244b5494.0 +19 -0
- data/spec/integration/capath_digicert/81b9768f.0 +19 -0
- data/spec/integration/capath_digicert/README +8 -0
- data/spec/integration/capath_digicert/digicert.crt +19 -0
- data/spec/integration/certs/digicert.crt +19 -0
- data/spec/integration/certs/verisign.crt +14 -14
- data/spec/integration/request_spec.rb +54 -4
- data/spec/integration_spec.rb +9 -9
- data/spec/master_shake.jpg +0 -0
- data/spec/payload_spec.rb +60 -35
- data/spec/raw_response_spec.rb +4 -4
- data/spec/request2_spec.rb +22 -4
- data/spec/request_spec.rb +129 -130
- data/spec/resource_spec.rb +30 -18
- data/spec/response_spec.rb +48 -36
- data/spec/restclient_spec.rb +6 -1
- metadata +142 -74
- data/VERSION +0 -1
- 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.
|
data/lib/restclient.rb
CHANGED
@@ -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
|
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
|
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 :
|
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
|
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)
|
data/lib/restclient/payload.rb
CHANGED
@@ -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.
|
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 +=
|
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
|
-
|
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
|
data/lib/restclient/request.rb
CHANGED
@@ -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 =
|
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
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
-
|
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 =
|
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
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
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
|
-
|
168
|
-
|
169
|
-
|
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
|
-
|
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
|
|