rest-client 1.6.14 → 2.0.2

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 (65) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +6 -6
  3. data/.rspec +2 -1
  4. data/.rubocop-disables.yml +384 -0
  5. data/.rubocop.yml +3 -0
  6. data/.travis.yml +46 -1
  7. data/AUTHORS +28 -5
  8. data/Gemfile +5 -1
  9. data/LICENSE +21 -0
  10. data/README.md +784 -0
  11. data/Rakefile +95 -12
  12. data/bin/restclient +11 -12
  13. data/history.md +180 -16
  14. data/lib/restclient.rb +25 -11
  15. data/lib/restclient/abstract_response.rb +171 -51
  16. data/lib/restclient/exceptions.rb +102 -56
  17. data/lib/restclient/params_array.rb +72 -0
  18. data/lib/restclient/payload.rb +43 -74
  19. data/lib/restclient/platform.rb +22 -2
  20. data/lib/restclient/raw_response.rb +7 -3
  21. data/lib/restclient/request.rb +672 -179
  22. data/lib/restclient/resource.rb +6 -7
  23. data/lib/restclient/response.rb +64 -10
  24. data/lib/restclient/utils.rb +235 -0
  25. data/lib/restclient/version.rb +2 -1
  26. data/lib/restclient/windows.rb +8 -0
  27. data/lib/restclient/windows/root_certs.rb +105 -0
  28. data/rest-client.gemspec +16 -11
  29. data/rest-client.windows.gemspec +19 -0
  30. data/spec/helpers.rb +22 -0
  31. data/spec/integration/_lib.rb +1 -0
  32. data/spec/integration/capath_verisign/415660c1.0 +14 -0
  33. data/spec/integration/capath_verisign/7651b327.0 +14 -0
  34. data/spec/integration/capath_verisign/README +8 -0
  35. data/spec/integration/capath_verisign/verisign.crt +14 -0
  36. data/spec/integration/httpbin_spec.rb +87 -0
  37. data/spec/integration/integration_spec.rb +125 -0
  38. data/spec/integration/request_spec.rb +72 -20
  39. data/spec/spec_helper.rb +29 -0
  40. data/spec/unit/_lib.rb +1 -0
  41. data/spec/unit/abstract_response_spec.rb +145 -0
  42. data/spec/unit/exceptions_spec.rb +108 -0
  43. data/spec/{master_shake.jpg → unit/master_shake.jpg} +0 -0
  44. data/spec/unit/params_array_spec.rb +36 -0
  45. data/spec/{payload_spec.rb → unit/payload_spec.rb} +73 -54
  46. data/spec/{raw_response_spec.rb → unit/raw_response_spec.rb} +5 -4
  47. data/spec/unit/request2_spec.rb +54 -0
  48. data/spec/unit/request_spec.rb +1250 -0
  49. data/spec/unit/resource_spec.rb +134 -0
  50. data/spec/unit/response_spec.rb +241 -0
  51. data/spec/unit/restclient_spec.rb +79 -0
  52. data/spec/unit/utils_spec.rb +147 -0
  53. data/spec/unit/windows/root_certs_spec.rb +22 -0
  54. metadata +143 -53
  55. data/README.rdoc +0 -300
  56. data/lib/restclient/net_http_ext.rb +0 -55
  57. data/spec/abstract_response_spec.rb +0 -85
  58. data/spec/base.rb +0 -13
  59. data/spec/exceptions_spec.rb +0 -98
  60. data/spec/integration_spec.rb +0 -38
  61. data/spec/request2_spec.rb +0 -35
  62. data/spec/request_spec.rb +0 -528
  63. data/spec/resource_spec.rb +0 -136
  64. data/spec/response_spec.rb +0 -169
  65. data/spec/restclient_spec.rb +0 -73
@@ -1,17 +1,18 @@
1
- require File.join( File.dirname(File.expand_path(__FILE__)), 'base')
1
+ require_relative '_lib'
2
2
 
3
3
  describe RestClient::RawResponse do
4
4
  before do
5
5
  @tf = double("Tempfile", :read => "the answer is 42", :open => true)
6
6
  @net_http_res = double('net http response')
7
- @response = RestClient::RawResponse.new(@tf, @net_http_res, {})
7
+ @request = double('http request')
8
+ @response = RestClient::RawResponse.new(@tf, @net_http_res, @request)
8
9
  end
9
10
 
10
11
  it "behaves like string" do
11
- @response.to_s.should eq 'the answer is 42'
12
+ expect(@response.to_s).to eq 'the answer is 42'
12
13
  end
13
14
 
14
15
  it "exposes a Tempfile" do
15
- @response.file.should eq @tf
16
+ expect(@response.file).to eq @tf
16
17
  end
17
18
  end
