rest-client 1.8.0 → 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.
Files changed (55) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +2 -0
  3. data/.mailmap +10 -0
  4. data/.rspec +2 -1
  5. data/.rubocop +2 -0
  6. data/.rubocop-disables.yml +386 -0
  7. data/.rubocop.yml +8 -0
  8. data/.travis.yml +56 -8
  9. data/AUTHORS +26 -1
  10. data/README.md +901 -0
  11. data/Rakefile +27 -3
  12. data/bin/restclient +3 -5
  13. data/history.md +181 -0
  14. data/lib/restclient/abstract_response.rb +172 -55
  15. data/lib/restclient/exceptions.rb +96 -55
  16. data/lib/restclient/params_array.rb +72 -0
  17. data/lib/restclient/payload.rb +70 -74
  18. data/lib/restclient/platform.rb +19 -0
  19. data/lib/restclient/raw_response.rb +21 -7
  20. data/lib/restclient/request.rb +540 -281
  21. data/lib/restclient/resource.rb +19 -9
  22. data/lib/restclient/response.rb +75 -6
  23. data/lib/restclient/utils.rb +274 -0
  24. data/lib/restclient/version.rb +2 -1
  25. data/lib/restclient.rb +21 -3
  26. data/rest-client.gemspec +12 -10
  27. data/spec/ISS.jpg +0 -0
  28. data/spec/helpers.rb +54 -0
  29. data/spec/integration/_lib.rb +1 -0
  30. data/spec/integration/capath_digicert/3513523f.0 +22 -0
  31. data/spec/integration/capath_digicert/399e7759.0 +22 -0
  32. data/spec/integration/capath_digicert/digicert.crt +20 -17
  33. data/spec/integration/certs/digicert.crt +20 -17
  34. data/spec/integration/httpbin_spec.rb +128 -0
  35. data/spec/integration/integration_spec.rb +97 -14
  36. data/spec/integration/request_spec.rb +25 -2
  37. data/spec/spec_helper.rb +28 -1
  38. data/spec/unit/_lib.rb +1 -0
  39. data/spec/unit/abstract_response_spec.rb +95 -38
  40. data/spec/unit/exceptions_spec.rb +41 -28
  41. data/spec/unit/params_array_spec.rb +36 -0
  42. data/spec/unit/payload_spec.rb +118 -68
  43. data/spec/unit/raw_response_spec.rb +10 -6
  44. data/spec/unit/request2_spec.rb +34 -12
  45. data/spec/unit/request_spec.rb +745 -424
  46. data/spec/unit/resource_spec.rb +31 -27
  47. data/spec/unit/response_spec.rb +134 -57
  48. data/spec/unit/restclient_spec.rb +16 -15
  49. data/spec/unit/utils_spec.rb +147 -0
  50. data/spec/unit/windows/root_certs_spec.rb +3 -3
  51. metadata +79 -29
  52. data/README.rdoc +0 -324
  53. data/spec/integration/capath_digicert/244b5494.0 +0 -19
  54. data/spec/integration/capath_digicert/81b9768f.0 +0 -19
  55. data/spec/unit/master_shake.jpg +0 -0
@@ -1,5 +1,19 @@
1
1
  module RestClient
2
2
 
