rest-client 1.8.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -14,7 +14,7 @@ module RestClient
14
14
  #
15
15
  # With a timeout (seconds):
16
16
  #
17
- # RestClient::Resource.new('http://slow', :timeout => 10)
17
+ # RestClient::Resource.new('http://slow', :read_timeout => 10)
18
18
  #
19
19
  # With an open timeout (seconds):
20
20
  #
@@ -51,7 +51,8 @@ module RestClient
51
51
  Request.execute(options.merge(
52
52
  :method => :get,
53
53
  :url => url,
54
- :headers => headers), &(block || @block))
54
+ :headers => headers,
55
+ :log => log), &(block || @block))
55
56
  end
56
57
 
57
58
  def head(additional_headers={}, &block)
@@ -59,7 +60,8 @@ module RestClient
59
60
  Request.execute(options.merge(
60
61
  :method => :head,
61
62
  :url => url,
62
- :headers => headers), &(block || @block))
63
+ :headers => headers,
64
+ :log => log), &(block || @block))
63
65
  end
64
66
 
65
67
  def post(payload, additional_headers={}, &block)
@@ -68,7 +70,8 @@ module RestClient
68
70
  :method => :post,
69
71
  :url => url,
70
72
  :payload => payload,
71
- :headers => headers), &(block || @block))
73
+ :headers => headers,
74
+ :log => log), &(block || @block))
72
75
  end
73
76
 
74
77
  def put(payload, additional_headers={}, &block)
@@ -77,7 +80,8 @@ module RestClient
77
80
  :method => :put,
78
81
  :url => url,
79
82
  :payload => payload,
80
- :headers => headers), &(block || @block))
83
+ :headers => headers,
84
+ :log => log), &(block || @block))
81
85
  end
82
86
 
83
87
  def patch(payload, additional_headers={}, &block)
@@ -86,7 +90,8 @@ module RestClient
86
90
  :method => :patch,
87
91
  :url => url,
88
92
  :payload => payload,
89
- :headers => headers), &(block || @block))
93
+ :headers => headers,
94
+ :log => log), &(block || @block))
90
95
  end
91
96
 
92
97
  def delete(additional_headers={}, &block)
@@ -94,7 +99,8 @@ module RestClient
94
99
  Request.execute(options.merge(
95
100
  :method => :delete,
96
101
  :url => url,
97
- :headers => headers), &(block || @block))
102
+ :headers => headers,
103
+ :log => log), &(block || @block))
98
104
  end
99
105
 
100
106
  def to_s
@@ -113,14 +119,18 @@ module RestClient
113
119
  options[:headers] || {}
114
120
  end
115
121
 
116
- def timeout
117
- options[:timeout]
122
+ def read_timeout
123
+ options[:read_timeout]
118
124
  end
119
125
 
120
126
  def open_timeout
121
127
  options[:open_timeout]
122
128
  end
123
129
 
130
+ def log
131
+ options[:log] || RestClient.log
132
+ end
133
+
124
134
  # Construct a subresource, preserving authentication.
125
135
  #
126
136
  # Example:
@@ -2,20 +2,89 @@ module RestClient
2
2
 
3
3
  # A Response from RestClient, you can access the response body, the code or the headers.
4
4
  #
5
- module Response
5
+ class Response < String
6
6
 
7
7
  include AbstractResponse
8
8
 
9
+ # Return the HTTP response body.
10
+ #
11
+ # Future versions of RestClient will deprecate treating response objects
12
+ # directly as strings, so it will be necessary to call `.body`.
13
+ #
14
+ # @return [String]
15
+ #
9
16
  def body
10
- self
17
+ # Benchmarking suggests that "#{self}" is fastest, and that caching the
18
+ # body string in an instance variable doesn't make it enough faster to be
19
+ # worth the extra memory storage.
20
+ String.new(self)
11
21
  end
12
22
 
