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