3
+ # Hash of HTTP status code => message.
4
+ #
5
+ # 1xx: Informational - Request received, continuing process
6
+ # 2xx: Success - The action was successfully received, understood, and
7
+ # accepted
8
+ # 3xx: Redirection - Further action must be taken in order to complete the
9
+ # request
10
+ # 4xx: Client Error - The request contains bad syntax or cannot be fulfilled
11
+ # 5xx: Server Error - The server failed to fulfill an apparently valid
12
+ # request
13
+ #
14
+ # @see
15
+ # http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
16
+ #
3
17
  STATUSES = {100 => 'Continue',
4
18
  101 => 'Switching Protocols',
5
19
  102 => 'Processing', #WebDAV
@@ -12,6 +26,8 @@ module RestClient
12
26
  205 => 'Reset Content',
13
27
  206 => 'Partial Content',
14
28
  207 => 'Multi-Status', #WebDAV
29
+ 208 => 'Already Reported', # RFC5842
30
+ 226 => 'IM Used', # RFC3229
15
31
 
16
32
  300 => 'Multiple Choices',
17
33
  301 => 'Moved Permanently',
@@ -21,12 +37,13 @@ module RestClient
21
37
  305 => 'Use Proxy', # http/1.1
22
38
  306 => 'Switch Proxy', # no longer used
23
39
  307 => 'Temporary Redirect', # http/1.1
40
+ 308 => 'Permanent Redirect', # RFC7538
24
41
 
25
42
  400 => 'Bad Request',
26
43
  401 => 'Unauthorized',
27
44
  402 => 'Payment Required',
28
45
  403 => 'Forbidden',
29
- 404 => 'Resource Not Found',
46
+ 404 => 'Not Found',
30
47
  405 => 'Method Not Allowed',
31
48
  406 => 'Not Acceptable',
32
49
  407 => 'Proxy Authentication Required',
@@ -35,10 +52,10 @@ module RestClient
35
52
  410 => 'Gone',
36
53
  411 => 'Length Required',
37
54
  412 => 'Precondition Failed',
38
- 413 => 'Request Entity Too Large',
39
- 414 => 'Request-URI Too Long',
55
+ 413 => 'Payload Too Large', # RFC7231 (renamed, see below)
56
+ 414 => 'URI Too Long', # RFC7231 (renamed, see below)
40
57
  415 => 'Unsupported Media Type',
41
- 416 => 'Requested Range Not Satisfiable',
58
+ 416 => 'Range Not Satisfiable', # RFC7233 (renamed, see below)
42
59
  417 => 'Expectation Failed',
43
60
  418 => 'I\'m A Teapot', #RFC2324
44
61
  421 => 'Too Many Connections From This IP',
@@ -61,22 +78,27 @@ module RestClient
61
78
  505 => 'HTTP Version Not Supported',
62
79
  506 => 'Variant Also Negotiates',
63
80
  507 => 'Insufficient Storage', #WebDAV
81
+ 508 => 'Loop Detected', # RFC5842
64
82
  509 => 'Bandwidth Limit Exceeded', #Apache
65
83
  510 => 'Not Extended',
66
84
  511 => 'Network Authentication Required', # RFC6585
67
85
  }
68
86
 
69
- # Compatibility : make the Response act like a Net::HTTPResponse when needed
70
- module ResponseForException
71
- def method_missing symbol, *args
72
- if net_http_res.respond_to? symbol
73
- warn "[warning] The response contained in an RestClient::Exception is now a RestClient::Response instead of a Net::HTTPResponse, please update your code"
74
- net_http_res.send symbol, *args
75
- else
76
- super
77
- end
78
- end
79
- end
87
+ STATUSES_COMPATIBILITY = {
88
+ # The RFCs all specify "Not Found", but "Resource Not Found" was used in
89
+ # earlier RestClient releases.
90
+ 404 => ['ResourceNotFound'],
91
+
92
+ # HTTP 413 was renamed to "Payload Too Large" in RFC7231.
93
+ 413 => ['RequestEntityTooLarge'],
94
+
95
+ # HTTP 414 was renamed to "URI Too Long" in RFC7231.
96
+ 414 => ['RequestURITooLong'],
97
+
98
+ # HTTP 416 was renamed to "Range Not Satisfiable" in RFC7233.
99
+ 416 => ['RequestedRangeNotSatisfiable'],
100
+ }
101
+
80
102
 
81
103
  # This is the base RestClient exception class. Rescue it if you want to
82
104
  # catch any exception that your request might raise
@@ -86,15 +108,13 @@ module RestClient
86
108
  # probably an HTML error page) is e.response.
87
109
  class Exception < RuntimeError
88
110
  attr_accessor :response
111
+ attr_accessor :original_exception
89
112
  attr_writer :message
90
113
 
91
114
  def initialize response = nil, initial_response_code = nil
92
115
  @response = response
93
116
  @message = nil
94
117
  @initial_response_code = initial_response_code
95
-
96
- # compatibility: this make the exception behave like a Net::HTTPResponse
97
- response.extend ResponseForException if response
98
118
  end
99
119
 
100
120
  def http_code
@@ -106,32 +126,35 @@ module RestClient
106
126
  end
107
127
  end
108
128
 
