alinta-rest-client 2.2.0-x64-mingw32

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