rest-client 2.0.2 → 2.1.0
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.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.mailmap +10 -0
- data/.rubocop +2 -0
- data/.rubocop-disables.yml +46 -44
- data/.rubocop.yml +5 -0
- data/.travis.yml +31 -17
- data/AUTHORS +8 -0
- data/README.md +126 -9
- data/Rakefile +12 -4
- data/history.md +53 -0
- data/lib/restclient.rb +0 -1
- data/lib/restclient/abstract_response.rb +28 -2
- data/lib/restclient/exceptions.rb +3 -3
- data/lib/restclient/payload.rb +29 -4
- data/lib/restclient/raw_response.rb +17 -6
- data/lib/restclient/request.rb +94 -67
- data/lib/restclient/resource.rb +16 -6
- data/lib/restclient/response.rb +14 -4
- data/lib/restclient/utils.rb +47 -8
- data/lib/restclient/version.rb +2 -2
- data/rest-client.gemspec +3 -2
- data/spec/ISS.jpg +0 -0
- data/spec/helpers.rb +37 -5
- data/spec/integration/capath_digicert/3513523f.0 +22 -0
- data/spec/integration/capath_digicert/399e7759.0 +22 -0
- data/spec/integration/capath_digicert/digicert.crt +20 -17
- data/spec/integration/certs/digicert.crt +20 -17
- data/spec/integration/httpbin_spec.rb +41 -0
- data/spec/integration/integration_spec.rb +0 -7
- data/spec/unit/abstract_response_spec.rb +7 -7
- data/spec/unit/payload_spec.rb +51 -19
- data/spec/unit/raw_response_spec.rb +6 -2
- data/spec/unit/request2_spec.rb +8 -8
- data/spec/unit/request_spec.rb +53 -65
- data/spec/unit/resource_spec.rb +7 -7
- data/spec/unit/response_spec.rb +33 -22
- data/spec/unit/restclient_spec.rb +3 -2
- data/spec/unit/utils_spec.rb +10 -10
- metadata +34 -13
- data/spec/integration/capath_digicert/244b5494.0 +0 -19
- data/spec/integration/capath_digicert/81b9768f.0 +0 -19
- data/spec/unit/master_shake.jpg +0 -0
data/Rakefile
CHANGED
@@ -38,12 +38,11 @@ desc 'Regenerate authors file'
|
|
38
38
|
task :authors do
|
39
39
|
Dir.chdir(File.dirname(__FILE__)) do
|
40
40
|
File.open('AUTHORS', 'w') do |f|
|
41
|
-
f.write
|
41
|
+
f.write <<-EOM
|
42
42
|
The Ruby REST Client would not be what it is today without the help of
|
43
43
|
the following kind souls:
|
44
44
|
|
45
45
|
EOM
|
46
|
-
)
|
47
46
|
end
|
48
47
|
|
49
48
|
sh 'git shortlog -s | cut -f 2 >> AUTHORS'
|
@@ -70,8 +69,8 @@ namespace :all do
|
|
70
69
|
task :build => ['ruby:build'] + \
|
71
70
|
WindowsPlatforms.map {|p| "windows:#{p}:build"}
|
72
71
|
|
73
|
-
desc "Create tag v#{RestClient::VERSION} and for all platforms build and
|
74
|
-
"rest-client #{RestClient::VERSION} to Rubygems"
|
72
|
+
desc "Create tag v#{RestClient::VERSION} and for all platforms build and " \
|
73
|
+
"push rest-client #{RestClient::VERSION} to Rubygems"
|
75
74
|
task :release => ['build', 'ruby:release'] + \
|
76
75
|
WindowsPlatforms.map {|p| "windows:#{p}:push"}
|
77
76
|
|
@@ -130,3 +129,12 @@ Rake::RDocTask.new do |t|
|
|
130
129
|
t.rdoc_files.include('README.md')
|
131
130
|
t.rdoc_files.include('lib/*.rb')
|
132
131
|
end
|
132
|
+
|
133
|
+
############################
|
134
|
+
|
135
|
+
require 'rubocop/rake_task'
|
136
|
+
|
137
|
+
RuboCop::RakeTask.new(:rubocop) do |t|
|
138
|
+
t.options = ['--display-cop-names']
|
139
|
+
end
|
140
|
+
alias_task(:lint, :rubocop)
|
data/history.md
CHANGED
@@ -1,3 +1,40 @@
|
|
1
|
+
# 2.1.0
|
2
|
+
|
3
|
+
- Add a dependency on http-accept for parsing Content-Type charset headers.
|
4
|
+
This works around a bad memory leak introduced in MRI Ruby 2.4.0 and fixed in
|
5
|
+
Ruby 2.4.2. (#615)
|
6
|
+
- Use mime/types/columnar from mime-types 2.6.1+, which is leaner in memory
|
7
|
+
usage than the older storage model of mime-types. (#393)
|
8
|
+
- Add `:log` option to individual requests. This allows users to set a log on a
|
9
|
+
per-request / per-resource basis instead of the kludgy global log. (#538)
|
10
|
+
- Log request duration by tracking request start and end times. Make
|
11
|
+
`log_response` a method on the Response object, and ensure the `size` method
|
12
|
+
works on RawResponse objects. (#126)
|
13
|
+
- `# => 200 OK | text/html 1270 bytes, 0.08s`
|
14
|
+
- Also add a new `:stream_log_percent` parameter, which is applicable only
|
15
|
+
when `:raw_response => true` is set. This causes progress logs to be
|
16
|
+
emitted only on every N% (default 10%) of the total download size rather
|
17
|
+
than on every chunk.
|
18
|
+
- Drop custom handling of compression and use built-in Net::HTTP support for
|
19
|
+
supported Content-Encodings like gzip and deflate. Don't set any explicit
|
20
|
+
`Accept-Encoding` header, rely instead on Net::HTTP defaults. (#597)
|
21
|
+
- Note: this changes behavior for compressed responses when using
|
22
|
+
`:raw_response => true`. Previously the raw response would not have been
|
23
|
+
uncompressed by rest-client, but now Net::HTTP will uncompress it.
|
24
|
+
- The previous fix to avoid having Netrc username/password override an
|
25
|
+
Authorization header was case-sensitive and incomplete. Fix this by
|
26
|
+
respecting existing Authorization headers, regardless of letter case. (#550)
|
27
|
+
- Handle ParamsArray payloads. Previously, rest-client would silently drop a
|
28
|
+
ParamsArray passed as the payload. Instead, automatically use
|
29
|
+
Payload::Multipart if the ParamsArray contains a file handle, or use
|
30
|
+
Payload::UrlEncoded if it doesn't. (#508)
|
31
|
+
- Gracefully handle Payload objects (Payload::Base or subclasses) that are
|
32
|
+
passed as a payload argument. Previously, `Payload.generate` would wrap a
|
33
|
+
Payload object in Payload::Streamed, creating a pointlessly nested payload.
|
34
|
+
Also add a `closed?` method to Payload objects, and don't error in
|
35
|
+
`short_inspect` if `size` returns nil. (#603)
|
36
|
+
- Test with an image in the public domain to avoid licensing complexity. (#607)
|
37
|
+
|
1
38
|
# 2.0.2
|
2
39
|
|
3
40
|
- Suppress the header override warning introduced in 2.0.1 if the value is the
|
@@ -179,6 +216,22 @@ release:
|
|
179
216
|
- Disable timeouts with :timeout => nil rather than :timeout => -1
|
180
217
|
- Drop all Net::HTTP monkey patches
|
181
218
|
|
219
|
+
# 1.6.14
|
220
|
+
|
221
|
+
- This release is unchanged from 1.6.9. It was published in order to supersede
|
222
|
+
the malicious 1.6.10-13 versions, even for users who are still pinning to the
|
223
|
+
legacy 1.6.x series. All users are encouraged to upgrade to rest-client 2.x.
|
224
|
+
|
225
|
+
# 1.6.10, 1.6.11, 1.6.12, 1.6.13 (CVE-2019-15224)
|
226
|
+
|
227
|
+
- These versions were pushed by a malicious actor and included a backdoor permitting
|
228
|
+
remote code execution in Rails environments. (#713)
|
229
|
+
- They were live for about five days before being yanked.
|
230
|
+
|
231
|
+
# 1.6.9
|
232
|
+
|
233
|
+
- Move rdoc to a development dependency
|
234
|
+
|
182
235
|
# 1.6.8
|
183
236
|
|
184
237
|
- The 1.6.x series will be the last to support Ruby 1.8.7
|
data/lib/restclient.rb
CHANGED
@@ -5,12 +5,27 @@ module RestClient
|
|
5
5
|
|
6
6
|
module AbstractResponse
|
7
7
|
|
8
|
-
attr_reader :net_http_res, :request
|
8
|
+
attr_reader :net_http_res, :request, :start_time, :end_time, :duration
|
9
9
|
|
10
10
|
def inspect
|
11
11
|
raise NotImplementedError.new('must override in subclass')
|
12
12
|
end
|
13
13
|
|
14
|
+
# Logger from the request, potentially nil.
|
15
|
+
def log
|
16
|
+
request.log
|
17
|
+
end
|
18
|
+
|
19
|
+
def log_response
|
20
|
+
return unless log
|
21
|
+
|
22
|
+
code = net_http_res.code
|
23
|
+
res_name = net_http_res.class.to_s.gsub(/\ANet::HTTP/, '')
|
24
|
+
content_type = (net_http_res['Content-type'] || '').gsub(/;.*\z/, '')
|
25
|
+
|
26
|
+
log << "# => #{code} #{res_name} | #{content_type} #{size} bytes, #{sprintf('%.2f', duration)}s\n"
|
27
|
+
end
|
28
|
+
|
14
29
|
# HTTP status code
|
15
30
|
def code
|
16
31
|
@code ||= @net_http_res.code.to_i
|
@@ -31,9 +46,20 @@ module RestClient
|
|
31
46
|
@raw_headers ||= @net_http_res.to_hash
|
32
47
|
end
|
33
48
|
|
34
|
-
|
49
|
+
# @param [Net::HTTPResponse] net_http_res
|
50
|
+
# @param [RestClient::Request] request
|
51
|
+
# @param [Time] start_time
|
52
|
+
def response_set_vars(net_http_res, request, start_time)
|
35
53
|
@net_http_res = net_http_res
|
36
54
|
@request = request
|
55
|
+
@start_time = start_time
|
56
|
+
@end_time = Time.now
|
57
|
+
|
58
|
+
if @start_time
|
59
|
+
@duration = @end_time - @start_time
|
60
|
+
else
|
61
|
+
@duration = nil
|
62
|
+
end
|
37
63
|
|
38
64
|
# prime redirection history
|
39
65
|
history
|
@@ -148,7 +148,7 @@ module RestClient
|
|
148
148
|
end
|
149
149
|
|
150
150
|
# Compatibility
|
151
|
-
class ExceptionWithResponse < Exception
|
151
|
+
class ExceptionWithResponse < RestClient::Exception
|
152
152
|
end
|
153
153
|
|
154
154
|
# The request failed with an error code not managed by the code
|
@@ -228,14 +228,14 @@ module RestClient
|
|
228
228
|
# The server broke the connection prior to the request completing. Usually
|
229
229
|
# this means it crashed, or sometimes that your network connection was
|
230
230
|
# severed before it could complete.
|
231
|
-
class ServerBrokeConnection < Exception
|
231
|
+
class ServerBrokeConnection < RestClient::Exception
|
232
232
|
def initialize(message = 'Server broke connection')
|
233
233
|
super nil, nil
|
234
234
|
self.message = message
|
235
235
|
end
|
236
236
|
end
|
237
237
|
|
238
|
-
class SSLCertificateNotVerified < Exception
|
238
|
+
class SSLCertificateNotVerified < RestClient::Exception
|
239
239
|
def initialize(message = 'SSL certificate not verified')
|
240
240
|
super nil, nil
|
241
241
|
self.message = message
|
data/lib/restclient/payload.rb
CHANGED
@@ -2,14 +2,22 @@ require 'tempfile'
|
|
2
2
|
require 'securerandom'
|
3
3
|
require 'stringio'
|
4
4
|
|
5
|
-
|
5
|
+
begin
|
6
|
+
# Use mime/types/columnar if available, for reduced memory usage
|
7
|
+
require 'mime/types/columnar'
|
8
|
+
rescue LoadError
|
9
|
+
require 'mime/types'
|
10
|
+
end
|
6
11
|
|
7
12
|
module RestClient
|
8
13
|
module Payload
|
9
14
|
extend self
|
10
15
|
|
11
16
|
def generate(params)
|
12
|
-
if params.is_a?(
|
17
|
+
if params.is_a?(RestClient::Payload::Base)
|
18
|
+
# pass through Payload objects unchanged
|
19
|
+
params
|
20
|
+
elsif params.is_a?(String)
|
13
21
|
Base.new(params)
|
14
22
|
elsif params.is_a?(Hash)
|
15
23
|
if params.delete(:multipart) == true || has_file?(params)
|
@@ -17,6 +25,12 @@ module RestClient
|
|
17
25
|
else
|
18
26
|
UrlEncoded.new(params)
|
19
27
|
end
|
28
|
+
elsif params.is_a?(ParamsArray)
|
29
|
+
if _has_file?(params)
|
30
|
+
Multipart.new(params)
|
31
|
+
else
|
32
|
+
UrlEncoded.new(params)
|
33
|
+
end
|
20
34
|
elsif params.respond_to?(:read)
|
21
35
|
Streamed.new(params)
|
22
36
|
else
|
@@ -76,12 +90,20 @@ module RestClient
|
|
76
90
|
@stream.close unless @stream.closed?
|
77
91
|
end
|
78
92
|
|
93
|
+
def closed?
|
94
|
+
@stream.closed?
|
95
|
+
end
|
96
|
+
|
79
97
|
def to_s_inspect
|
80
98
|
to_s.inspect
|
81
99
|
end
|
82
100
|
|
83
101
|
def short_inspect
|
84
|
-
|
102
|
+
if size && size > 500
|
103
|
+
"#{size} byte(s) length"
|
104
|
+
else
|
105
|
+
to_s_inspect
|
106
|
+
end
|
85
107
|
end
|
86
108
|
|
87
109
|
end
|
@@ -99,6 +121,9 @@ module RestClient
|
|
99
121
|
end
|
100
122
|
end
|
101
123
|
|
124
|
+
# TODO (breaks compatibility): ought to use mime_for() to autodetect the
|
125
|
+
# Content-Type for stream objects that have a filename.
|
126
|
+
|
102
127
|
alias :length :size
|
103
128
|
end
|
104
129
|
|
@@ -119,7 +144,7 @@ module RestClient
|
|
119
144
|
def build_stream(params)
|
120
145
|
b = '--' + boundary
|
121
146
|
|
122
|
-
@stream = Tempfile.new(
|
147
|
+
@stream = Tempfile.new('rest-client.multipart.')
|
123
148
|
@stream.binmode
|
124
149
|
@stream.write(b + EOL)
|
125
150
|
|
@@ -13,25 +13,36 @@ module RestClient
|
|
13
13
|
|
14
14
|
include AbstractResponse
|
15
15
|
|
16
|
-
attr_reader :file, :request
|
16
|
+
attr_reader :file, :request, :start_time, :end_time
|
17
17
|
|
18
18
|
def inspect
|
19
19
|
"<RestClient::RawResponse @code=#{code.inspect}, @file=#{file.inspect}, @request=#{request.inspect}>"
|
20
20
|
end
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
# @param [Tempfile] tempfile The temporary file containing the body
|
23
|
+
# @param [Net::HTTPResponse] net_http_res
|
24
|
+
# @param [RestClient::Request] request
|
25
|
+
# @param [Time] start_time
|
26
|
+
def initialize(tempfile, net_http_res, request, start_time=nil)
|
24
27
|
@file = tempfile
|
25
|
-
|
28
|
+
|
29
|
+
# reopen the tempfile so we can read it
|
30
|
+
@file.open
|
31
|
+
|
32
|
+
response_set_vars(net_http_res, request, start_time)
|
26
33
|
end
|
27
34
|
|
28
35
|
def to_s
|
29
|
-
|
36
|
+
body
|
37
|
+
end
|
38
|
+
|
39
|
+
def body
|
40
|
+
@file.rewind
|
30
41
|
@file.read
|
31
42
|
end
|
32
43
|
|
33
44
|
def size
|
34
|
-
|
45
|
+
file.size
|
35
46
|
end
|
36
47
|
|
37
48
|
end
|
data/lib/restclient/request.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
require 'tempfile'
|
2
|
-
require 'mime/types'
|
3
2
|
require 'cgi'
|
4
3
|
require 'netrc'
|
5
4
|
require 'set'
|
6
5
|
|
6
|
+
begin
|
7
|
+
# Use mime/types/columnar if available, for reduced memory usage
|
8
|
+
require 'mime/types/columnar'
|
9
|
+
rescue LoadError
|
10
|
+
require 'mime/types'
|
11
|
+
end
|
12
|
+
|
7
13
|
module RestClient
|
8
14
|
# This class is used internally by RestClient to send the request, but you can also
|
9
15
|
# call it directly if you'd like to use a method not supported by the
|
@@ -22,6 +28,11 @@ module RestClient
|
|
22
28
|
# * :user and :password for basic auth, will be replaced by a user/password available in the :url
|
23
29
|
# * :block_response call the provided block with the HTTPResponse as parameter
|
24
30
|
# * :raw_response return a low-level RawResponse instead of a Response
|
31
|
+
# * :log Set the log for this request only, overriding RestClient.log, if
|
32
|
+
# any.
|
33
|
+
# * :stream_log_percent (Only relevant with :raw_response => true) Customize
|
34
|
+
# the interval at which download progress is logged. Defaults to every
|
35
|
+
# 10% complete.
|
25
36
|
# * :max_redirects maximum number of redirections (default to 10)
|
26
37
|
# * :proxy An HTTP proxy URI to use for this request. Any value here
|
27
38
|
# (including nil) will override RestClient.proxy.
|
@@ -92,6 +103,12 @@ module RestClient
|
|
92
103
|
@block_response = args[:block_response]
|
93
104
|
@raw_response = args[:raw_response] || false
|
94
105
|
|
106
|
+
@stream_log_percent = args[:stream_log_percent] || 10
|
107
|
+
if @stream_log_percent <= 0 || @stream_log_percent > 100
|
108
|
+
raise ArgumentError.new(
|
109
|
+
"Invalid :stream_log_percent #{@stream_log_percent.inspect}")
|
110
|
+
end
|
111
|
+
|
95
112
|
@proxy = args.fetch(:proxy) if args.include?(:proxy)
|
96
113
|
|
97
114
|
@ssl_opts = {}
|
@@ -131,9 +148,10 @@ module RestClient
|
|
131
148
|
end
|
132
149
|
end
|
133
150
|
|
134
|
-
@
|
151
|
+
@log = args[:log]
|
135
152
|
@max_redirects = args[:max_redirects] || 10
|
136
153
|
@processed_headers = make_headers headers
|
154
|
+
@processed_headers_lowercase = Hash[@processed_headers.map {|k, v| [k.downcase, v]}]
|
137
155
|
@args = args
|
138
156
|
|
139
157
|
@before_execution_proc = args[:before_execution_proc]
|
@@ -356,6 +374,13 @@ module RestClient
|
|
356
374
|
# - headers from the payload object (e.g. Content-Type, Content-Lenth)
|
357
375
|
# - cookie headers from #make_cookie_header
|
358
376
|
#
|
377
|
+
# BUG: stringify_headers does not alter the capitalization of headers that
|
378
|
+
# are passed as strings, it only normalizes those passed as symbols. This
|
379
|
+
# behavior will probably remain for a while for compatibility, but it means
|
380
|
+
# that the warnings that attempt to detect accidental header overrides may
|
381
|
+
# not always work.
|
382
|
+
# https://github.com/rest-client/rest-client/issues/599
|
383
|
+
#
|
359
384
|
# @param [Hash] user_headers User-provided headers to include
|
360
385
|
#
|
361
386
|
# @return [Hash<String, String>] A hash of HTTP headers => values
|
@@ -493,24 +518,6 @@ module RestClient
|
|
493
518
|
cert_store
|
494
519
|
end
|
495
520
|
|
496
|
-
def self.decode content_encoding, body
|
497
|
-
if (!body) || body.empty?
|
498
|
-
body
|
499
|
-
elsif content_encoding == 'gzip'
|
500
|
-
Zlib::GzipReader.new(StringIO.new(body)).read
|
501
|
-
elsif content_encoding == 'deflate'
|
502
|
-
begin
|
503
|
-
Zlib::Inflate.new.inflate body
|
504
|
-
rescue Zlib::DataError
|
505
|
-
# No luck with Zlib decompression. Let's try with raw deflate,
|
506
|
-
# like some broken web servers do.
|
507
|
-
Zlib::Inflate.new(-Zlib::MAX_WBITS).inflate body
|
508
|
-
end
|
509
|
-
else
|
510
|
-
body
|
511
|
-
end
|
512
|
-
end
|
513
|
-
|
514
521
|
def redacted_uri
|
515
522
|
if uri.password
|
516
523
|
sanitized_uri = uri.dup
|
@@ -525,30 +532,29 @@ module RestClient
|
|
525
532
|
redacted_uri.to_s
|
526
533
|
end
|
527
534
|
|
535
|
+
# Default to the global logger if there's not a request-specific one
|
536
|
+
def log
|
537
|
+
@log || RestClient.log
|
538
|
+
end
|
539
|
+
|
528
540
|
def log_request
|
529
|
-
return unless
|
541
|
+
return unless log
|
530
542
|
|
531
543
|
out = []
|
532
544
|
|
533
545
|
out << "RestClient.#{method} #{redacted_url.inspect}"
|
534
546
|
out << payload.short_inspect if payload
|
535
547
|
out << processed_headers.to_a.sort.map { |(k, v)| [k.inspect, v.inspect].join("=>") }.join(", ")
|
536
|
-
|
537
|
-
end
|
538
|
-
|
539
|
-
def log_response res
|
540
|
-
return unless RestClient.log
|
541
|
-
|
542
|
-
size = if @raw_response
|
543
|
-
File.size(@tf.path)
|
544
|
-
else
|
545
|
-
res.body.nil? ? 0 : res.body.size
|
546
|
-
end
|
547
|
-
|
548
|
-
RestClient.log << "# => #{res.code} #{res.class.to_s.gsub(/^Net::HTTP/, '')} | #{(res['Content-type'] || '').gsub(/;.*$/, '')} #{size} bytes\n"
|
548
|
+
log << out.join(', ') + "\n"
|
549
549
|
end
|
550
550
|
|
551
551
|
# Return a hash of headers whose keys are capitalized strings
|
552
|
+
#
|
553
|
+
# BUG: stringify_headers does not fix the capitalization of headers that
|
554
|
+
# are already Strings. Leaving this behavior as is for now for
|
555
|
+
# backwards compatibility.
|
556
|
+
# https://github.com/rest-client/rest-client/issues/599
|
557
|
+
#
|
552
558
|
def stringify_headers headers
|
553
559
|
headers.inject({}) do |result, (key, value)|
|
554
560
|
if key.is_a? Symbol
|
@@ -573,10 +579,13 @@ module RestClient
|
|
573
579
|
end
|
574
580
|
end
|
575
581
|
|
582
|
+
# Default headers set by RestClient. In addition to these headers, servers
|
583
|
+
# will receive headers set by Net::HTTP, such as Accept-Encoding and Host.
|
584
|
+
#
|
585
|
+
# @return [Hash<Symbol, String>]
|
576
586
|
def default_headers
|
577
587
|
{
|
578
588
|
:accept => '*/*',
|
579
|
-
:accept_encoding => 'gzip, deflate',
|
580
589
|
:user_agent => RestClient::Platform.default_user_agent,
|
581
590
|
}
|
582
591
|
end
|
@@ -712,6 +721,9 @@ module RestClient
|
|
712
721
|
|
713
722
|
log_request
|
714
723
|
|
724
|
+
start_time = Time.now
|
725
|
+
tempfile = nil
|
726
|
+
|
715
727
|
net.start do |http|
|
716
728
|
established_connection = true
|
717
729
|
|
@@ -719,10 +731,16 @@ module RestClient
|
|
719
731
|
net_http_do_request(http, req, payload, &@block_response)
|
720
732
|
else
|
721
733
|
res = net_http_do_request(http, req, payload) { |http_response|
|
722
|
-
|
734
|
+
if @raw_response
|
735
|
+
# fetch body into tempfile
|
736
|
+
tempfile = fetch_body_to_tempfile(http_response)
|
737
|
+
else
|
738
|
+
# fetch body
|
739
|
+
http_response.read_body
|
740
|
+
end
|
741
|
+
http_response
|
723
742
|
}
|
724
|
-
|
725
|
-
process_result res, & block
|
743
|
+
process_result(res, start_time, tempfile, &block)
|
726
744
|
end
|
727
745
|
end
|
728
746
|
rescue EOFError
|
@@ -762,47 +780,56 @@ module RestClient
|
|
762
780
|
end
|
763
781
|
|
764
782
|
def setup_credentials(req)
|
765
|
-
|
783
|
+
if user && !@processed_headers_lowercase.include?('authorization')
|
784
|
+
req.basic_auth(user, password)
|
785
|
+
end
|
766
786
|
end
|
767
787
|
|
768
|
-
def
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
788
|
+
def fetch_body_to_tempfile(http_response)
|
789
|
+
# Taken from Chef, which as in turn...
|
790
|
+
# Stolen from http://www.ruby-forum.com/topic/166423
|
791
|
+
# Kudos to _why!
|
792
|
+
tf = Tempfile.new('rest-client.')
|
793
|
+
tf.binmode
|
794
|
+
|
795
|
+
size = 0
|
796
|
+
total = http_response['Content-Length'].to_i
|
797
|
+
stream_log_bucket = nil
|
798
|
+
|
799
|
+
http_response.read_body do |chunk|
|
800
|
+
tf.write chunk
|
801
|
+
size += chunk.size
|
802
|
+
if log
|
803
|
+
if total == 0
|
804
|
+
log << "streaming %s %s (%d of unknown) [0 Content-Length]\n" % [@method.upcase, @url, size]
|
805
|
+
else
|
806
|
+
percent = (size * 100) / total
|
807
|
+
current_log_bucket, _ = percent.divmod(@stream_log_percent)
|
808
|
+
if current_log_bucket != stream_log_bucket
|
809
|
+
stream_log_bucket = current_log_bucket
|
810
|
+
log << "streaming %s %s %d%% done (%d of %d)\n" % [@method.upcase, @url, (size * 100) / total, size, total]
|
786
811
|
end
|
787
812
|
end
|
788
813
|
end
|
789
|
-
@tf.close
|
790
|
-
@tf
|
791
|
-
else
|
792
|
-
http_response.read_body
|
793
814
|
end
|
794
|
-
|
815
|
+
tf.close
|
816
|
+
tf
|
795
817
|
end
|
796
818
|
|
797
|
-
|
819
|
+
# @param res The Net::HTTP response object
|
820
|
+
# @param start_time [Time] Time of request start
|
821
|
+
def process_result(res, start_time, tempfile=nil, &block)
|
798
822
|
if @raw_response
|
799
|
-
|
800
|
-
|
823
|
+
unless tempfile
|
824
|
+
raise ArgumentError.new('tempfile is required')
|
825
|
+
end
|
826
|
+
response = RawResponse.new(tempfile, res, self, start_time)
|
801
827
|
else
|
802
|
-
|
803
|
-
response = Response.create(decoded, res, self)
|
828
|
+
response = Response.create(res.body, res, self, start_time)
|
804
829
|
end
|
805
830
|
|
831
|
+
response.log_response
|
832
|
+
|
806
833
|
if block_given?
|
807
834
|
block.call(response, self, res, & block)
|
808
835
|
else
|