@@ -0,0 +1,54 @@
1
+ require_relative '_lib'
2
+
3
+ describe RestClient::Request do
4
+
5
+ context 'params for GET requests' do
6
+ it "manage params for get requests" do
7
+ stub_request(:get, 'http://some/resource?a=b&c=d').with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip, deflate', 'Foo'=>'bar'}).to_return(:body => 'foo', :status => 200)
8
+ expect(RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :headers => {:foo => :bar, :params => {:a => :b, 'c' => 'd'}}).body).to eq 'foo'
9
+
10
+ stub_request(:get, 'http://some/resource').with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip, deflate', 'Foo'=>'bar'}).to_return(:body => 'foo', :status => 200)
11
+ expect(RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :headers => {:foo => :bar, :params => :a}).body).to eq 'foo'
12
+ end
13
+
14
+ it 'adds GET params when params are present in URL' do
15
+ stub_request(:get, 'http://some/resource?a=b&c=d').with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip, deflate', 'Foo'=>'bar'}).to_return(:body => 'foo', :status => 200)
16
+ expect(RestClient::Request.execute(:url => 'http://some/resource?a=b', :method => :get, :headers => {:foo => :bar, :params => {:c => 'd'}}).body).to eq 'foo'
17
+ end
18
+
19
+ it 'encodes nested GET params' do
20
+ stub_request(:get, 'http://some/resource?a[foo][]=1&a[foo][]=2&a[bar]&b=foo+bar&math=2+%2B+2+%3D%3D+4').with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip, deflate'}).to_return(:body => 'foo', :status => 200)
21
+ expect(RestClient::Request.execute(url: 'http://some/resource', method: :get, headers: {
22
+ params: {
23
+ a: {
24
+ foo: [1,2],
25
+ bar: nil,
26
+ },
27
+ b: 'foo bar',
28
+ math: '2 + 2 == 4',
29
+ }
30
+ }).body).to eq 'foo'
31
+ end
32
+
33
+ end
34
+
35
+ it "can use a block to process response" do
36
+ response_value = nil
37
+ block = proc do |http_response|
38
+ response_value = http_response.body
39
+ end
40
+ stub_request(:get, 'http://some/resource?a=b&c=d').with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip, deflate', 'Foo'=>'bar'}).to_return(:body => 'foo', :status => 200)
41
+ RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :headers => {:foo => :bar, :params => {:a => :b, 'c' => 'd'}}, :block_response => block)
42
+ expect(response_value).to eq "foo"
43
+ end
44
+
45
+ it 'closes payload if not nil' do
46
+ test_file = File.new(File.join( File.dirname(File.expand_path(__FILE__)), 'master_shake.jpg'))
47
+
48
+ stub_request(:post, 'http://some/resource').with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip, deflate'}).to_return(:body => 'foo', :status => 200)
49
+ RestClient::Request.execute(:url => 'http://some/resource', :method => :post, :payload => {:file => test_file})
50
+
51
+ expect(test_file.closed?).to be true
52
+ end
53
+
54
+ end
@@ -0,0 +1,1250 @@
1
+ require_relative './_lib'
2
+
3
+ describe RestClient::Request, :include_helpers do
4
+ before do
5
+ @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload')
6
+
7
+ @uri = double("uri")
8
+ allow(@uri).to receive(:request_uri).and_return('/resource')
9
+ allow(@uri).to receive(:hostname).and_return('some')
10
+ allow(@uri).to receive(:port).and_return(80)
11
+
12
+ @net = double("net::http base")
13
+ @http = double("net::http connection")
14
+
15
+ allow(Net::HTTP).to receive(:new).and_return(@net)
16
+
17
+ allow(@net).to receive(:start).and_yield(@http)
18
+ allow(@net).to receive(:use_ssl=)
19
+ allow(@net).to receive(:verify_mode=)
20
+ allow(@net).to receive(:verify_callback=)
21
+ allow(@net).to receive(:ciphers=)
22
+ allow(@net).to receive(:cert_store=)
23
+ RestClient.log = nil
24
+ end
25
+
26
+ it "accept */* mimetype" do
27
+ expect(@request.default_headers[:accept]).to eq '*/*'
28
+ end
29
+
30
+ describe "compression" do
31
+
32
+ it "decodes an uncompressed result body by passing it straight through" do
33
+ expect(RestClient::Request.decode(nil, 'xyz')).to eq 'xyz'
34
+ end
35
+
36
+ it "doesn't fail for nil bodies" do
37
+ expect(RestClient::Request.decode('gzip', nil)).to be_nil
38
+ end
39
+
40
+
41
+ it "decodes a gzip body" do
42
+ expect(RestClient::Request.decode('gzip', "\037\213\b\b\006'\252H\000\003t\000\313T\317UH\257\312,HM\341\002\000G\242(\r\v\000\000\000")).to eq "i'm gziped\n"
43
+ end
44
+
45
+ it "ingores gzip for empty bodies" do
46
+ expect(RestClient::Request.decode('gzip', '')).to be_empty
47
+ end
48
+
49
+ it "decodes a deflated body" do
50
+ expect(RestClient::Request.decode('deflate', "x\234+\316\317MUHIM\313I,IMQ(I\255(\001\000A\223\006\363")).to eq "some deflated text"
51
+ end
52
+ end
53
+
54
+ it "processes a successful result" do
55
+ res = response_double
56
+ allow(res).to receive(:code).and_return("200")
57
+ allow(res).to receive(:body).and_return('body')
58
+ allow(res).to receive(:[]).with('content-encoding').and_return(nil)
59
+ expect(@request.send(:process_result, res).body).to eq 'body'
60
+ expect(@request.send(:process_result, res).to_s).to eq 'body'
61
+ end
62
+
63
+ it "doesn't classify successful requests as failed" do
64
+ 203.upto(207) do |code|
65
+ res = response_double
66
+ allow(res).to receive(:code).and_return(code.to_s)
67
+ allow(res).to receive(:body).and_return("")
68
+ allow(res).to receive(:[]).with('content-encoding').and_return(nil)
69
+ expect(@request.send(:process_result, res)).to be_empty
70
+ end
71
+ end
72
+
73
+ describe '.normalize_url' do
74
+ it "adds http:// to the front of resources specified in the syntax example.com/resource" do
75
+ expect(@request.normalize_url('example.com/resource')).to eq 'http://example.com/resource'
76
+ end
77
+
78
+ it 'adds http:// to resources containing a colon' do
79
+ expect(@request.normalize_url('example.com:1234')).to eq 'http://example.com:1234'
80
+ end
81
+
82
+ it 'does not add http:// to the front of https resources' do
83
+ expect(@request.normalize_url('https://example.com/resource')).to eq 'https://example.com/resource'
84
+ end
85
+
86
+ it 'does not add http:// to the front of capital HTTP resources' do
87
+ expect(@request.normalize_url('HTTP://example.com/resource')).to eq 'HTTP://example.com/resource'
88
+ end
89
+
90
+ it 'does not add http:// to the front of capital HTTPS resources' do
91
+ expect(@request.normalize_url('HTTPS://example.com/resource')).to eq 'HTTPS://example.com/resource'
92
+ end
93
+
94
+ it 'raises with invalid URI' do
95
+ expect {
96
+ RestClient::Request.new(method: :get, url: 'http://a@b:c')
97
+ }.to raise_error(URI::InvalidURIError)
98
+ expect {
99
+ RestClient::Request.new(method: :get, url: 'http://::')
100
+ }.to raise_error(URI::InvalidURIError)
101
+ end
102
+ end
103
+
104
+ describe "user - password" do
105
+ it "extracts the username and password when parsing http://user:password@example.com/" do
106
+ @request.send(:parse_url_with_auth!, 'http://joe:pass1@example.com/resource')
107
+ expect(@request.user).to eq 'joe'
108
+ expect(@request.password).to eq 'pass1'
109
+ end
110
+
111
+ it "extracts with escaping the username and password when parsing http://user:password@example.com/" do
112
+ @request.send(:parse_url_with_auth!, 'http://joe%20:pass1@example.com/resource')
113
+ expect(@request.user).to eq 'joe '
114
+ expect(@request.password).to eq 'pass1'
115
+ end
116
+
117
+ it "doesn't overwrite user and password (which may have already been set by the Resource constructor) if there is no user/password in the url" do
118
+ request = RestClient::Request.new(method: :get, url: 'http://example.com/resource', user: 'beth', password: 'pass2')
119
+ expect(request.user).to eq 'beth'
120
+ expect(request.password).to eq 'pass2'
121
+ end
122
+
123
+ it 'uses the username and password from the URL' do
124
+ request = RestClient::Request.new(method: :get, url: 'http://person:secret@example.com/resource')
125
+ expect(request.user).to eq 'person'
126
+ expect(request.password).to eq 'secret'
127
+ end
128
+
129
+ it 'overrides URL user/pass with explicit options' do
130
+ request = RestClient::Request.new(method: :get, url: 'http://person:secret@example.com/resource', user: 'beth', password: 'pass2')
131
+ expect(request.user).to eq 'beth'
132
+ expect(request.password).to eq 'pass2'
133
+ end
134
+ end
135
+
136
+ it "correctly formats cookies provided to the constructor" do
137
+ cookies_arr = [
138
+ HTTP::Cookie.new('session_id', '1', domain: 'example.com', path: '/'),
139
+ HTTP::Cookie.new('user_id', 'someone', domain: 'example.com', path: '/'),
140
+ ]
141
+
142
+ jar = HTTP::CookieJar.new
143
+ cookies_arr.each {|c| jar << c }
144
+
145
+ # test Hash, HTTP::CookieJar, and Array<HTTP::Cookie> modes
146
+ [
147
+ {session_id: '1', user_id: 'someone'},
148
+ jar,
149
+ cookies_arr
150
+ ].each do |cookies|
151
+ [true, false].each do |in_headers|
152
+ if in_headers
153
+ opts = {headers: {cookies: cookies}}
154
+ else
155
+ opts = {cookies: cookies}
156
+ end
157
+
158
+ request = RestClient::Request.new(method: :get, url: 'example.com', **opts)
159
+ expect(request).to receive(:default_headers).and_return({'Foo' => 'bar'})
160
+ expect(request.make_headers({})).to eq({'Foo' => 'bar', 'Cookie' => 'session_id=1; user_id=someone'})
161
+ expect(request.make_cookie_header).to eq 'session_id=1; user_id=someone'
162
+ expect(request.cookies).to eq({'session_id' => '1', 'user_id' => 'someone'})
163
+ expect(request.cookie_jar.cookies.length).to eq 2
164
+ expect(request.cookie_jar.object_id).not_to eq jar.object_id # make sure we dup it
165
+ end
166
+ end
167
+
168
+ # test with no cookies
169
+ request = RestClient::Request.new(method: :get, url: 'example.com')
170
+ expect(request).to receive(:default_headers).and_return({'Foo' => 'bar'})
171
+ expect(request.make_headers({})).to eq({'Foo' => 'bar'})
172
+ expect(request.make_cookie_header).to be_nil
173
+ expect(request.cookies).to eq({})
174
+ expect(request.cookie_jar.cookies.length).to eq 0
175
+ end
176
+
177
+ it 'strips out cookies set for a different domain name' do
178
+ jar = HTTP::CookieJar.new
179
+ jar << HTTP::Cookie.new('session_id', '1', domain: 'other.example.com', path: '/')
180
+ jar << HTTP::Cookie.new('user_id', 'someone', domain: 'other.example.com', path: '/')
181
+
182
+ request = RestClient::Request.new(method: :get, url: 'www.example.com', cookies: jar)
183
+ expect(request).to receive(:default_headers).and_return({'Foo' => 'bar'})
184
+ expect(request.make_headers({})).to eq({'Foo' => 'bar'})
185
+ expect(request.make_cookie_header).to eq nil
186
+ expect(request.cookies).to eq({})
187
+ expect(request.cookie_jar.cookies.length).to eq 2
188
+ end
189
+
190
+ it 'assumes default domain and path for cookies set by hash' do
191
+ request = RestClient::Request.new(method: :get, url: 'www.example.com', cookies: {'session_id' => '1'})
192
+ expect(request.cookie_jar.cookies.length).to eq 1
193
+
194
+ cookie = request.cookie_jar.cookies.first
195
+ expect(cookie).to be_a(HTTP::Cookie)
196
+ expect(cookie.domain).to eq('www.example.com')
197
+ expect(cookie.for_domain?).to be_truthy
198
+ expect(cookie.path).to eq('/')
199
+ end
200
+
201
+ it 'rejects or warns with contradictory cookie options' do
202
+ # same opt in two different places
203
+ expect {
204
+ RestClient::Request.new(method: :get, url: 'example.com',
205
+ cookies: {bar: '456'},
206
+ headers: {cookies: {foo: '123'}})
207
+ }.to raise_error(ArgumentError, /Cannot pass :cookies in Request.*headers/)
208
+
209
+ # :cookies opt and Cookie header
210
+ [
211
+ {cookies: {foo: '123'}, headers: {cookie: 'foo'}},
212
+ {cookies: {foo: '123'}, headers: {'Cookie' => 'foo'}},
213
+ {headers: {cookies: {foo: '123'}, cookie: 'foo'}},
214
+ {headers: {cookies: {foo: '123'}, 'Cookie' => 'foo'}},
215
+ ].each do |opts|
216
+ expect(fake_stderr {
217
+ RestClient::Request.new(method: :get, url: 'example.com', **opts)
218
+ }).to match(/warning: overriding "Cookie" header with :cookies option/)
219
+ end
220
+ end
221
+
222
+ it "does not escape or unescape cookies" do
223
+ cookie = 'Foo%20:Bar%0A~'
224
+ @request = RestClient::Request.new(:method => 'get', :url => 'example.com',
225
+ :cookies => {:test => cookie})
226
+ expect(@request).to receive(:default_headers).and_return({'Foo' => 'bar'})
227
+ expect(@request.make_headers({})).to eq({
228
+ 'Foo' => 'bar',
229
+ 'Cookie' => "test=#{cookie}"
230
+ })
231
+ end
232
+
233
+ it "rejects cookie names containing invalid characters" do
234
+ # Cookie validity is something of a mess, but we should reject the worst of
235
+ # the RFC 6265 (4.1.1) prohibited characters such as control characters.
236
+
237
+ ['foo=bar', 'foo;bar', "foo\nbar"].each do |cookie_name|
238
+ expect {
239
+ RestClient::Request.new(:method => 'get', :url => 'example.com',
240
+ :cookies => {cookie_name => 'value'})
241
+ }.to raise_error(ArgumentError, /\AInvalid cookie name/i)
242
+ end
243
+
244
+ cookie_name = ''
245
+ expect {
246
+ RestClient::Request.new(:method => 'get', :url => 'example.com',
247
+ :cookies => {cookie_name => 'value'})
248
+ }.to raise_error(ArgumentError, /cookie name cannot be empty/i)
249
+ end
250
+
251
+ it "rejects cookie values containing invalid characters" do
252
+ # Cookie validity is something of a mess, but we should reject the worst of
253
+ # the RFC 6265 (4.1.1) prohibited characters such as control characters.
254
+
255
+ ["foo\tbar", "foo\nbar"].each do |cookie_value|
256
+ expect {
257
+ RestClient::Request.new(:method => 'get', :url => 'example.com',
258
+ :cookies => {'test' => cookie_value})
259
+ }.to raise_error(ArgumentError, /\AInvalid cookie value/i)
260
+ end
261
+ end
262
+
263
+ it 'warns when overriding existing headers via payload' do
264
+ expect(fake_stderr {
265
+ RestClient::Request.new(method: :post, url: 'example.com',
266
+ payload: {'foo' => 1}, headers: {content_type: :json})
267
+ }).to match(/warning: Overriding "Content-Type" header/i)
268
+ expect(fake_stderr {
269
+ RestClient::Request.new(method: :post, url: 'example.com',
270
+ payload: {'foo' => 1}, headers: {'Content-Type' => 'application/json'})
271
+ }).to match(/warning: Overriding "Content-Type" header/i)
272
+
273
+ expect(fake_stderr {
274
+ RestClient::Request.new(method: :post, url: 'example.com',
275
+ payload: '123456', headers: {content_length: '20'})
276
+ }).to match(/warning: Overriding "Content-Length" header/i)
277
+ expect(fake_stderr {
278
+ RestClient::Request.new(method: :post, url: 'example.com',
279
+ payload: '123456', headers: {'Content-Length' => '20'})
280
+ }).to match(/warning: Overriding "Content-Length" header/i)
281
+ end
282
+
283
+ it "does not warn when overriding user header with header derived from payload if those header values were identical" do
284
+ expect(fake_stderr {
285
+ RestClient::Request.new(method: :post, url: 'example.com',
286
+ payload: {'foo' => '123456'}, headers: { 'Content-Type' => 'application/x-www-form-urlencoded' })
287
+ }).not_to match(/warning: Overriding "Content-Type" header/i)
288
+ end
289
+
290
+ it 'does not warn for a normal looking payload' do
291
+ expect(fake_stderr {
292
+ RestClient::Request.new(method: :post, url: 'example.com', payload: 'payload')
293
+ RestClient::Request.new(method: :post, url: 'example.com', payload: 'payload', headers: {content_type: :json})
294
+ RestClient::Request.new(method: :post, url: 'example.com', payload: {'foo' => 'bar'})
295
+ }).to eq ''
296
+ end
297
+
298
+ it "uses netrc credentials" do
299
+ expect(Netrc).to receive(:read).and_return('example.com' => ['a', 'b'])
300
+ request = RestClient::Request.new(:method => :put, :url => 'http://example.com/', :payload => 'payload')
301
+ expect(request.user).to eq 'a'
302
+ expect(request.password).to eq 'b'
303
+ end
304
+
305
+ it "uses credentials in the url in preference to netrc" do
306
+ allow(Netrc).to receive(:read).and_return('example.com' => ['a', 'b'])
307
+ request = RestClient::Request.new(:method => :put, :url => 'http://joe%20:pass1@example.com/', :payload => 'payload')
308
+ expect(request.user).to eq 'joe '
309
+ expect(request.password).to eq 'pass1'
310
+ end
311
+
312
+ it "determines the Net::HTTP class to instantiate by the method name" do
313
+ expect(@request.net_http_request_class(:put)).to eq Net::HTTP::Put
314
+ end
315
+
316
+ describe "user headers" do
317
+ it "merges user headers with the default headers" do
318
+ expect(@request).to receive(:default_headers).and_return({ :accept => '*/*', :accept_encoding => 'gzip, deflate' })
319
+ headers = @request.make_headers("Accept" => "application/json", :accept_encoding => 'gzip')
320
+ expect(headers).to have_key "Accept-Encoding"
321
+ expect(headers["Accept-Encoding"]).to eq "gzip"
322
+ expect(headers).to have_key "Accept"
323
+ expect(headers["Accept"]).to eq "application/json"
324
+ end
325
+
326
+ it "prefers the user header when the same header exists in the defaults" do
327
+ expect(@request).to receive(:default_headers).and_return({ '1' => '2' })
328
+ headers = @request.make_headers('1' => '3')
329
+ expect(headers).to have_key('1')
330
+ expect(headers['1']).to eq '3'
331
+ end
332
+
333
+ it "converts user headers to string before calling CGI::unescape which fails on non string values" do
334
+ expect(@request).to receive(:default_headers).and_return({ '1' => '2' })
335
+ headers = @request.make_headers('1' => 3)
336
+ expect(headers).to have_key('1')
337
+ expect(headers['1']).to eq '3'
338
+ end
339
+ end
340
+
341
+ describe "header symbols" do
342
+
343
+ it "converts header symbols from :content_type to 'Content-Type'" do
344
+ expect(@request).to receive(:default_headers).and_return({})
345
+ headers = @request.make_headers(:content_type => 'abc')
346
+ expect(headers).to have_key('Content-Type')
347
+ expect(headers['Content-Type']).to eq 'abc'
348
+ end
349
+
350
+ it "converts content-type from extension to real content-type" do
351
+ expect(@request).to receive(:default_headers).and_return({})
352
+ headers = @request.make_headers(:content_type => 'json')
353
+ expect(headers).to have_key('Content-Type')
354
+ expect(headers['Content-Type']).to eq 'application/json'
355
+ end
356
+
357
+ it "converts accept from extension(s) to real content-type(s)" do
358
+ expect(@request).to receive(:default_headers).and_return({})
359
+ headers = @request.make_headers(:accept => 'json, mp3')
360
+ expect(headers).to have_key('Accept')
361
+ expect(headers['Accept']).to eq 'application/json, audio/mpeg'
362
+
363
+ expect(@request).to receive(:default_headers).and_return({})
364
+ headers = @request.make_headers(:accept => :json)
365
+ expect(headers).to have_key('Accept')
366
+ expect(headers['Accept']).to eq 'application/json'
367
+ end
368
+
369
+ it "only convert symbols in header" do
370
+ expect(@request).to receive(:default_headers).and_return({})
371
+ headers = @request.make_headers({:foo_bar => 'value', "bar_bar" => 'value'})
372
+ expect(headers['Foo-Bar']).to eq 'value'
373
+ expect(headers['bar_bar']).to eq 'value'
374
+ end
375
+
376
+ it "converts header values to strings" do
377
+ expect(@request.make_headers('A' => 1)['A']).to eq '1'
378
+ end
379
+ end
380
+
381
+ it "executes by constructing the Net::HTTP object, headers, and payload and calling transmit" do
382
+ klass = double("net:http class")
383
+ expect(@request).to receive(:net_http_request_class).with('put').and_return(klass)
384
+ expect(klass).to receive(:new).and_return('result')
385
+ expect(@request).to receive(:transmit).with(@request.uri, 'result', kind_of(RestClient::Payload::Base))
386
+ @request.execute
387
+ end
388
+
389
+ it "IPv6: executes by constructing the Net::HTTP object, headers, and payload and calling transmit" do
390
+ @request = RestClient::Request.new(:method => :put, :url => 'http://[::1]/some/resource', :payload => 'payload')
391
+ klass = double("net:http class")
392
+ expect(@request).to receive(:net_http_request_class).with('put').and_return(klass)
393
+
394
+ if RUBY_VERSION >= "2.0.0"
395
+ expect(klass).to receive(:new).with(kind_of(URI), kind_of(Hash)).and_return('result')
396
+ else
397
+ expect(klass).to receive(:new).with(kind_of(String), kind_of(Hash)).and_return('result')
398
+ end
399
+
400
+ expect(@request).to receive(:transmit)
401
+ @request.execute
402
+ end
403
+
404
+ # TODO: almost none of these tests should actually call transmit, which is
405
+ # part of the private API
406
+
407
+ it "transmits the request with Net::HTTP" do
408
+ expect(@http).to receive(:request).with('req', 'payload')
409
+ expect(@request).to receive(:process_result)
410
+ @request.send(:transmit, @uri, 'req', 'payload')
411
+ end
412
+
413
+ # TODO: most of these payload tests are historical relics that actually
414
+ # belong in payload_spec.rb. Or we need new tests that actually cover the way
415
+ # that Request#initialize or Request#execute uses the payload.
416
+ describe "payload" do
417
+ it "sends nil payloads" do
418
+ expect(@http).to receive(:request).with('req', nil)
419
+ expect(@request).to receive(:process_result)
420
+ allow(@request).to receive(:response_log)
421
+ @request.send(:transmit, @uri, 'req', nil)
422
+ end
423
+
424
+ it "passes non-hash payloads straight through" do
425
+ expect(RestClient::Payload.generate("x").to_s).to eq "x"
426
+ end
427
+
428
+ it "converts a hash payload to urlencoded data" do
429
+ expect(RestClient::Payload.generate(:a => 'b c+d').to_s).to eq "a=b+c%2Bd"
430
+ end
431
+
432
+ it "accepts nested hashes in payload" do
433
+ payload = RestClient::Payload.generate(:user => { :name => 'joe', :location => { :country => 'USA', :state => 'CA' }}).to_s
434
+ expect(payload).to include('user[name]=joe')
435
+ expect(payload).to include('user[location][country]=USA')
436
+ expect(payload).to include('user[location][state]=CA')
437
+ end
438
+ end
439
+
440
+ it "set urlencoded content_type header on hash payloads" do
441
+ req = RestClient::Request.new(method: :post, url: 'http://some/resource', payload: {a: 1})
442
+ expect(req.processed_headers.fetch('Content-Type')).to eq 'application/x-www-form-urlencoded'
443
+ end
444
+
445
+ describe "credentials" do
446
+ it "sets up the credentials prior to the request" do
447
+ allow(@http).to receive(:request)
448
+
449
+ allow(@request).to receive(:process_result)
450
+ allow(@request).to receive(:response_log)
451
+
452
+ allow(@request).to receive(:user).and_return('joe')
453
+ allow(@request).to receive(:password).and_return('mypass')
454
+ expect(@request).to receive(:setup_credentials).with('req')
455
+
456
+ @request.send(:transmit, @uri, 'req', nil)
457
+ end
458
+
459
+ it "does not attempt to send any credentials if user is nil" do
460
+ allow(@request).to receive(:user).and_return(nil)
461
+ req = double("request")
462
+ expect(req).not_to receive(:basic_auth)
463
+ @request.send(:setup_credentials, req)
464
+ end
465
+
466
+ it "setup credentials when there's a user" do
467
+ allow(@request).to receive(:user).and_return('joe')
468
+ allow(@request).to receive(:password).and_return('mypass')
469
+ req = double("request")
470
+ expect(req).to receive(:basic_auth).with('joe', 'mypass')
471
+ @request.send(:setup_credentials, req)
472
+ end
473
+
474
+ it "does not attempt to send credentials if Authorization header is set" do
475
+ @request.headers['Authorization'] = 'Token abc123'
476
+ allow(@request).to receive(:user).and_return('joe')
477
+ allow(@request).to receive(:password).and_return('mypass')
478
+ req = double("request")
479
+ expect(req).not_to receive(:basic_auth)
480
+ @request.send(:setup_credentials, req)
481
+ end
482
+ end
483
+
484
+ it "catches EOFError and shows the more informative ServerBrokeConnection" do
485
+ allow(@http).to receive(:request).and_raise(EOFError)
486
+ expect { @request.send(:transmit, @uri, 'req', nil) }.to raise_error(RestClient::ServerBrokeConnection)
487
+ end
488
+
489
+ it "catches OpenSSL::SSL::SSLError and raise it back without more informative message" do
490
+ allow(@http).to receive(:request).and_raise(OpenSSL::SSL::SSLError)
491
+ expect { @request.send(:transmit, @uri, 'req', nil) }.to raise_error(OpenSSL::SSL::SSLError)
492
+ end
493
+
494
+ it "catches Timeout::Error and raise the more informative ReadTimeout" do
495
+ allow(@http).to receive(:request).and_raise(Timeout::Error)
496
+ expect { @request.send(:transmit, @uri, 'req', nil) }.to raise_error(RestClient::Exceptions::ReadTimeout)
497
+ end
498
+
499
+ it "catches Errno::ETIMEDOUT and raise the more informative ReadTimeout" do
500
+ allow(@http).to receive(:request).and_raise(Errno::ETIMEDOUT)
501
+ expect { @request.send(:transmit, @uri, 'req', nil) }.to raise_error(RestClient::Exceptions::ReadTimeout)
502
+ end
503
+
504
+ it "catches Net::ReadTimeout and raises RestClient's ReadTimeout",
505
+ :if => defined?(Net::ReadTimeout) do
506
+ allow(@http).to receive(:request).and_raise(Net::ReadTimeout)
507
+ expect { @request.send(:transmit, @uri, 'req', nil) }.to raise_error(RestClient::Exceptions::ReadTimeout)
508
+ end
509
+
510
+ it "catches Net::OpenTimeout and raises RestClient's OpenTimeout",
511
+ :if => defined?(Net::OpenTimeout) do
512
+ allow(@http).to receive(:request).and_raise(Net::OpenTimeout)
513
+ expect { @request.send(:transmit, @uri, 'req', nil) }.to raise_error(RestClient::Exceptions::OpenTimeout)
514
+ end
515
+
516
+ it "uses correct error message for ReadTimeout",
517
+ :if => defined?(Net::ReadTimeout) do
518
+ allow(@http).to receive(:request).and_raise(Net::ReadTimeout)
519
+ expect { @request.send(:transmit, @uri, 'req', nil) }.to raise_error(RestClient::Exceptions::ReadTimeout, 'Timed out reading data from server')
520
+ end
521
+
522
+ it "uses correct error message for OpenTimeout",
523
+ :if => defined?(Net::OpenTimeout) do
524
+ allow(@http).to receive(:request).and_raise(Net::OpenTimeout)
525
+ expect { @request.send(:transmit, @uri, 'req', nil) }.to raise_error(RestClient::Exceptions::OpenTimeout, 'Timed out connecting to server')
526
+ end
527
+
528
+
529
+ it "class method execute wraps constructor" do
530
+ req = double("rest request")
531
+ expect(RestClient::Request).to receive(:new).with(1 => 2).and_return(req)
532
+ expect(req).to receive(:execute)
533
+ RestClient::Request.execute(1 => 2)
534
+ end
535
+
536
+ describe "exception" do
537
+ it "raises Unauthorized when the response is 401" do
538
+ res = response_double(:code => '401', :[] => ['content-encoding' => ''], :body => '' )
539
+ expect { @request.send(:process_result, res) }.to raise_error(RestClient::Unauthorized)
540
+ end
541
+
542
+ it "raises ResourceNotFound when the response is 404" do
543
+ res = response_double(:code => '404', :[] => ['content-encoding' => ''], :body => '' )
544
+ expect { @request.send(:process_result, res) }.to raise_error(RestClient::ResourceNotFound)
545
+ end
546
+
547
+ it "raises RequestFailed otherwise" do
548
+ res = response_double(:code => '500', :[] => ['content-encoding' => ''], :body => '' )
549
+ expect { @request.send(:process_result, res) }.to raise_error(RestClient::InternalServerError)
550
+ end
551
+ end
552
+
553
+ describe "block usage" do
554
+ it "returns what asked to" do
555
+ res = response_double(:code => '401', :[] => ['content-encoding' => ''], :body => '' )
556
+ expect(@request.send(:process_result, res){|response, request| "foo"}).to eq "foo"
557
+ end
558
+ end
559
+
560
+ describe "proxy" do
561
+ before do
562
+ # unstub Net::HTTP creation since we need to test it
563
+ allow(Net::HTTP).to receive(:new).and_call_original
564
+
565
+ @proxy_req = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload')
566
+ end
567
+
568
+ it "creates a proxy class if a proxy url is given" do
569
+ allow(RestClient).to receive(:proxy).and_return("http://example.com/")
570
+ allow(RestClient).to receive(:proxy_set?).and_return(true)
571
+ expect(@proxy_req.net_http_object('host', 80).proxy?).to be true
572
+ end
573
+
574
+ it "creates a proxy class with the correct address if a IPv6 proxy url is given" do
575
+ allow(RestClient).to receive(:proxy).and_return("http://[::1]/")
576
+ allow(RestClient).to receive(:proxy_set?).and_return(true)
577
+ expect(@proxy_req.net_http_object('host', 80).proxy?).to be true
578
+ expect(@proxy_req.net_http_object('host', 80).proxy_address).to eq('::1')
579
+ end
580
+
581
+ it "creates a non-proxy class if a proxy url is not given" do
582
+ expect(@proxy_req.net_http_object('host', 80).proxy?).to be_falsey
583
+ end
584
+
585
+ it "disables proxy on a per-request basis" do
586
+ allow(RestClient).to receive(:proxy).and_return('http://example.com')
587
+ allow(RestClient).to receive(:proxy_set?).and_return(true)
588
+ expect(@proxy_req.net_http_object('host', 80).proxy?).to be true
589
+
590
+ disabled_req = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :proxy => nil)
591
+ expect(disabled_req.net_http_object('host', 80).proxy?).to be_falsey
592
+ end
593
+
594
+ it "sets proxy on a per-request basis" do
595
+ expect(@proxy_req.net_http_object('some', 80).proxy?).to be_falsey
596
+
597
+ req = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :proxy => 'http://example.com')
598
+ expect(req.net_http_object('host', 80).proxy?).to be true
599
+ end
600
+
601
+ it "overrides proxy from environment", if: RUBY_VERSION >= '2.0' do
602
+ allow(ENV).to receive(:[]).with("http_proxy").and_return("http://127.0.0.1")
603
+ allow(ENV).to receive(:[]).with("no_proxy").and_return(nil)
604
+ allow(ENV).to receive(:[]).with("NO_PROXY").and_return(nil)
605
+ allow(Netrc).to receive(:read).and_return({})
606
+
607
+ req = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload')
608
+ obj = req.net_http_object('host', 80)
609
+ expect(obj.proxy?).to be true
610
+ expect(obj.proxy_address).to eq '127.0.0.1'
611
+
612
+ # test original method .proxy?
613
+ req = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :proxy => nil)
614
+ obj = req.net_http_object('host', 80)
615
+ expect(obj.proxy?).to be_falsey
616
+
617
+ # stub RestClient.proxy_set? to peek into implementation
618
+ allow(RestClient).to receive(:proxy_set?).and_return(true)
619
+ req = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload')
620
+ obj = req.net_http_object('host', 80)
621
+ expect(obj.proxy?).to be_falsey
622
+
623
+ # test stubbed Net::HTTP.new
624
+ req = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :proxy => nil)
625
+ expect(Net::HTTP).to receive(:new).with('host', 80, nil, nil, nil, nil)
626
+ req.net_http_object('host', 80)
627
+ end
628
+
629
+ it "overrides global proxy with per-request proxy" do
630
+ allow(RestClient).to receive(:proxy).and_return('http://example.com')
631
+ allow(RestClient).to receive(:proxy_set?).and_return(true)
632
+ obj = @proxy_req.net_http_object('host', 80)
633
+ expect(obj.proxy?).to be true
634
+ expect(obj.proxy_address).to eq 'example.com'
635
+
636
+ req = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :proxy => 'http://127.0.0.1/')
637
+ expect(req.net_http_object('host', 80).proxy?).to be true
638
+ expect(req.net_http_object('host', 80).proxy_address).to eq('127.0.0.1')
639
+ end
640
+ end
641
+
642
+
643
+ describe "logging" do
644
+ it "logs a get request" do
645
+ log = RestClient.log = []
646
+ RestClient::Request.new(:method => :get, :url => 'http://url', :headers => {:user_agent => 'rest-client'}).log_request
647
+ expect(log[0]).to eq %Q{RestClient.get "http://url", "Accept"=>"*/*", "Accept-Encoding"=>"gzip, deflate", "User-Agent"=>"rest-client"\n}
648
+ end
649
+
650
+ it "logs a post request with a small payload" do
651
+ log = RestClient.log = []
652
+ RestClient::Request.new(:method => :post, :url => 'http://url', :payload => 'foo', :headers => {:user_agent => 'rest-client'}).log_request
653
+ expect(log[0]).to eq %Q{RestClient.post "http://url", "foo", "Accept"=>"*/*", "Accept-Encoding"=>"gzip, deflate", "Content-Length"=>"3", "User-Agent"=>"rest-client"\n}
654
+ end
655
+
656
+ it "logs a post request with a large payload" do
657
+ log = RestClient.log = []
658
+ RestClient::Request.new(:method => :post, :url => 'http://url', :payload => ('x' * 1000), :headers => {:user_agent => 'rest-client'}).log_request
659
+ expect(log[0]).to eq %Q{RestClient.post "http://url", 1000 byte(s) length, "Accept"=>"*/*", "Accept-Encoding"=>"gzip, deflate", "Content-Length"=>"1000", "User-Agent"=>"rest-client"\n}
660
+ end
661
+
662
+ it "logs input headers as a hash" do
663
+ log = RestClient.log = []
664
+ RestClient::Request.new(:method => :get, :url => 'http://url', :headers => { :accept => 'text/plain', :user_agent => 'rest-client' }).log_request
665
+ expect(log[0]).to eq %Q{RestClient.get "http://url", "Accept"=>"text/plain", "Accept-Encoding"=>"gzip, deflate", "User-Agent"=>"rest-client"\n}
666
+ end
667
+
668
+ it "logs a response including the status code, content type, and result body size in bytes" do
669
+ log = RestClient.log = []
670
+ res = double('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd')
671
+ allow(res).to receive(:[]).with('Content-type').and_return('text/html')
672
+ @request.log_response res
673
+ expect(log[0]).to eq "# => 200 OK | text/html 4 bytes\n"
674
+ end
675
+
676
+ it "logs a response with a nil Content-type" do
677
+ log = RestClient.log = []
678
+ res = double('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd')
679
+ allow(res).to receive(:[]).with('Content-type').and_return(nil)
680
+ @request.log_response res
681
+ expect(log[0]).to eq "# => 200 OK | 4 bytes\n"
682
+ end
683
+
684
+ it "logs a response with a nil body" do
685
+ log = RestClient.log = []
686
+ res = double('result', :code => '200', :class => Net::HTTPOK, :body => nil)
687
+ allow(res).to receive(:[]).with('Content-type').and_return('text/html; charset=utf-8')
688
+ @request.log_response res
689
+ expect(log[0]).to eq "# => 200 OK | text/html 0 bytes\n"
690
+ end
691
+
692
+ it 'does not log request password' do
693
+ log = RestClient.log = []
694
+ RestClient::Request.new(:method => :get, :url => 'http://user:password@url', :headers => {:user_agent => 'rest-client'}).log_request
695
+ expect(log[0]).to eq %Q{RestClient.get "http://user:REDACTED@url", "Accept"=>"*/*", "Accept-Encoding"=>"gzip, deflate", "User-Agent"=>"rest-client"\n}
696
+ end
697
+ end
698
+
699
+ it "strips the charset from the response content type" do
700
+ log = RestClient.log = []
701
+ res = double('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd')
702
+ allow(res).to receive(:[]).with('Content-type').and_return('text/html; charset=utf-8')
703
+ @request.log_response res
704
+ expect(log[0]).to eq "# => 200 OK | text/html 4 bytes\n"
705
+ end
706
+
707
+ describe "timeout" do
708
+ it "does not set timeouts if not specified" do
709
+ @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload')
710
+ allow(@http).to receive(:request)
711
+ allow(@request).to receive(:process_result)
712
+ allow(@request).to receive(:response_log)
713
+
714
+ expect(@net).not_to receive(:read_timeout=)
715
+ expect(@net).not_to receive(:open_timeout=)
716
+
717
+ @request.send(:transmit, @uri, 'req', nil)
718
+ end
719
+
720
+ it 'sets read_timeout' do
721
+ @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :read_timeout => 123)
722
+ allow(@http).to receive(:request)
723
+ allow(@request).to receive(:process_result)
724
+ allow(@request).to receive(:response_log)
725
+
726
+ expect(@net).to receive(:read_timeout=).with(123)
727
+
728
+ @request.send(:transmit, @uri, 'req', nil)
729
+ end
730
+
731
+ it "sets open_timeout" do
732
+ @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :open_timeout => 123)
733
+ allow(@http).to receive(:request)
734
+ allow(@request).to receive(:process_result)
735
+ allow(@request).to receive(:response_log)
736
+
737
+ expect(@net).to receive(:open_timeout=).with(123)
738
+
739
+ @request.send(:transmit, @uri, 'req', nil)
740
+ end
741
+
742
+ it 'sets both timeouts with :timeout' do
743
+ @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :timeout => 123)
744
+ allow(@http).to receive(:request)
745
+ allow(@request).to receive(:process_result)
746
+ allow(@request).to receive(:response_log)
747
+
748
+ expect(@net).to receive(:open_timeout=).with(123)
749
+ expect(@net).to receive(:read_timeout=).with(123)
750
+
751
+ @request.send(:transmit, @uri, 'req', nil)
752
+ end
753
+
754
+ it 'supersedes :timeout with open/read_timeout' do
755
+ @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :timeout => 123, :open_timeout => 34, :read_timeout => 56)
756
+ allow(@http).to receive(:request)
757
+ allow(@request).to receive(:process_result)
758
+ allow(@request).to receive(:response_log)
759
+
760
+ expect(@net).to receive(:open_timeout=).with(34)
761
+ expect(@net).to receive(:read_timeout=).with(56)
762
+
763
+ @request.send(:transmit, @uri, 'req', nil)
764
+ end
765
+
766
+
767
+ it "disable timeout by setting it to nil" do
768
+ @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :read_timeout => nil, :open_timeout => nil)
769
+ allow(@http).to receive(:request)
770
+ allow(@request).to receive(:process_result)
771
+ allow(@request).to receive(:response_log)
772
+
773
+ expect(@net).to receive(:read_timeout=).with(nil)
774
+ expect(@net).to receive(:open_timeout=).with(nil)
775
+
776
+ @request.send(:transmit, @uri, 'req', nil)
777
+ end
778
+
779
+ it 'deprecated: warns when disabling timeout by setting it to -1' do
780
+ @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :read_timeout => -1)
781
+ allow(@http).to receive(:request)
782
+ allow(@request).to receive(:process_result)
783
+ allow(@request).to receive(:response_log)
784
+
785
+ expect(@net).to receive(:read_timeout=).with(nil)
786
+
787
+ expect(fake_stderr {
788
+ @request.send(:transmit, @uri, 'req', nil)
789
+ }).to match(/^Deprecated: .*timeout.* nil instead of -1$/)
790
+ end
791
+
792
+ it "deprecated: disable timeout by setting it to -1" do
793
+ @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :read_timeout => -1, :open_timeout => -1)
794
+ allow(@http).to receive(:request)
795
+ allow(@request).to receive(:process_result)
796
+ allow(@request).to receive(:response_log)
797
+
798
+ expect(@request).to receive(:warn)
799
+ expect(@net).to receive(:read_timeout=).with(nil)
800
+
801
+ expect(@request).to receive(:warn)
802
+ expect(@net).to receive(:open_timeout=).with(nil)
803
+
804
+ @request.send(:transmit, @uri, 'req', nil)
805
+ end
806
+ end
807
+
808
+ describe "ssl" do
809
+ it "uses SSL when the URI refers to a https address" do
810
+ allow(@uri).to receive(:is_a?).with(URI::HTTPS).and_return(true)
811
+ expect(@net).to receive(:use_ssl=).with(true)
812
+ allow(@http).to receive(:request)
813
+ allow(@request).to receive(:process_result)
814
+ allow(@request).to receive(:response_log)
815
+ @request.send(:transmit, @uri, 'req', 'payload')
816
+ end
817
+
818
+ it "should default to verifying ssl certificates" do
819
+ expect(@request.verify_ssl).to eq OpenSSL::SSL::VERIFY_PEER
820
+ end
821
+
822
+ it "should have expected values for VERIFY_PEER and VERIFY_NONE" do
823
+ expect(OpenSSL::SSL::VERIFY_NONE).to eq(0)
824
+ expect(OpenSSL::SSL::VERIFY_PEER).to eq(1)
825
+ end
826
+
827
+ it "should set net.verify_mode to OpenSSL::SSL::VERIFY_NONE if verify_ssl is false" do
828
+ @request = RestClient::Request.new(:method => :put, :verify_ssl => false, :url => 'http://some/resource', :payload => 'payload')
829
+ expect(@net).to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
830
+ allow(@http).to receive(:request)
831
+ allow(@request).to receive(:process_result)
832
+ allow(@request).to receive(:response_log)
833
+ @request.send(:transmit, @uri, 'req', 'payload')
834
+ end
835
+
836
+ it "should not set net.verify_mode to OpenSSL::SSL::VERIFY_NONE if verify_ssl is true" do
837
+ @request = RestClient::Request.new(:method => :put, :url => 'https://some/resource', :payload => 'payload', :verify_ssl => true)
838
+ expect(@net).not_to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
839
+ allow(@http).to receive(:request)
840
+ allow(@request).to receive(:process_result)
841
+ allow(@request).to receive(:response_log)
842
+ @request.send(:transmit, @uri, 'req', 'payload')
843
+ end
844
+
845
+ it "should set net.verify_mode to OpenSSL::SSL::VERIFY_PEER if verify_ssl is true" do
846
+ @request = RestClient::Request.new(:method => :put, :url => 'https://some/resource', :payload => 'payload', :verify_ssl => true)
847
+ expect(@net).to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER)
848
+ allow(@http).to receive(:request)
849
+ allow(@request).to receive(:process_result)
850
+ allow(@request).to receive(:response_log)
851
+ @request.send(:transmit, @uri, 'req', 'payload')
852
+ end
853
+
854
+ it "should set net.verify_mode to OpenSSL::SSL::VERIFY_PEER if verify_ssl is not given" do
855
+ @request = RestClient::Request.new(:method => :put, :url => 'https://some/resource', :payload => 'payload')
856
+ expect(@net).to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER)
857
+ allow(@http).to receive(:request)
858
+ allow(@request).to receive(:process_result)
859
+ allow(@request).to receive(:response_log)
860
+ @request.send(:transmit, @uri, 'req', 'payload')
861
+ end
862
+
863
+ it "should set net.verify_mode to the passed value if verify_ssl is an OpenSSL constant" do
864
+ mode = OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
865
+ @request = RestClient::Request.new( :method => :put,
866
+ :url => 'https://some/resource',
867
+ :payload => 'payload',
868
+ :verify_ssl => mode )
869
+ expect(@net).to receive(:verify_mode=).with(mode)
870
+ allow(@http).to receive(:request)
871
+ allow(@request).to receive(:process_result)
872
+ allow(@request).to receive(:response_log)
873
+ @request.send(:transmit, @uri, 'req', 'payload')
874
+ end
875
+
876
+ it "should default to not having an ssl_client_cert" do
877
+ expect(@request.ssl_client_cert).to be(nil)
878
+ end
879
+
880
+ it "should set the ssl_version if provided" do
881
+ @request = RestClient::Request.new(
882
+ :method => :put,
883
+ :url => 'https://some/resource',
884
+ :payload => 'payload',
885
+ :ssl_version => "TLSv1"
886
+ )
887
+ expect(@net).to receive(:ssl_version=).with("TLSv1")
888
+ allow(@http).to receive(:request)
889
+ allow(@request).to receive(:process_result)
890
+ allow(@request).to receive(:response_log)
891
+ @request.send(:transmit, @uri, 'req', 'payload')
892
+ end
893
+
894
+ it "should not set the ssl_version if not provided" do
895
+ @request = RestClient::Request.new(
896
+ :method => :put,
897
+ :url => 'https://some/resource',
898
+ :payload => 'payload'
899
+ )
900
+ expect(@net).not_to receive(:ssl_version=).with("TLSv1")
901
+ allow(@http).to receive(:request)
902
+ allow(@request).to receive(:process_result)
903
+ allow(@request).to receive(:response_log)
904
+ @request.send(:transmit, @uri, 'req', 'payload')
905
+ end
906
+
907
+ it "should set the ssl_ciphers if provided" do
908
+ ciphers = 'AESGCM:HIGH:!aNULL:!eNULL:RC4+RSA'
909
+ @request = RestClient::Request.new(
910
+ :method => :put,
911
+ :url => 'https://some/resource',
912
+ :payload => 'payload',
913
+ :ssl_ciphers => ciphers
914
+ )
915
+ expect(@net).to receive(:ciphers=).with(ciphers)
916
+ allow(@http).to receive(:request)
917
+ allow(@request).to receive(:process_result)
918
+ allow(@request).to receive(:response_log)
919
+ @request.send(:transmit, @uri, 'req', 'payload')
920
+ end
921
+
922
+ it "should not set the ssl_ciphers if set to nil" do
923
+ @request = RestClient::Request.new(
924
+ :method => :put,
925
+ :url => 'https://some/resource',
926
+ :payload => 'payload',
927
+ :ssl_ciphers => nil,
928
+ )
929
+ expect(@net).not_to receive(:ciphers=)
930
+ allow(@http).to receive(:request)
931
+ allow(@request).to receive(:process_result)
932
+ allow(@request).to receive(:response_log)
933
+ @request.send(:transmit, @uri, 'req', 'payload')
934
+ end
935
+
936
+ it "should set the ssl_client_cert if provided" do
937
+ @request = RestClient::Request.new(
938
+ :method => :put,
939
+ :url => 'https://some/resource',
940
+ :payload => 'payload',
941
+ :ssl_client_cert => "whatsupdoc!"
942
+ )
943
+ expect(@net).to receive(:cert=).with("whatsupdoc!")
944
+ allow(@http).to receive(:request)
945
+ allow(@request).to receive(:process_result)
946
+ allow(@request).to receive(:response_log)
947
+ @request.send(:transmit, @uri, 'req', 'payload')
948
+ end
949
+
950
+ it "should not set the ssl_client_cert if it is not provided" do
951
+ @request = RestClient::Request.new(
952
+ :method => :put,
953
+ :url => 'https://some/resource',
954
+ :payload => 'payload'
955
+ )
956
+ expect(@net).not_to receive(:cert=)
957
+ allow(@http).to receive(:request)
958
+ allow(@request).to receive(:process_result)
959
+ allow(@request).to receive(:response_log)
960
+ @request.send(:transmit, @uri, 'req', 'payload')
961
+ end
962
+
963
+ it "should default to not having an ssl_client_key" do
964
+ expect(@request.ssl_client_key).to be(nil)
965
+ end
966
+
967
+ it "should set the ssl_client_key if provided" do
968
+ @request = RestClient::Request.new(
969
+ :method => :put,
970
+ :url => 'https://some/resource',
971
+ :payload => 'payload',
972
+ :ssl_client_key => "whatsupdoc!"
973
+ )
974
+ expect(@net).to receive(:key=).with("whatsupdoc!")
975
+ allow(@http).to receive(:request)
976
+ allow(@request).to receive(:process_result)
977
+ allow(@request).to receive(:response_log)
978
+ @request.send(:transmit, @uri, 'req', 'payload')
979
+ end
980
+
981
+ it "should not set the ssl_client_key if it is not provided" do
982
+ @request = RestClient::Request.new(
983
+ :method => :put,
984
+ :url => 'https://some/resource',
985
+ :payload => 'payload'
986
+ )
987
+ expect(@net).not_to receive(:key=)
988
+ allow(@http).to receive(:request)
989
+ allow(@request).to receive(:process_result)
990
+ allow(@request).to receive(:response_log)
991
+ @request.send(:transmit, @uri, 'req', 'payload')
992
+ end
993
+
994
+ it "should default to not having an ssl_ca_file" do
995
+ expect(@request.ssl_ca_file).to be(nil)
996
+ end
997
+
998
+ it "should set the ssl_ca_file if provided" do
999
+ @request = RestClient::Request.new(
1000
+ :method => :put,
1001
+ :url => 'https://some/resource',
1002
+ :payload => 'payload',
1003
+ :ssl_ca_file => "Certificate Authority File"
1004
+ )
1005
+ expect(@net).to receive(:ca_file=).with("Certificate Authority File")
1006
+ expect(@net).not_to receive(:cert_store=)
1007
+ allow(@http).to receive(:request)
1008
+ allow(@request).to receive(:process_result)
1009
+ allow(@request).to receive(:response_log)
1010
+ @request.send(:transmit, @uri, 'req', 'payload')
1011
+ end
1012
+
1013
+ it "should not set the ssl_ca_file if it is not provided" do
1014
+ @request = RestClient::Request.new(
1015
+ :method => :put,
1016
+ :url => 'https://some/resource',
1017
+ :payload => 'payload'
1018
+ )
1019
+ expect(@net).not_to receive(:ca_file=)
1020
+ allow(@http).to receive(:request)
1021
+ allow(@request).to receive(:process_result)
1022
+ allow(@request).to receive(:response_log)
1023
+ @request.send(:transmit, @uri, 'req', 'payload')
1024
+ end
1025
+
1026
+ it "should default to not having an ssl_ca_path" do
1027
+ expect(@request.ssl_ca_path).to be(nil)
1028
+ end
1029
+
1030
+ it "should set the ssl_ca_path if provided" do
1031
+ @request = RestClient::Request.new(
1032
+ :method => :put,
1033
+ :url => 'https://some/resource',
1034
+ :payload => 'payload',
1035
+ :ssl_ca_path => "Certificate Authority Path"
1036
+ )
1037
+ expect(@net).to receive(:ca_path=).with("Certificate Authority Path")
1038
+ expect(@net).not_to receive(:cert_store=)
1039
+ allow(@http).to receive(:request)
1040
+ allow(@request).to receive(:process_result)
1041
+ allow(@request).to receive(:response_log)
1042
+ @request.send(:transmit, @uri, 'req', 'payload')
1043
+ end
1044
+
1045
+ it "should not set the ssl_ca_path if it is not provided" do
1046
+ @request = RestClient::Request.new(
1047
+ :method => :put,
1048
+ :url => 'https://some/resource',
1049
+ :payload => 'payload'
1050
+ )
1051
+ expect(@net).not_to receive(:ca_path=)
1052
+ allow(@http).to receive(:request)
1053
+ allow(@request).to receive(:process_result)
1054
+ allow(@request).to receive(:response_log)
1055
+ @request.send(:transmit, @uri, 'req', 'payload')
1056
+ end
1057
+
1058
+ it "should set the ssl_cert_store if provided" do
1059
+ store = OpenSSL::X509::Store.new
1060
+ store.set_default_paths
1061
+
1062
+ @request = RestClient::Request.new(
1063
+ :method => :put,
1064
+ :url => 'https://some/resource',
1065
+ :payload => 'payload',
1066
+ :ssl_cert_store => store
1067
+ )
1068
+ expect(@net).to receive(:cert_store=).with(store)
1069
+ expect(@net).not_to receive(:ca_path=)
1070
+ expect(@net).not_to receive(:ca_file=)
1071
+ allow(@http).to receive(:request)
1072
+ allow(@request).to receive(:process_result)
1073
+ allow(@request).to receive(:response_log)
1074
+ @request.send(:transmit, @uri, 'req', 'payload')
1075
+ end
1076
+
1077
+ it "should by default set the ssl_cert_store if no CA info is provided" do
1078
+ @request = RestClient::Request.new(
1079
+ :method => :put,
1080
+ :url => 'https://some/resource',
1081
+ :payload => 'payload'
1082
+ )
1083
+ expect(@net).to receive(:cert_store=)
1084
+ expect(@net).not_to receive(:ca_path=)
1085
+ expect(@net).not_to receive(:ca_file=)
1086
+ allow(@http).to receive(:request)
1087
+ allow(@request).to receive(:process_result)
1088
+ allow(@request).to receive(:response_log)
1089
+ @request.send(:transmit, @uri, 'req', 'payload')
1090
+ end
1091
+
1092
+ it "should not set the ssl_cert_store if it is set falsy" do
1093
+ @request = RestClient::Request.new(
1094
+ :method => :put,
1095
+ :url => 'https://some/resource',
1096
+ :payload => 'payload',
1097
+ :ssl_cert_store => nil,
1098
+ )
1099
+ expect(@net).not_to receive(:cert_store=)
1100
+ allow(@http).to receive(:request)
1101
+ allow(@request).to receive(:process_result)
1102
+ allow(@request).to receive(:response_log)
1103
+ @request.send(:transmit, @uri, 'req', 'payload')
1104
+ end
1105
+
1106
+ it "should not set the ssl_verify_callback by default" do
1107
+ @request = RestClient::Request.new(
1108
+ :method => :put,
1109
+ :url => 'https://some/resource',
1110
+ :payload => 'payload',
1111
+ )
1112
+ expect(@net).not_to receive(:verify_callback=)
1113
+ allow(@http).to receive(:request)
1114
+ allow(@request).to receive(:process_result)
1115
+ allow(@request).to receive(:response_log)
1116
+ @request.send(:transmit, @uri, 'req', 'payload')
1117
+ end
1118
+
1119
+ it "should set the ssl_verify_callback if passed" do
1120
+ callback = lambda {}
1121
+ @request = RestClient::Request.new(
1122
+ :method => :put,
1123
+ :url => 'https://some/resource',
1124
+ :payload => 'payload',
1125
+ :ssl_verify_callback => callback,
1126
+ )
1127
+ expect(@net).to receive(:verify_callback=).with(callback)
1128
+
1129
+ # we'll read cert_store on jruby
1130
+ # https://github.com/jruby/jruby/issues/597
1131
+ if RestClient::Platform.jruby?
1132
+ allow(@net).to receive(:cert_store)
1133
+ end
1134
+
1135
+ allow(@http).to receive(:request)
1136
+ allow(@request).to receive(:process_result)
1137
+ allow(@request).to receive(:response_log)
1138
+ @request.send(:transmit, @uri, 'req', 'payload')
1139
+ end
1140
+
1141
+ # </ssl>
1142
+ end
1143
+
1144
+ it "should still return a response object for 204 No Content responses" do
1145
+ @request = RestClient::Request.new(
1146
+ :method => :put,
1147
+ :url => 'https://some/resource',
1148
+ :payload => 'payload'
1149
+ )
1150
+ net_http_res = Net::HTTPNoContent.new("", "204", "No Content")
1151
+ allow(net_http_res).to receive(:read_body).and_return(nil)
1152
+ expect(@http).to receive(:request).and_return(@request.send(:fetch_body, net_http_res))
1153
+ response = @request.send(:transmit, @uri, 'req', 'payload')
1154
+ expect(response).not_to be_nil
1155
+ expect(response.code).to eq 204
1156
+ end
1157
+
1158
+ describe "raw response" do
1159
+ it "should read the response into a binary-mode tempfile" do
1160
+ @request = RestClient::Request.new(:method => "get", :url => "example.com", :raw_response => true)
1161
+
1162
+ tempfile = double("tempfile")
1163
+ expect(tempfile).to receive(:binmode)
1164
+ allow(tempfile).to receive(:open)
1165
+ allow(tempfile).to receive(:close)
1166
+ expect(Tempfile).to receive(:new).with("rest-client.").and_return(tempfile)
1167
+
1168
+ net_http_res = Net::HTTPOK.new(nil, "200", "body")
1169
+ allow(net_http_res).to receive(:read_body).and_return("body")
1170
+ @request.send(:fetch_body, net_http_res)
1171
+ end
1172
+ end
1173
+
1174
+ describe 'payloads' do
1175
+ it 'should accept string payloads' do
1176
+ payload = 'Foo'
1177
+ @request = RestClient::Request.new(method: :get, url: 'example.com', :payload => payload)
1178
+ expect(@request).to receive(:process_result)
1179
+ expect(@http).to receive(:request).with('req', payload)
1180
+ @request.send(:transmit, @uri, 'req', payload)
1181
+ end
1182
+
1183
+ it 'should accept streaming IO payloads' do
1184
+ payload = StringIO.new('streamed')
1185
+
1186
+ @request = RestClient::Request.new(method: :get, url: 'example.com', :payload => payload)
1187
+ expect(@request).to receive(:process_result)
1188
+
1189
+ @get = double('net::http::get')
1190
+ expect(@get).to receive(:body_stream=).with(instance_of(RestClient::Payload::Streamed))
1191
+
1192
+ allow(@request.net_http_request_class(:GET)).to receive(:new).and_return(@get)
1193
+ expect(@http).to receive(:request).with(@get, nil)
1194
+ @request.execute
1195
+ end
1196
+ end
1197
+
1198
+ describe 'constructor' do
1199
+ it 'should reject valid URIs with no hostname' do
1200
+ expect(URI.parse('http:///').hostname).to be_nil
1201
+
1202
+ expect {
1203
+ RestClient::Request.new(method: :get, url: 'http:///')
1204
+ }.to raise_error(URI::InvalidURIError, /\Abad URI/)
1205
+ end
1206
+
1207
+ it 'should reject invalid URIs' do
1208
+ expect {
1209
+ RestClient::Request.new(method: :get, url: 'http://::')
1210
+ }.to raise_error(URI::InvalidURIError)
1211
+ end
1212
+ end
1213
+
1214
+ describe 'process_url_params' do
1215
+ it 'should handle basic URL params' do
1216
+ expect(@request.process_url_params('https://example.com/foo', params: {key1: 123, key2: 'abc'})).
1217
+ to eq 'https://example.com/foo?key1=123&key2=abc'
1218
+
1219
+ expect(@request.process_url_params('https://example.com/foo', params: {'key1' => 123})).
1220
+ to eq 'https://example.com/foo?key1=123'
1221
+
1222
+ expect(@request.process_url_params('https://example.com/path',
1223
+ params: {foo: 'one two', bar: 'three + four == seven'})).
1224
+ to eq 'https://example.com/path?foo=one+two&bar=three+%2B+four+%3D%3D+seven'
1225
+ end
1226
+
1227
+ it 'should combine with & when URL params already exist' do
1228
+ expect(@request.process_url_params('https://example.com/path?foo=1', params: {bar: 2})).
1229
+ to eq 'https://example.com/path?foo=1&bar=2'
1230
+ end
1231
+
1232
+ it 'should handle complex nested URL params per Rack / Rails conventions' do
1233
+ expect(@request.process_url_params('https://example.com/', params: {
1234
+ foo: [1,2,3],
1235
+ null: nil,
1236
+ false: false,
1237
+ math: '2+2=4',
1238
+ nested: {'key + escaped' => 'value + escaped', other: [], arr: [1,2]},
1239
+ })).to eq 'https://example.com/?foo[]=1&foo[]=2&foo[]=3&null&false=false&math=2%2B2%3D4' \
1240
+ '&nested[key+%2B+escaped]=value+%2B+escaped&nested[other]' \
1241
+ '&nested[arr][]=1&nested[arr][]=2'
1242
+ end
1243
+
1244
+ it 'should handle ParamsArray objects' do
1245
+ expect(@request.process_url_params('https://example.com/',
1246
+ params: RestClient::ParamsArray.new([[:foo, 1], [:foo, 2]])
1247
+ )).to eq 'https://example.com/?foo=1&foo=2'
1248
+ end
1249
+ end
1250
+ end