109
- def http_body
110
- @response.body if @response
129
+ def http_headers
130
+ @response.headers if @response
111
131
  end
112
132
 
113
- def inspect
114
- "#{message}: #{http_body}"
133
+ def http_body
134
+ @response.body if @response
115
135
  end
116
136
 
117
137
  def to_s
118
- inspect
138
+ message
119
139
  end
120
140
 
121
141
  def message
122
- @message || self.class.name
142
+ @message || default_message
123
143
  end
124
144
 
145
+ def default_message
146
+ self.class.name
147
+ end
125
148
  end
126
149
 
127
150
  # Compatibility
128
- class ExceptionWithResponse < Exception
151
+ class ExceptionWithResponse < RestClient::Exception
129
152
  end
130
153
 
131
154
  # The request failed with an error code not managed by the code
132
155
  class RequestFailed < ExceptionWithResponse
133
156
 
134
- def message
157
+ def default_message
135
158
  "HTTP status code #{http_code}"
136
159
  end
137
160
 
@@ -140,64 +163,82 @@ module RestClient
140
163
  end
141
164
  end
142
165
 
143
- # We will a create an exception for each status code, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
166
+ # RestClient exception classes. TODO: move all exceptions into this module.
167
+ #
168
+ # We will a create an exception for each status code, see
169
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
170
+ #
144
171
  module Exceptions
145
172
  # Map http status codes to the corresponding exception class
146
173
  EXCEPTIONS_MAP = {}
147
174
  end
148
175
 
176
+ # Create HTTP status exception classes
149
177
  STATUSES.each_pair do |code, message|