13
- def self.create body, net_http_res, args, request
14
- result = body || ''
15
- result.extend Response
16
- result.response_set_vars(net_http_res, args, request)
23
+ # Convert the HTTP response body to a pure String object.
24
+ #
25
+ # @return [String]
26
+ def to_s
27
+ body
28
+ end
29
+
30
+ # Convert the HTTP response body to a pure String object.
31
+ #
32
+ # @return [String]
33
+ def to_str
34
+ body
35
+ end
36
+
37
+ def inspect
38
+ "<RestClient::Response #{code.inspect} #{body_truncated(10).inspect}>"
39
+ end
40
+
41
+ # Initialize a Response object. Because RestClient::Response is
42
+ # (unfortunately) a subclass of String for historical reasons,
43
+ # Response.create is the preferred initializer.
44
+ #
45
+ # @param [String, nil] body The response body from the Net::HTTPResponse
46
+ # @param [Net::HTTPResponse] net_http_res
47
+ # @param [RestClient::Request] request
48
+ # @param [Time] start_time
49
+ def self.create(body, net_http_res, request, start_time=nil)
50
+ result = self.new(body || '')
51
+
52
+ result.response_set_vars(net_http_res, request, start_time)
53
+ fix_encoding(result)
54
+
17
55
  result
18
56
  end
19
57
 
58
+ # Set the String encoding according to the 'Content-Type: charset' header,
59
+ # if possible.
60
+ def self.fix_encoding(response)
61
+ charset = RestClient::Utils.get_encoding_from_headers(response.headers)
62
+ encoding = nil
63
+
64
+ begin
65
+ encoding = Encoding.find(charset) if charset
66
+ rescue ArgumentError
67
+ if response.log
68
+ response.log << "No such encoding: #{charset.inspect}"
69
+ end
70
+ end
71
+
72
+ return unless encoding
73
+
74
+ response.force_encoding(encoding)
75
+
76
+ response
77
+ end
78
+
79
+ private
80
+
81
+ def body_truncated(length)
82
+ b = body
83
+ if b.length > length
84
+ b[0..length] + '...'
85
+ else
86
+ b
87
+ end
88
+ end
20
89
  end
21
90
  end
