rest-client 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.rspec +2 -0
  4. data/.rubocop-disables.yml +384 -0
  5. data/.rubocop.yml +3 -0
  6. data/.travis.yml +48 -0
  7. data/AUTHORS +98 -0
  8. data/Gemfile +11 -0
  9. data/LICENSE +21 -0
  10. data/README.md +784 -0
  11. data/Rakefile +132 -0
  12. data/bin/restclient +92 -0
  13. data/history.md +324 -0
  14. data/lib/rest-client.rb +2 -0
  15. data/lib/rest_client.rb +2 -0
  16. data/lib/restclient.rb +184 -0
  17. data/lib/restclient/abstract_response.rb +226 -0
  18. data/lib/restclient/exceptions.rb +244 -0
  19. data/lib/restclient/params_array.rb +72 -0
  20. data/lib/restclient/payload.rb +209 -0
  21. data/lib/restclient/platform.rb +49 -0
  22. data/lib/restclient/raw_response.rb +38 -0
  23. data/lib/restclient/request.rb +853 -0
  24. data/lib/restclient/resource.rb +168 -0
  25. data/lib/restclient/response.rb +80 -0
  26. data/lib/restclient/utils.rb +235 -0
  27. data/lib/restclient/version.rb +8 -0
  28. data/lib/restclient/windows.rb +8 -0
  29. data/lib/restclient/windows/root_certs.rb +105 -0
  30. data/rest-client.gemspec +31 -0
  31. data/rest-client.windows.gemspec +19 -0
  32. data/spec/helpers.rb +22 -0
  33. data/spec/integration/_lib.rb +1 -0
  34. data/spec/integration/capath_digicert/244b5494.0 +19 -0
  35. data/spec/integration/capath_digicert/81b9768f.0 +19 -0
  36. data/spec/integration/capath_digicert/README +8 -0
  37. data/spec/integration/capath_digicert/digicert.crt +19 -0
  38. data/spec/integration/capath_verisign/415660c1.0 +14 -0
  39. data/spec/integration/capath_verisign/7651b327.0 +14 -0
  40. data/spec/integration/capath_verisign/README +8 -0
  41. data/spec/integration/capath_verisign/verisign.crt +14 -0
  42. data/spec/integration/certs/digicert.crt +19 -0
  43. data/spec/integration/certs/verisign.crt +14 -0
  44. data/spec/integration/httpbin_spec.rb +87 -0
  45. data/spec/integration/integration_spec.rb +125 -0
  46. data/spec/integration/request_spec.rb +127 -0
  47. data/spec/spec_helper.rb +29 -0
  48. data/spec/unit/_lib.rb +1 -0
  49. data/spec/unit/abstract_response_spec.rb +145 -0
  50. data/spec/unit/exceptions_spec.rb +108 -0
  51. data/spec/unit/master_shake.jpg +0 -0
  52. data/spec/unit/params_array_spec.rb +36 -0
  53. data/spec/unit/payload_spec.rb +263 -0
  54. data/spec/unit/raw_response_spec.rb +18 -0
  55. data/spec/unit/request2_spec.rb +54 -0
  56. data/spec/unit/request_spec.rb +1250 -0
  57. data/spec/unit/resource_spec.rb +134 -0
  58. data/spec/unit/response_spec.rb +241 -0
  59. data/spec/unit/restclient_spec.rb +79 -0
  60. data/spec/unit/utils_spec.rb +147 -0
  61. data/spec/unit/windows/root_certs_spec.rb +22 -0
  62. metadata +282 -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,263 @@
1
+ # encoding: binary
2
+
3
+ require_relative '_lib'
4
+
5
+ describe RestClient::Payload 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(File.join(File.dirname(File.expand_path(__FILE__)), 'master_shake.jpg')))
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(File.dirname(__FILE__) + "/master_shake.jpg")
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="master_shake.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(File.dirname(__FILE__) + "/master_shake.jpg")
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="master_shake.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(File.dirname(__FILE__) + "/master_shake.jpg")
141
+ f.instance_eval "def content_type; 'text/plain'; end"
142
+ f.instance_eval "def original_filename; 'foo.txt'; end"
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(File.dirname(__FILE__) + "/master_shake.jpg")
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(File.dirname(__FILE__) + '/master_shake.jpg')
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(File.dirname(__FILE__) + "/master_shake.jpg")
190
+ payload = RestClient::Payload.generate(f)
191
+ expect(payload.size).to eq 76_988
192
+ expect(payload.length).to eq 76_988
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
+ end
213
+
214
+ context "Payload generation" do
215
+ it "should recognize standard urlencoded params" do
216
+ expect(RestClient::Payload.generate({"foo" => 'bar'})).to be_kind_of(RestClient::Payload::UrlEncoded)
217
+ end
218
+
219
+ it "should recognize multipart params" do
220
+ f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
221
+ expect(RestClient::Payload.generate({"foo" => f})).to be_kind_of(RestClient::Payload::Multipart)
222
+ end
223
+
224
+ it "should be multipart if forced" do
225
+ expect(RestClient::Payload.generate({"foo" => "bar", :multipart => true})).to be_kind_of(RestClient::Payload::Multipart)
226
+ end
227
+
228
+ it "should handle deeply nested multipart" do
229
+ f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
230
+ params = {foo: RestClient::ParamsArray.new({nested: f})}
231
+ expect(RestClient::Payload.generate(params)).to be_kind_of(RestClient::Payload::Multipart)
232
+ end
233
+
234
+
235
+ it "should return data if no of the above" do
236
+ expect(RestClient::Payload.generate("data")).to be_kind_of(RestClient::Payload::Base)
237
+ end
238
+
239
+ it "should recognize nested multipart payloads in hashes" do
240
+ f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
241
+ expect(RestClient::Payload.generate({"foo" => {"file" => f}})).to be_kind_of(RestClient::Payload::Multipart)
242
+ end
243
+
244
+ it "should recognize nested multipart payloads in arrays" do
245
+ f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
246
+ expect(RestClient::Payload.generate({"foo" => [f]})).to be_kind_of(RestClient::Payload::Multipart)
247
+ end
248
+
249
+ it "should recognize file payloads that can be streamed" do
250
+ f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
251
+ expect(RestClient::Payload.generate(f)).to be_kind_of(RestClient::Payload::Streamed)
252
+ end
253
+
254
+ it "should recognize other payloads that can be streamed" do
255
+ expect(RestClient::Payload.generate(StringIO.new('foo'))).to be_kind_of(RestClient::Payload::Streamed)
256
+ end
257
+
258
+ # hashery gem introduces Hash#read convenience method. Existence of #read method used to determine of content is streameable :/
259
+ it "shouldn't treat hashes as streameable" do
260
+ expect(RestClient::Payload.generate({"foo" => 'bar'})).to be_kind_of(RestClient::Payload::UrlEncoded)
261
+ end
262
+ end
263
+ end
@@ -0,0 +1,18 @@
1
+ require_relative '_lib'
2
+
3
+ describe RestClient::RawResponse do
4
+ before do
5
+ @tf = double("Tempfile", :read => "the answer is 42", :open => true)
6
+ @net_http_res = double('net http response')
7
+ @request = double('http request')
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
+ 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