150
-
151
- # Compatibility
152
- superclass = ([304, 401, 404].include? code) ? ExceptionWithResponse : RequestFailed
153
- klass = Class.new(superclass) do
154
- send(:define_method, :message) {"#{http_code ? "#{http_code} " : ''}#{message}"}
178
+ klass = Class.new(RequestFailed) do
179
+ send(:define_method, :default_message) {"#{http_code ? "#{http_code} " : ''}#{message}"}
155
180
  end
156
- klass_constant = const_set message.delete(' \-\''), klass
181
+ klass_constant = const_set(message.delete(' \-\''), klass)
157
182
  Exceptions::EXCEPTIONS_MAP[code] = klass_constant
158
183
  end
159
184
 
160
- # A redirect was encountered; caught by execute to retry with the new url.
161
- class Redirect < Exception
162
-
163
- def message
164
- 'Redirect'
185
+ # Create HTTP status exception classes used for backwards compatibility
186
+ STATUSES_COMPATIBILITY.each_pair do |code, compat_list|
187
+ klass = Exceptions::EXCEPTIONS_MAP.fetch(code)
188
+ compat_list.each do |old_name|
189
+ const_set(old_name, klass)
165
190
  end
191
+ end
166
192
 
167
- attr_accessor :url
193
+ module Exceptions
194
+ # We have to split the Exceptions module like we do here because the
195
+ # EXCEPTIONS_MAP is under Exceptions, but we depend on
196
+ # RestClient::RequestTimeout below.
197
+
198
+ # Base class for request timeouts.
199
+ #
200
+ # NB: Previous releases of rest-client would raise RequestTimeout both for
201
+ # HTTP 408 responses and for actual connection timeouts.
202
+ class Timeout < RestClient::RequestTimeout
203
+ def initialize(message=nil, original_exception=nil)
204
+ super(nil, nil)
205
+ self.message = message if message
206
+ self.original_exception = original_exception if original_exception
207
+ end
208
+ end
168
209
 
169
- def initialize(url)
170
- @url = url
210
+ # Timeout when connecting to a server. Typically wraps Net::OpenTimeout (in
211
+ # ruby 2.0 or greater).
212
+ class OpenTimeout < Timeout
213
+ def default_message
214
+ 'Timed out connecting to server'
215
+ end
171
216
  end
172
- end
173
217
 
174
- class MaxRedirectsReached < Exception
175
- def message
176
- 'Maximum number of redirect reached'
218
+ # Timeout when reading from a server. Typically wraps Net::ReadTimeout (in
219
+ # ruby 2.0 or greater).
220
+ class ReadTimeout < Timeout
221
+ def default_message
222
+ 'Timed out reading data from server'
223
+ end
177
224
  end
178
225
  end
179
226
 
227
+
180
228
  # The server broke the connection prior to the request completing. Usually
181
229
  # this means it crashed, or sometimes that your network connection was
182
230
  # severed before it could complete.
183
- class ServerBrokeConnection < Exception
231
+ class ServerBrokeConnection < RestClient::Exception
184
232
  def initialize(message = 'Server broke connection')
185
233
  super nil, nil
186
234
  self.message = message
187
235
  end
188
236
  end
189
237
 
190
- class SSLCertificateNotVerified < Exception
191
- def initialize(message)
238
+ class SSLCertificateNotVerified < RestClient::Exception
239
+ def initialize(message = 'SSL certificate not verified')
192
240
  super nil, nil
193
241
  self.message = message
194
242
  end
195
243
  end
196
244
  end
197
-
198
- class RestClient::Request
199
- # backwards compatibility
200
- Redirect = RestClient::Redirect
201
- Unauthorized = RestClient::Unauthorized
202
- RequestFailed = RestClient::RequestFailed
203
- end
@@ -0,0 +1,72 @@
1
+ module RestClient
2
+
3
+ # The ParamsArray class is used to represent an ordered list of [key, value]
4
+ # pairs. Use this when you need to include a key multiple times or want
5
+ # explicit control over parameter ordering.
6
+ #
7
+ # Most of the request payload & parameter functions normally accept a Hash of
8
+ # keys => values, which does not allow for duplicated keys.
9
+ #
10
+ # @see RestClient::Utils.encode_query_string
11
+ # @see RestClient::Utils.flatten_params
12
+ #
13
+ class ParamsArray
14
+ include Enumerable
15
+
16
+ # @param array [Array<Array>] An array of parameter key,value pairs. These
17
+ # pairs may be 2 element arrays [key, value] or single element hashes
18
+ # {key => value}. They may also be single element arrays to represent a
19
+ # key with no value.
20
+ #
21
+ # @example
22
+ # >> ParamsArray.new([[:foo, 123], [:foo, 456], [:bar, 789]])
23
+ # This will be encoded as "foo=123&foo=456&bar=789"
24
+ #
25
+ # @example
26
+ # >> ParamsArray.new({foo: 123, bar: 456})
27
+ # This is valid, but there's no reason not to just use the Hash directly
28
+ # instead of a ParamsArray.
29
+ #
30
+ #
31
+ def initialize(array)
32
+ @array = process_input(array)
33
+ end
34
+
35
+ def each(*args, &blk)
36
+ @array.each(*args, &blk)
37
+ end
38
+
39
+ def empty?
40
+ @array.empty?
41
+ end
42
+
43
+ private
44
+
45
+ def process_input(array)
46
+ array.map {|v| process_pair(v) }
47
+ end
48
+
49
+ # A pair may be:
50
+ # - A single element hash, e.g. {foo: 'bar'}
51
+ # - A two element array, e.g. ['foo', 'bar']
52
+ # - A one element array, e.g. ['foo']
53
+ #
54
+ def process_pair(pair)
55
+ case pair
56
+ when Hash
57
+ if pair.length != 1
58
+ raise ArgumentError.new("Bad # of fields for pair: #{pair.inspect}")
59
+ end
60
+ pair.to_a.fetch(0)
61
+ when Array
62
+ if pair.length > 2
63
+ raise ArgumentError.new("Bad # of fields for pair: #{pair.inspect}")
64
+ end
65
+ [pair.fetch(0), pair[1]]
66
+ else
67
+ # recurse, converting any non-array to an array
68
+ process_pair(pair.to_a)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -1,13 +1,23 @@
1
1
  require 'tempfile'
2
+ require 'securerandom'
2
3
  require 'stringio'
3
- require 'mime/types'
4
+
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
4
11
 
5
12
  module RestClient
6
13
  module Payload
7
14
  extend self
8
15
 
9
16
  def generate(params)
10
- if params.is_a?(String)
17
+ if params.is_a?(RestClient::Payload::Base)
18
+ # pass through Payload objects unchanged
19
+ params
20
+ elsif params.is_a?(String)
11
21
  Base.new(params)
12
22
  elsif params.is_a?(Hash)
13
23
  if params.delete(:multipart) == true || has_file?(params)
@@ -15,6 +25,12 @@ module RestClient
15
25
  else
16
26
  UrlEncoded.new(params)
17
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
18
34
  elsif params.respond_to?(:read)
19
35
  Streamed.new(params)
20
36
  else
@@ -23,28 +39,20 @@ module RestClient
23
39
  end
24
40
 
25
41
  def has_file?(params)
26
- params.any? do |_, v|
27
- case v
28
- when Hash
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
42
+ unless params.is_a?(Hash)
43
+ raise ArgumentError.new("Must pass Hash, not #{params.inspect}")
35
44
  end
45
+ _has_file?(params)
36
46
  end
37
47
 
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)
45
- else
46
- v.respond_to?(:path) && v.respond_to?(:read)
47
- end
48
+ def _has_file?(obj)
49
+ case obj
50
+ when Hash, ParamsArray
51
+ obj.any? {|_, v| _has_file?(v) }
52
+ when Array
53
+ obj.any? {|v| _has_file?(v) }
54
+ else
55
+ obj.respond_to?(:path) && obj.respond_to?(:read)
48
56
  end
49
57
  end
50
58
 
@@ -58,40 +66,13 @@ module RestClient
58
66
  @stream.seek(0)
59
67
  end
60
68
 
61
- def read(bytes=nil)
62
- @stream.read(bytes)
63
- end
64
-
65
- alias :to_s :read
66
-
67
- # Flatten parameters by converting hashes of hashes to flat hashes
68
- # {keys1 => {keys2 => value}} will be transformed into [keys1[key2], value]
69
- def flatten_params(params, parent_key = nil)
70
- result = []
71
- params.each do |key, value|
72
- calculated_key = parent_key ? "#{parent_key}[#{handle_key(key)}]" : handle_key(key)
73
- if value.is_a? Hash
74
- result += flatten_params(value, calculated_key)
75
- elsif value.is_a? Array
76
- result += flatten_params_array(value, calculated_key)
77
- else
78
- result << [calculated_key, value]
79
- end
80
- end
81
- result
69
+ def read(*args)
70
+ @stream.read(*args)
82
71
  end
83
72
 
84
- def flatten_params_array value, calculated_key
85
- result = []
86
- value.each do |elem|
87
- if elem.is_a? Hash
88
- result += flatten_params(elem, calculated_key)
89
- elsif elem.is_a? Array
90
- result += flatten_params_array(elem, calculated_key)
91
- else
92
- result << ["#{calculated_key}[]", elem]
93
- end
94
- end
73
+ def to_s
74
+ result = read
75
+ @stream.seek(0)
95
76
  result
96
77
  end
97
78
 
@@ -109,14 +90,20 @@ module RestClient
109
90
  @stream.close unless @stream.closed?
110
91
  end
111
92
 
112
- def inspect
113
- result = to_s.inspect
114
- @stream.seek(0)
115
- result
93
+ def closed?
94
+ @stream.closed?
95
+ end
96
+
97
+ def to_s_inspect
98
+ to_s.inspect
116
99
  end
117
100
 
118
101
  def short_inspect
119
- (size > 500 ? "#{size} byte(s) length" : inspect)
102
+ if size && size > 500
103
+ "#{size} byte(s) length"
104
+ else
105
+ to_s_inspect
106
+ end
120
107
  end
121
108
 
122
109
  end
@@ -134,42 +121,36 @@ module RestClient
134
121
  end
135
122
  end
136
123
 
124
+ # TODO (breaks compatibility): ought to use mime_for() to autodetect the
125
+ # Content-Type for stream objects that have a filename.
126
+
137
127
  alias :length :size
138
128
  end
139
129
 
140
130
  class UrlEncoded < Base
141
131
  def build_stream(params = nil)
142
- @stream = StringIO.new(flatten_params(params).collect do |entry|
143
- "#{entry[0]}=#{handle_key(entry[1])}"
144
- end.join("&"))
132
+ @stream = StringIO.new(Utils.encode_query_string(params))
145
133
  @stream.seek(0)
146
134
  end
147
135
 
148
- # for UrlEncoded escape the keys
149
- def handle_key key
150
- Parser.escape(key.to_s, Escape)
151
- end
152
-
153
136
  def headers
154
137
  super.merge({'Content-Type' => 'application/x-www-form-urlencoded'})
155
138
  end
156
-
157
- Parser = URI.const_defined?(:Parser) ? URI::Parser.new : URI
158
- Escape = Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")
159
139
  end
160
140
 
161
141
  class Multipart < Base
162
142
  EOL = "\r\n"
163
143
 
164
144
  def build_stream(params)
165
- b = "--#{boundary}"
145
+ b = '--' + boundary
166
146
 
167
- @stream = Tempfile.new("RESTClient.Stream.#{rand(1000)}")
147
+ @stream = Tempfile.new('rest-client.multipart.')
168
148
  @stream.binmode
169
149
  @stream.write(b + EOL)
170
150
 
171
- if params.is_a? Hash
172
- x = flatten_params(params)
151
+ case params
152
+ when Hash, ParamsArray
153
+ x = Utils.flatten_params(params)
173
154
  else
174
155
  x = params
175
156
  end
@@ -218,10 +199,25 @@ module RestClient
218
199
  end
219
200
 
220
201
  def boundary
221
- @boundary ||= rand(1_000_000).to_s
202
+ return @boundary if defined?(@boundary) && @boundary
203
+
204
+ # Use the same algorithm used by WebKit: generate 16 random
205
+ # alphanumeric characters, replacing `+` `/` with `A` `B` (included in
206
+ # the list twice) to round out the set of 64.
207
+ s = SecureRandom.base64(12)
208
+ s.tr!('+/', 'AB')
209
+
210
+ @boundary = '----RubyFormBoundary' + s
222
211
  end
223
212
 
224
213
  # for Multipart do not escape the keys
214
+ #
215
+ # Ostensibly multipart keys MAY be percent encoded per RFC 7578, but in
216
+ # practice no major browser that I'm aware of uses percent encoding.
217
+ #
218
+ # Further discussion of multipart encoding:
219
+ # https://github.com/rest-client/rest-client/pull/403#issuecomment-156976930
220
+ #
225
221
  def handle_key key
226
222
  key
227
223
  end
@@ -1,3 +1,5 @@
1
+ require 'rbconfig'
2
+
1
3
  module RestClient
2
4
  module Platform
3
5
  # Return true if we are running on a darwin-based Ruby platform. This will
@@ -26,5 +28,22 @@ module RestClient
26
28
  # defined on mri >= 1.9
27
29
  RUBY_ENGINE == 'jruby'
28
30
  end
31
+
32
+ def self.architecture
33
+ "#{RbConfig::CONFIG['host_os']} #{RbConfig::CONFIG['host_cpu']}"
34
+ end
35
+
36
+ def self.ruby_agent_version
37
+ case RUBY_ENGINE
38
+ when 'jruby'
39
+ "jruby/#{JRUBY_VERSION} (#{RUBY_VERSION}p#{RUBY_PATCHLEVEL})"
40
+ else
41
+ "#{RUBY_ENGINE}/#{RUBY_VERSION}p#{RUBY_PATCHLEVEL}"
42
+ end
43
+ end
44
+
45
+ def self.default_user_agent
46
+ "rest-client/#{VERSION} (#{architecture}) #{ruby_agent_version}"
47
+ end
29
48
  end
30
49
  end
@@ -13,22 +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
- def initialize(tempfile, net_http_res, args, request)
19
- @net_http_res = net_http_res
20
- @args = args
18
+ def inspect
19
+ "<RestClient::RawResponse @code=#{code.inspect}, @file=#{file.inspect}, @request=#{request.inspect}>"
20
+ end
21
+
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)
21
27
  @file = tempfile
22
- @request = request
28
+
29
+ # reopen the tempfile so we can read it
30
+ @file.open
31
+
32
+ response_set_vars(net_http_res, request, start_time)
23
33
  end
24
34
 
25
35
  def to_s
26
- @file.open
36
+ body
37
+ end
38
+
39
+ def body
40
+ @file.rewind
27
41
  @file.read
28
42
  end
29
43
 
30
44
  def size
31
- File.size file
45
+ file.size
32
46
  end
33
47
 
34
48
  end