@@ -0,0 +1,274 @@
1
+ require 'http/accept'
2
+
3
+ module RestClient
4
+ # Various utility methods
5
+ module Utils
6
+
7
+ # Return encoding from an HTTP header hash.
8
+ #
9
+ # We use the RFC 7231 specification and do not impose a default encoding on
10
+ # text. This differs from the older RFC 2616 behavior, which specifies
11
+ # using ISO-8859-1 for text/* content types without a charset.
12
+ #
13
+ # Strings will use the default encoding when this method returns nil. This
14
+ # default is likely to be UTF-8 for Ruby >= 2.0
15
+ #
16
+ # @param headers [Hash<Symbol,String>]
17
+ #
18
+ # @return [String, nil] Return the string encoding or nil if no header is
19
+ # found.
20
+ #
21
+ # @example
22
+ # >> get_encoding_from_headers({:content_type => 'text/plain; charset=UTF-8'})
23
+ # => "UTF-8"
24
+ #
25
+ def self.get_encoding_from_headers(headers)
26
+ type_header = headers[:content_type]
27
+ return nil unless type_header
28
+
29
+ # TODO: remove this hack once we drop support for Ruby 2.0
30
+ if RUBY_VERSION.start_with?('2.0')
31
+ _content_type, params = deprecated_cgi_parse_header(type_header)
32
+
33
+ if params.include?('charset')
34
+ return params.fetch('charset').gsub(/(\A["']*)|(["']*\z)/, '')
35
+ end
36
+
37
+ else
38
+
39
+ begin
40
+ _content_type, params = cgi_parse_header(type_header)
41
+ rescue HTTP::Accept::ParseError
42
+ return nil
43
+ else
44
+ params['charset']
45
+ end
46
+ end
47
+ end
48
+
49
+ # Parse a Content-Type like header.
50
+ #
51
+ # Return the main content-type and a hash of params.
52
+ #
53
+ # @param [String] line
54
+ # @return [Array(String, Hash)]
55
+ #
56
+ def self.cgi_parse_header(line)
57
+ types = HTTP::Accept::MediaTypes.parse(line)
58
+
59
+ if types.empty?
60
+ raise HTTP::Accept::ParseError.new("Found no types in header line")
61
+ end
62
+
63
+ [types.first.mime_type, types.first.parameters]
64
+ end
65
+
66
+ # Parse semi-colon separated, potentially quoted header string iteratively.
67
+ #
68
+ # @private
69
+ #
70
+ # @deprecated This method is deprecated and only exists to support Ruby
71
+ # 2.0, which is not supported by HTTP::Accept.
72
+ #
73
+ # @todo remove this method when dropping support for Ruby 2.0
74
+ #
75
+ def self._cgi_parseparam(s)
76
+ return enum_for(__method__, s) unless block_given?
77
+
78
+ while s[0] == ';'
79
+ s = s[1..-1]
80
+ ends = s.index(';')
81
+ while ends && ends > 0 \
82
+ && (s[0...ends].count('"') -
83
+ s[0...ends].scan('\"').count) % 2 != 0
84
+ ends = s.index(';', ends + 1)
85
+ end
86
+ if ends.nil?
87
+ ends = s.length
88
+ end
89
+ f = s[0...ends]
90
+ yield f.strip
91
+ s = s[ends..-1]
92
+ end
93
+ nil
94
+ end
95
+
96
+ # Parse a Content-Type like header.
97
+ #
98
+ # Return the main content-type and a hash of options.
99
+ #
100
+ # This method was ported directly from Python's cgi.parse_header(). It
101
+ # probably doesn't read or perform particularly well in ruby.
102
+ # https://github.com/python/cpython/blob/3.4/Lib/cgi.py#L301-L331
103
+ #
104
+ # @param [String] line
105
+ # @return [Array(String, Hash)]
106
+ #
107
+ # @deprecated This method is deprecated and only exists to support Ruby
108
+ # 2.0, which is not supported by HTTP::Accept.
109
+ #
110
+ # @todo remove this method when dropping support for Ruby 2.0
111
+ #
112
+ def self.deprecated_cgi_parse_header(line)
113
+ parts = _cgi_parseparam(';' + line)
114
+ key = parts.next
115
+ pdict = {}
116
+
117
+ begin
118
+ while (p = parts.next)
119
+ i = p.index('=')
120
+ if i
121
+ name = p[0...i].strip.downcase
122
+ value = p[i+1..-1].strip
123
+ if value.length >= 2 && value[0] == '"' && value[-1] == '"'
124
+ value = value[1...-1]
125
+ value = value.gsub('\\\\', '\\').gsub('\\"', '"')
126
+ end
127
+ pdict[name] = value
128
+ end
129
+ end
130
+ rescue StopIteration
131
+ end
132
+
133
+ [key, pdict]
134
+ end
135
+
136
+ # Serialize a ruby object into HTTP query string parameters.
137
+ #
138
+ # There is no standard for doing this, so we choose our own slightly
139
+ # idiosyncratic format. The output closely matches the format understood by
140
+ # Rails, Rack, and PHP.
141
+ #
142
+ # If you don't want handling of complex objects and only want to handle
143
+ # simple flat hashes, you may want to use `URI.encode_www_form` instead,
144
+ # which implements HTML5-compliant URL encoded form data.
145
+ #
146
+ # @param [Hash,ParamsArray] object The object to serialize
147
+ #
148
+ # @return [String] A string appropriate for use as an HTTP query string
149
+ #
150
+ # @see {flatten_params}
151
+ #
152
+ # @see URI.encode_www_form
153
+ #
154
+ # @see See also Object#to_query in ActiveSupport
155
+ # @see http://php.net/manual/en/function.http-build-query.php
156
+ # http_build_query in PHP
157
+ # @see See also Rack::Utils.build_nested_query in Rack
158
+ #
159
+ # Notable differences from the ActiveSupport implementation:
160
+ #
161
+ # - Empty hash and empty array are treated the same as nil instead of being
162
+ # omitted entirely from the output. Rather than disappearing, they will
163
+ # appear to be nil instead.
164
+ #
165
+ # It's most common to pass a Hash as the object to serialize, but you can
166
+ # also use a ParamsArray if you want to be able to pass the same key with
167
+ # multiple values and not use the rack/rails array convention.
168
+ #
169
+ # @since 2.0.0
170
+ #
171
+ # @example Simple hashes
172
+ # >> encode_query_string({foo: 123, bar: 456})
173
+ # => 'foo=123&bar=456'
174
+ #
175
+ # @example Simple arrays
176
+ # >> encode_query_string({foo: [1,2,3]})
177
+ # => 'foo[]=1&foo[]=2&foo[]=3'
178
+ #
179
+ # @example Nested hashes
180
+ # >> encode_query_string({outer: {foo: 123, bar: 456}})
181
+ # => 'outer[foo]=123&outer[bar]=456'
182
+ #
183
+ # @example Deeply nesting
184
+ # >> encode_query_string({coords: [{x: 1, y: 0}, {x: 2}, {x: 3}]})
185
+ # => 'coords[][x]=1&coords[][y]=0&coords[][x]=2&coords[][x]=3'
186
+ #
187
+ # @example Null and empty values
188
+ # >> encode_query_string({string: '', empty: nil, list: [], hash: {}})
189
+ # => 'string=&empty&list&hash'
190
+ #
191
+ # @example Nested nulls
192
+ # >> encode_query_string({foo: {string: '', empty: nil}})
193
+ # => 'foo[string]=&foo[empty]'
194
+ #
195
+ # @example Multiple fields with the same name using ParamsArray
196
+ # >> encode_query_string(RestClient::ParamsArray.new([[:foo, 1], [:foo, 2], [:foo, 3]]))
197
+ # => 'foo=1&foo=2&foo=3'
198
+ #
199
+ # @example Nested ParamsArray
200
+ # >> encode_query_string({foo: RestClient::ParamsArray.new([[:a, 1], [:a, 2]])})
201
+ # => 'foo[a]=1&foo[a]=2'
202
+ #
203
+ # >> encode_query_string(RestClient::ParamsArray.new([[:foo, {a: 1}], [:foo, {a: 2}]]))
204
+ # => 'foo[a]=1&foo[a]=2'
205
+ #
206
+ def self.encode_query_string(object)
207
+ flatten_params(object, true).map {|k, v| v.nil? ? k : "#{k}=#{v}" }.join('&')
208
+ end
209
+
210
+ # Transform deeply nested param containers into a flat array of [key,
211
+ # value] pairs.
212
+ #
213
+ # @example
214
+ # >> flatten_params({key1: {key2: 123}})
215
+ # => [["key1[key2]", 123]]
216
+ #
217
+ # @example
218
+ # >> flatten_params({key1: {key2: 123, arr: [1,2,3]}})
219
+ # => [["key1[key2]", 123], ["key1[arr][]", 1], ["key1[arr][]", 2], ["key1[arr][]", 3]]
220
+ #
221
+ # @param object [Hash, ParamsArray] The container to flatten
222
+ # @param uri_escape [Boolean] Whether to URI escape keys and values
223
+ # @param parent_key [String] Should not be passed (used for recursion)
224
+ #
225
+ def self.flatten_params(object, uri_escape=false, parent_key=nil)
226
+ unless object.is_a?(Hash) || object.is_a?(ParamsArray) ||
227
+ (parent_key && object.is_a?(Array))
228
+ raise ArgumentError.new('expected Hash or ParamsArray, got: ' + object.inspect)
229
+ end
230
+
231
+ # transform empty collections into nil, where possible
232
+ if object.empty? && parent_key
233
+ return [[parent_key, nil]]
234
+ end
235
+
236
+ # This is essentially .map(), but we need to do += for nested containers
237
+ object.reduce([]) { |result, item|
238
+ if object.is_a?(Array)
239
+ # item is already the value
240
+ k = nil
241
+ v = item
242
+ else
243
+ # item is a key, value pair
244
+ k, v = item
245
+ k = escape(k.to_s) if uri_escape
246
+ end
247
+
248
+ processed_key = parent_key ? "#{parent_key}[#{k}]" : k
249
+
250
+ case v
251
+ when Array, Hash, ParamsArray
252
+ result.concat flatten_params(v, uri_escape, processed_key)
253
+ else
254
+ v = escape(v.to_s) if uri_escape && v
255
+ result << [processed_key, v]
256
+ end
257
+ }
258
+ end
259
+
260
+ # Encode string for safe transport by URI or form encoding. This uses a CGI
261
+ # style escape, which transforms ` ` into `+` and various special
262
+ # characters into percent encoded forms.
263
+ #
264
+ # This calls URI.encode_www_form_component for the implementation. The only
265
+ # difference between this and CGI.escape is that it does not escape `*`.
266
+ # http://stackoverflow.com/questions/25085992/
267
+ #
268
+ # @see URI.encode_www_form_component
269
+ #
270
+ def self.escape(string)
271
+ URI.encode_www_form_component(string)
272
+ end
273
+ end
274
+ end
@@ -1,5 +1,6 @@
1
1
  module RestClient
2
- VERSION = '1.8.0' unless defined?(self::VERSION)
2
+ VERSION_INFO = [2, 1, 0].freeze
3
+ VERSION = VERSION_INFO.map(&:to_s).join('.').freeze
3
4
 
4
5
  def self.version
5
6
  VERSION
data/lib/restclient.rb CHANGED
@@ -2,16 +2,17 @@ require 'net/http'
2
2
  require 'openssl'
3
3
  require 'stringio'
4
4
  require 'uri'
5
- require 'zlib'
6
5
 
7
6
  require File.dirname(__FILE__) + '/restclient/version'
8
7
  require File.dirname(__FILE__) + '/restclient/platform'
9
8
  require File.dirname(__FILE__) + '/restclient/exceptions'
9
+ require File.dirname(__FILE__) + '/restclient/utils'
10
10
  require File.dirname(__FILE__) + '/restclient/request'
11
11
  require File.dirname(__FILE__) + '/restclient/abstract_response'
12
12
  require File.dirname(__FILE__) + '/restclient/response'
13
13
  require File.dirname(__FILE__) + '/restclient/raw_response'
14
14
  require File.dirname(__FILE__) + '/restclient/resource'
15
+ require File.dirname(__FILE__) + '/restclient/params_array'
15
16
  require File.dirname(__FILE__) + '/restclient/payload'
16
17
  require File.dirname(__FILE__) + '/restclient/windows'
17
18
 
@@ -89,8 +90,24 @@ module RestClient
89
90
  Request.execute(:method => :options, :url => url, :headers => headers, &block)
90
91
  end
91
92
 
92
- class << self
93
- attr_accessor :proxy
93
+ # A global proxy URL to use for all requests. This can be overridden on a
94
+ # per-request basis by passing `:proxy` to RestClient::Request.
95
+ def self.proxy
96
+ @proxy ||= nil
97
+ end
98
+
99
+ def self.proxy=(value)
100
+ @proxy = value
101
+ @proxy_set = true
102
+ end
103
+
104
+ # Return whether RestClient.proxy was set explicitly. We use this to
105
+ # differentiate between no value being set and a value explicitly set to nil.
106
+ #
107
+ # @return [Boolean]
108
+ #
109
+ def self.proxy_set?
110
+ @proxy_set ||= false
94
111
  end
95
112
 
96
113
  # Setup the log for RestClient calls.
@@ -150,6 +167,7 @@ module RestClient
150
167
  # Add a Proc to be called before each request in executed.
151
168
  # The proc parameters will be the http request and the request params.
152
169
  def self.add_before_execution_proc &proc
170
+ raise ArgumentError.new('block is required') unless proc
153
171
  @@before_execution_procs << proc
154
172
  end
155
173
 
data/rest-client.gemspec CHANGED
@@ -8,23 +8,25 @@ Gem::Specification.new do |s|
8
8
  s.authors = ['REST Client Team']
9
9
  s.description = 'A simple HTTP and REST client for Ruby, inspired by the Sinatra microframework style of specifying actions: get, put, post, delete.'
10
10
  s.license = 'MIT'
11
- s.email = 'rest.client@librelist.com'
11
+ s.email = 'discuss@rest-client.groups.io'
12
12
  s.executables = ['restclient']
13
- s.extra_rdoc_files = ['README.rdoc', 'history.md']
13
+ s.extra_rdoc_files = ['README.md', 'history.md']
14
14
  s.files = `git ls-files -z`.split("\0")
15
15
  s.test_files = `git ls-files -z spec/`.split("\0")
16
16
  s.homepage = 'https://github.com/rest-client/rest-client'
17
17
  s.summary = 'Simple HTTP and REST client for Ruby, inspired by microframework syntax for specifying actions.'
18
18
 
19
- s.add_development_dependency('webmock', '~> 1.4')
20
- s.add_development_dependency('rspec', '~> 2.4')
21
- s.add_development_dependency('pry')
22
- s.add_development_dependency('pry-doc')
23
- s.add_development_dependency('rdoc', '>= 2.4.2', '< 5.0')
19
+ s.add_development_dependency('webmock', '~> 2.0')
20
+ s.add_development_dependency('rspec', '~> 3.0')
21
+ s.add_development_dependency('pry', '~> 0')
22
+ s.add_development_dependency('pry-doc', '~> 0')
23
+ s.add_development_dependency('rdoc', '>= 2.4.2', '< 6.0')
24
+ s.add_development_dependency('rubocop', '~> 0.49')
24
25
 
26
+ s.add_dependency('http-accept', '>= 1.7.0', '< 2.0')
25
27
  s.add_dependency('http-cookie', '>= 1.0.2', '< 2.0')
26
- s.add_dependency('mime-types', '>= 1.16', '< 3.0')
27
- s.add_dependency('netrc', '~> 0.7')
28
+ s.add_dependency('mime-types', '>= 1.16', '< 4.0')
29
+ s.add_dependency('netrc', '~> 0.8')
28
30
 
29
- s.required_ruby_version = '>= 1.9.2'
31
+ s.required_ruby_version = '>= 2.0.0'
30
32
  end
data/spec/ISS.jpg ADDED
Binary file
data/spec/helpers.rb ADDED
@@ -0,0 +1,54 @@
1
+ require 'uri'
2
+
3
+ module Helpers
4
+
5
+ # @param [Hash] opts A hash of methods, passed directly to the double
6
+ # definition. Use this to stub other required methods.
7
+ #
8
+ # @return double for Net::HTTPResponse
9
+ def res_double(opts={})
10
+ instance_double('Net::HTTPResponse', {to_hash: {}, body: 'response body'}.merge(opts))
11
+ end
12
+
13
+ # Given a Net::HTTPResponse or double and a Request or double, create a
14
+ # RestClient::Response object.
15
+ #
16
+ # @param net_http_res_double an rspec double for Net::HTTPResponse
17
+ # @param request A RestClient::Request or rspec double
18
+ #
19
+ # @return [RestClient::Response]
20
+ #
21
+ def response_from_res_double(net_http_res_double, request=nil, duration: 1)
22
+ request ||= request_double()
23
+ start_time = Time.now - duration
24
+
25
+ response = RestClient::Response.create(net_http_res_double.body, net_http_res_double, request, start_time)
26
+
27
+ # mock duration to ensure it gets the value we expect
28
+ allow(response).to receive(:duration).and_return(duration)
29
+
30
+ response
31
+ end
32
+
33
+ # Redirect stderr to a string for the duration of the passed block.
34
+ def fake_stderr
35
+ original_stderr = $stderr
36
+ $stderr = StringIO.new
37
+ yield
38
+ $stderr.string
39
+ ensure
40
+ $stderr = original_stderr
41
+ end
42
+
43
+ # Create a double for RestClient::Request
44
+ def request_double(url: 'http://example.com', method: 'get')
45
+ instance_double('RestClient::Request',
46
+ url: url, uri: URI.parse(url), method: method, user: nil, password: nil,
47
+ cookie_jar: HTTP::CookieJar.new, redirection_history: nil,
48
+ args: {url: url, method: method})
49
+ end
50
+
51
+ def test_image_path
52
+ File.dirname(__FILE__) + "/ISS.jpg"
53
+ end
54
+ end
@@ -0,0 +1 @@
1
+ require_relative '../spec_helper'
@@ -0,0 +1,22 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
3
+ MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
4
+ d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
5
+ QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
6
+ MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
7
+ b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
8
+ 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
9
+ CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
10
+ nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
11
+ 43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
12
+ T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
13
+ gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
14
+ BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
15
+ TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
16
+ DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
17
+ hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
18
+ 06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
19
+ PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
20
+ YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
21
+ CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
22
+ -----END CERTIFICATE-----
@@ -0,0 +1,22 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
3
+ MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
4
+ d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
5
+ QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
6
+ MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
7
+ b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
8
+ 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
9
+ CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
10
+ nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
11
+ 43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
12
+ T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
13
+ gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
14
+ BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
15
+ TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
16
+ DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
17
+ hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
18
+ 06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
19
+ PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
20
+ YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
21
+ CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
22
+ -----END CERTIFICATE-----