rest-client 1.7.0.rc1-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rest-client might be problematic. Click here for more details.

Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +14 -0
  5. data/AUTHORS +81 -0
  6. data/Gemfile +11 -0
  7. data/LICENSE +21 -0
  8. data/README.rdoc +325 -0
  9. data/Rakefile +117 -0
  10. data/bin/restclient +93 -0
  11. data/history.md +166 -0
  12. data/lib/rest-client.rb +2 -0
  13. data/lib/rest_client.rb +2 -0
  14. data/lib/restclient.rb +164 -0
  15. data/lib/restclient/abstract_response.rb +106 -0
  16. data/lib/restclient/exceptions.rb +203 -0
  17. data/lib/restclient/payload.rb +240 -0
  18. data/lib/restclient/platform.rb +30 -0
  19. data/lib/restclient/raw_response.rb +34 -0
  20. data/lib/restclient/request.rb +582 -0
  21. data/lib/restclient/resource.rb +169 -0
  22. data/lib/restclient/response.rb +24 -0
  23. data/lib/restclient/version.rb +7 -0
  24. data/lib/restclient/windows.rb +8 -0
  25. data/lib/restclient/windows/root_certs.rb +105 -0
  26. data/rest-client.gemspec +30 -0
  27. data/rest-client.windows.gemspec +19 -0
  28. data/spec/integration/capath_digicert/244b5494.0 +19 -0
  29. data/spec/integration/capath_digicert/81b9768f.0 +19 -0
  30. data/spec/integration/capath_digicert/README +8 -0
  31. data/spec/integration/capath_digicert/digicert.crt +19 -0
  32. data/spec/integration/capath_verisign/415660c1.0 +14 -0
  33. data/spec/integration/capath_verisign/7651b327.0 +14 -0
  34. data/spec/integration/capath_verisign/README +8 -0
  35. data/spec/integration/capath_verisign/verisign.crt +14 -0
  36. data/spec/integration/certs/digicert.crt +19 -0
  37. data/spec/integration/certs/verisign.crt +14 -0
  38. data/spec/integration/integration_spec.rb +35 -0
  39. data/spec/integration/request_spec.rb +104 -0
  40. data/spec/spec_helper.rb +12 -0
  41. data/spec/unit/abstract_response_spec.rb +85 -0
  42. data/spec/unit/exceptions_spec.rb +95 -0
  43. data/spec/unit/master_shake.jpg +0 -0
  44. data/spec/unit/payload_spec.rb +245 -0
  45. data/spec/unit/raw_response_spec.rb +17 -0
  46. data/spec/unit/request2_spec.rb +32 -0
  47. data/spec/unit/request_spec.rb +905 -0
  48. data/spec/unit/resource_spec.rb +133 -0
  49. data/spec/unit/response_spec.rb +166 -0
  50. data/spec/unit/restclient_spec.rb +79 -0
  51. data/spec/unit/windows/root_certs_spec.rb +22 -0
  52. metadata +241 -0
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
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
+ @response = RestClient::RawResponse.new(@tf, @net_http_res, {})
8
+ end
9
+
10
+ it "behaves like string" do
11
+ @response.to_s.should eq 'the answer is 42'
12
+ end
13
+
14
+ it "exposes a Tempfile" do
15
+ @response.file.should eq @tf
16
+ end
17
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe RestClient::Request do
4
+
5
+ it "manage params for get requests" do
6
+ stub_request(:get, 'http://some/resource?a=b&c=d').with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate', 'Foo'=>'bar'}).to_return(:body => 'foo', :status => 200)
7
+ RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :headers => {:foo => :bar, :params => {:a => :b, 'c' => 'd'}}).body.should eq 'foo'
8
+
9
+ stub_request(:get, 'http://some/resource').with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate', 'Foo'=>'bar', 'params' => 'a'}).to_return(:body => 'foo', :status => 200)
10
+ RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :headers => {:foo => :bar, :params => :a}).body.should eq 'foo'
11
+ end
12
+
13
+ it "can use a block to process response" do
14
+ response_value = nil
15
+ block = Proc.new do |http_response|
16
+ response_value = http_response.body
17
+ end
18
+ stub_request(:get, 'http://some/resource?a=b&c=d').with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate', 'Foo'=>'bar'}).to_return(:body => 'foo', :status => 200)
19
+ RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :headers => {:foo => :bar, :params => {:a => :b, 'c' => 'd'}}, :block_response => block)
20
+ response_value.should eq "foo"
21
+ end
22
+
23
+ it 'closes payload if not nil' do
24
+ test_file = File.new(File.join( File.dirname(File.expand_path(__FILE__)), 'master_shake.jpg'))
25
+
26
+ stub_request(:post, 'http://some/resource').with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate'}).to_return(:body => 'foo', :status => 200)
27
+ RestClient::Request.execute(:url => 'http://some/resource', :method => :post, :payload => {:file => test_file})
28
+
29
+ test_file.closed?.should be_true
30
+ end
31
+
32
+ end
@@ -0,0 +1,905 @@
1
+ require 'spec_helper'
2
+
3
+ describe RestClient::Request do
4
+ before do
5
+ @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload')
6
+
7
+ @uri = double("uri")
8
+ @uri.stub(:request_uri).and_return('/resource')
9
+ @uri.stub(:host).and_return('some')
10
+ @uri.stub(:port).and_return(80)
11
+
12
+ @net = double("net::http base")
13
+ @http = double("net::http connection")
14
+ Net::HTTP.stub(:new).and_return(@net)
15
+ @net.stub(:start).and_yield(@http)
16
+ @net.stub(:use_ssl=)
17
+ @net.stub(:verify_mode=)
18
+ @net.stub(:verify_callback=)
19
+ allow(@net).to receive(:ciphers=)
20
+ allow(@net).to receive(:cert_store=)
21
+ RestClient.log = nil
22
+ end
23
+
24
+ it "accept */* mimetype, preferring xml" do
25
+ @request.default_headers[:accept].should eq '*/*; q=0.5, application/xml'
26
+ end
27
+
28
+ describe "compression" do
29
+
30
+ it "decodes an uncompressed result body by passing it straight through" do
31
+ RestClient::Request.decode(nil, 'xyz').should eq 'xyz'
32
+ end
33
+
34
+ it "doesn't fail for nil bodies" do
35
+ RestClient::Request.decode('gzip', nil).should be_nil
36
+ end
37
+
38
+
39
+ it "decodes a gzip body" do
40
+ 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").should eq "i'm gziped\n"
41
+ end
42
+
43
+ it "ingores gzip for empty bodies" do
44
+ RestClient::Request.decode('gzip', '').should be_empty
45
+ end
46
+
47
+ it "decodes a deflated body" do
48
+ RestClient::Request.decode('deflate', "x\234+\316\317MUHIM\313I,IMQ(I\255(\001\000A\223\006\363").should eq "some deflated text"
49
+ end
50
+ end
51
+
52
+ it "processes a successful result" do
53
+ res = double("result")
54
+ res.stub(:code).and_return("200")
55
+ res.stub(:body).and_return('body')
56
+ res.stub(:[]).with('content-encoding').and_return(nil)
57
+ @request.process_result(res).body.should eq 'body'
58
+ @request.process_result(res).to_s.should eq 'body'
59
+ end
60
+
61
+ it "doesn't classify successful requests as failed" do
62
+ 203.upto(207) do |code|
63
+ res = double("result")
64
+ res.stub(:code).and_return(code.to_s)
65
+ res.stub(:body).and_return("")
66
+ res.stub(:[]).with('content-encoding').and_return(nil)
67
+ @request.process_result(res).should be_empty
68
+ end
69
+ end
70
+
71
+ it "parses a url into a URI object" do
72
+ URI.should_receive(:parse).with('http://example.com/resource')
73
+ @request.parse_url('http://example.com/resource')
74
+ end
75
+
76
+ it "adds http:// to the front of resources specified in the syntax example.com/resource" do
77
+ URI.should_receive(:parse).with('http://example.com/resource')
78
+ @request.parse_url('example.com/resource')
79
+ end
80
+
81
+ describe "user - password" do
82
+ it "extracts the username and password when parsing http://user:password@example.com/" do
83
+ URI.stub(:parse).and_return(double('uri', :user => 'joe', :password => 'pass1'))
84
+ @request.parse_url_with_auth('http://joe:pass1@example.com/resource')
85
+ @request.user.should eq 'joe'
86
+ @request.password.should eq 'pass1'
87
+ end
88
+
89
+ it "extracts with escaping the username and password when parsing http://user:password@example.com/" do
90
+ URI.stub(:parse).and_return(double('uri', :user => 'joe%20', :password => 'pass1'))
91
+ @request.parse_url_with_auth('http://joe%20:pass1@example.com/resource')
92
+ @request.user.should eq 'joe '
93
+ @request.password.should eq 'pass1'
94
+ end
95
+
96
+ 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
97
+ URI.stub(:parse).and_return(double('uri', :user => nil, :password => nil))
98
+ @request = RestClient::Request.new(:method => 'get', :url => 'example.com', :user => 'beth', :password => 'pass2')
99
+ @request.parse_url_with_auth('http://example.com/resource')
100
+ @request.user.should eq 'beth'
101
+ @request.password.should eq 'pass2'
102
+ end
103
+ end
104
+
105
+ it "correctly formats cookies provided to the constructor" do
106
+ URI.stub(:parse).and_return(double('uri', :user => nil, :password => nil))
107
+ @request = RestClient::Request.new(:method => 'get', :url => 'example.com', :cookies => {:session_id => '1', :user_id => "someone" })
108
+ @request.should_receive(:default_headers).and_return({'Foo' => 'bar'})
109
+ @request.make_headers({}).should eq({ 'Foo' => 'bar', 'Cookie' => 'session_id=1; user_id=someone'})
110
+ end
111
+
112
+ it "does not escape or unescape cookies" do
113
+ cookie = 'Foo%20:Bar%0A~'
114
+ @request = RestClient::Request.new(:method => 'get', :url => 'example.com',
115
+ :cookies => {:test => cookie})
116
+ @request.should_receive(:default_headers).and_return({'Foo' => 'bar'})
117
+ @request.make_headers({}).should eq({
118
+ 'Foo' => 'bar',
119
+ 'Cookie' => "test=#{cookie}"
120
+ })
121
+ end
122
+
123
+ it "rejects cookie names containing invalid characters" do
124
+ # Cookie validity is something of a mess, but we should reject the worst of
125
+ # the RFC 6265 (4.1.1) prohibited characters such as control characters.
126
+
127
+ ['', 'foo=bar', 'foo;bar', "foo\nbar"].each do |cookie_name|
128
+ lambda {
129
+ RestClient::Request.new(:method => 'get', :url => 'example.com',
130
+ :cookies => {cookie_name => 'value'})
131
+ }.should raise_error(ArgumentError, /\AInvalid cookie name/)
132
+ end
133
+ end
134
+
135
+ it "rejects cookie values containing invalid characters" do
136
+ # Cookie validity is something of a mess, but we should reject the worst of
137
+ # the RFC 6265 (4.1.1) prohibited characters such as control characters.
138
+
139
+ ['foo,bar', 'foo;bar', "foo\nbar"].each do |cookie_value|
140
+ lambda {
141
+ RestClient::Request.new(:method => 'get', :url => 'example.com',
142
+ :cookies => {'test' => cookie_value})
143
+ }.should raise_error(ArgumentError, /\AInvalid cookie value/)
144
+ end
145
+ end
146
+
147
+ it "uses netrc credentials" do
148
+ URI.stub(:parse).and_return(double('uri', :user => nil, :password => nil, :host => 'example.com'))
149
+ Netrc.stub(:read).and_return('example.com' => ['a', 'b'])
150
+ @request.parse_url_with_auth('http://example.com/resource')
151
+ @request.user.should eq 'a'
152
+ @request.password.should eq 'b'
153
+ end
154
+
155
+ it "uses credentials in the url in preference to netrc" do
156
+ URI.stub(:parse).and_return(double('uri', :user => 'joe%20', :password => 'pass1', :host => 'example.com'))
157
+ Netrc.stub(:read).and_return('example.com' => ['a', 'b'])
158
+ @request.parse_url_with_auth('http://joe%20:pass1@example.com/resource')
159
+ @request.user.should eq 'joe '
160
+ @request.password.should eq 'pass1'
161
+ end
162
+
163
+ it "determines the Net::HTTP class to instantiate by the method name" do
164
+ @request.net_http_request_class(:put).should eq Net::HTTP::Put
165
+ end
166
+
167
+ describe "user headers" do
168
+ it "merges user headers with the default headers" do
169
+ @request.should_receive(:default_headers).and_return({ :accept => '*/*; q=0.5, application/xml', :accept_encoding => 'gzip, deflate' })
170
+ headers = @request.make_headers("Accept" => "application/json", :accept_encoding => 'gzip')
171
+ headers.should have_key "Accept-Encoding"
172
+ headers["Accept-Encoding"].should eq "gzip"
173
+ headers.should have_key "Accept"
174
+ headers["Accept"].should eq "application/json"
175
+ end
176
+
177
+ it "prefers the user header when the same header exists in the defaults" do
178
+ @request.should_receive(:default_headers).and_return({ '1' => '2' })
179
+ headers = @request.make_headers('1' => '3')
180
+ headers.should have_key('1')
181
+ headers['1'].should eq '3'
182
+ end
183
+
184
+ it "converts user headers to string before calling CGI::unescape which fails on non string values" do
185
+ @request.should_receive(:default_headers).and_return({ '1' => '2' })
186
+ headers = @request.make_headers('1' => 3)
187
+ headers.should have_key('1')
188
+ headers['1'].should eq '3'
189
+ end
190
+ end
191
+
192
+ describe "header symbols" do
193
+
194
+ it "converts header symbols from :content_type to 'Content-Type'" do
195
+ @request.should_receive(:default_headers).and_return({})
196
+ headers = @request.make_headers(:content_type => 'abc')
197
+ headers.should have_key('Content-Type')
198
+ headers['Content-Type'].should eq 'abc'
199
+ end
200
+
201
+ it "converts content-type from extension to real content-type" do
202
+ @request.should_receive(:default_headers).and_return({})
203
+ headers = @request.make_headers(:content_type => 'json')
204
+ headers.should have_key('Content-Type')
205
+ headers['Content-Type'].should eq 'application/json'
206
+ end
207
+
208
+ it "converts accept from extension(s) to real content-type(s)" do
209
+ @request.should_receive(:default_headers).and_return({})
210
+ headers = @request.make_headers(:accept => 'json, mp3')
211
+ headers.should have_key('Accept')
212
+ headers['Accept'].should eq 'application/json, audio/mpeg'
213
+
214
+ @request.should_receive(:default_headers).and_return({})
215
+ headers = @request.make_headers(:accept => :json)
216
+ headers.should have_key('Accept')
217
+ headers['Accept'].should eq 'application/json'
218
+ end
219
+
220
+ it "only convert symbols in header" do
221
+ @request.should_receive(:default_headers).and_return({})
222
+ headers = @request.make_headers({:foo_bar => 'value', "bar_bar" => 'value'})
223
+ headers['Foo-Bar'].should eq 'value'
224
+ headers['bar_bar'].should eq 'value'
225
+ end
226
+
227
+ it "converts header values to strings" do
228
+ @request.make_headers('A' => 1)['A'].should eq '1'
229
+ end
230
+ end
231
+
232
+ it "executes by constructing the Net::HTTP object, headers, and payload and calling transmit" do
233
+ @request.should_receive(:parse_url_with_auth).with('http://some/resource').and_return(@uri)
234
+ klass = double("net:http class")
235
+ @request.should_receive(:net_http_request_class).with(:put).and_return(klass)
236
+ klass.should_receive(:new).and_return('result')
237
+ @request.should_receive(:transmit).with(@uri, 'result', kind_of(RestClient::Payload::Base))
238
+ @request.execute
239
+ end
240
+
241
+ it "transmits the request with Net::HTTP" do
242
+ @http.should_receive(:request).with('req', 'payload')
243
+ @request.should_receive(:process_result)
244
+ @request.transmit(@uri, 'req', 'payload')
245
+ end
246
+
247
+ describe "payload" do
248
+ it "sends nil payloads" do
249
+ @http.should_receive(:request).with('req', nil)
250
+ @request.should_receive(:process_result)
251
+ @request.stub(:response_log)
252
+ @request.transmit(@uri, 'req', nil)
253
+ end
254
+
255
+ it "passes non-hash payloads straight through" do
256
+ @request.process_payload("x").should eq "x"
257
+ end
258
+
259
+ it "converts a hash payload to urlencoded data" do
260
+ @request.process_payload(:a => 'b c+d').should eq "a=b%20c%2Bd"
261
+ end
262
+
263
+ it "accepts nested hashes in payload" do
264
+ payload = @request.process_payload(:user => { :name => 'joe', :location => { :country => 'USA', :state => 'CA' }})
265
+ payload.should include('user[name]=joe')
266
+ payload.should include('user[location][country]=USA')
267
+ payload.should include('user[location][state]=CA')
268
+ end
269
+ end
270
+
271
+ it "set urlencoded content_type header on hash payloads" do
272
+ @request.process_payload(:a => 1)
273
+ @request.headers[:content_type].should eq 'application/x-www-form-urlencoded'
274
+ end
275
+
276
+ describe "credentials" do
277
+ it "sets up the credentials prior to the request" do
278
+ @http.stub(:request)
279
+
280
+ @request.stub(:process_result)
281
+ @request.stub(:response_log)
282
+
283
+ @request.stub(:user).and_return('joe')
284
+ @request.stub(:password).and_return('mypass')
285
+ @request.should_receive(:setup_credentials).with('req')
286
+
287
+ @request.transmit(@uri, 'req', nil)
288
+ end
289
+
290
+ it "does not attempt to send any credentials if user is nil" do
291
+ @request.stub(:user).and_return(nil)
292
+ req = double("request")
293
+ req.should_not_receive(:basic_auth)
294
+ @request.setup_credentials(req)
295
+ end
296
+
297
+ it "setup credentials when there's a user" do
298
+ @request.stub(:user).and_return('joe')
299
+ @request.stub(:password).and_return('mypass')
300
+ req = double("request")
301
+ req.should_receive(:basic_auth).with('joe', 'mypass')
302
+ @request.setup_credentials(req)
303
+ end
304
+ end
305
+
306
+ it "catches EOFError and shows the more informative ServerBrokeConnection" do
307
+ @http.stub(:request).and_raise(EOFError)
308
+ lambda { @request.transmit(@uri, 'req', nil) }.should raise_error(RestClient::ServerBrokeConnection)
309
+ end
310
+
311
+ it "catches OpenSSL::SSL::SSLError and raise it back without more informative message" do
312
+ @http.stub(:request).and_raise(OpenSSL::SSL::SSLError)
313
+ lambda { @request.transmit(@uri, 'req', nil) }.should raise_error(OpenSSL::SSL::SSLError)
314
+ end
315
+
316
+ it "catches Timeout::Error and raise the more informative RequestTimeout" do
317
+ @http.stub(:request).and_raise(Timeout::Error)
318
+ lambda { @request.transmit(@uri, 'req', nil) }.should raise_error(RestClient::RequestTimeout)
319
+ end
320
+
321
+ it "catches Timeout::Error and raise the more informative RequestTimeout" do
322
+ @http.stub(:request).and_raise(Errno::ETIMEDOUT)
323
+ lambda { @request.transmit(@uri, 'req', nil) }.should raise_error(RestClient::RequestTimeout)
324
+ end
325
+
326
+ it "class method execute wraps constructor" do
327
+ req = double("rest request")
328
+ RestClient::Request.should_receive(:new).with(1 => 2).and_return(req)
329
+ req.should_receive(:execute)
330
+ RestClient::Request.execute(1 => 2)
331
+ end
332
+
333
+ describe "exception" do
334
+ it "raises Unauthorized when the response is 401" do
335
+ res = double('response', :code => '401', :[] => ['content-encoding' => ''], :body => '' )
336
+ lambda { @request.process_result(res) }.should raise_error(RestClient::Unauthorized)
337
+ end
338
+
339
+ it "raises ResourceNotFound when the response is 404" do
340
+ res = double('response', :code => '404', :[] => ['content-encoding' => ''], :body => '' )
341
+ lambda { @request.process_result(res) }.should raise_error(RestClient::ResourceNotFound)
342
+ end
343
+
344
+ it "raises RequestFailed otherwise" do
345
+ res = double('response', :code => '500', :[] => ['content-encoding' => ''], :body => '' )
346
+ lambda { @request.process_result(res) }.should raise_error(RestClient::InternalServerError)
347
+ end
348
+ end
349
+
350
+ describe "block usage" do
351
+ it "returns what asked to" do
352
+ res = double('response', :code => '401', :[] => ['content-encoding' => ''], :body => '' )
353
+ @request.process_result(res){|response, request| "foo"}.should eq "foo"
354
+ end
355
+ end
356
+
357
+ describe "proxy" do
358
+ it "creates a proxy class if a proxy url is given" do
359
+ RestClient.stub(:proxy).and_return("http://example.com/")
360
+ @request.net_http_class.proxy_class?.should be_true
361
+ end
362
+
363
+ it "creates a non-proxy class if a proxy url is not given" do
364
+ @request.net_http_class.proxy_class?.should be_false
365
+ end
366
+ end
367
+
368
+
369
+ describe "logging" do
370
+ it "logs a get request" do
371
+ log = RestClient.log = []
372
+ RestClient::Request.new(:method => :get, :url => 'http://url').log_request
373
+ log[0].should eq %Q{RestClient.get "http://url", "Accept"=>"*/*; q=0.5, application/xml", "Accept-Encoding"=>"gzip, deflate"\n}
374
+ end
375
+
376
+ it "logs a post request with a small payload" do
377
+ log = RestClient.log = []
378
+ RestClient::Request.new(:method => :post, :url => 'http://url', :payload => 'foo').log_request
379
+ log[0].should eq %Q{RestClient.post "http://url", "foo", "Accept"=>"*/*; q=0.5, application/xml", "Accept-Encoding"=>"gzip, deflate", "Content-Length"=>"3"\n}
380
+ end
381
+
382
+ it "logs a post request with a large payload" do
383
+ log = RestClient.log = []
384
+ RestClient::Request.new(:method => :post, :url => 'http://url', :payload => ('x' * 1000)).log_request
385
+ log[0].should eq %Q{RestClient.post "http://url", 1000 byte(s) length, "Accept"=>"*/*; q=0.5, application/xml", "Accept-Encoding"=>"gzip, deflate", "Content-Length"=>"1000"\n}
386
+ end
387
+
388
+ it "logs input headers as a hash" do
389
+ log = RestClient.log = []
390
+ RestClient::Request.new(:method => :get, :url => 'http://url', :headers => { :accept => 'text/plain' }).log_request
391
+ log[0].should eq %Q{RestClient.get "http://url", "Accept"=>"text/plain", "Accept-Encoding"=>"gzip, deflate"\n}
392
+ end
393
+
394
+ it "logs a response including the status code, content type, and result body size in bytes" do
395
+ log = RestClient.log = []
396
+ res = double('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd')
397
+ res.stub(:[]).with('Content-type').and_return('text/html')
398
+ @request.log_response res
399
+ log[0].should eq "# => 200 OK | text/html 4 bytes\n"
400
+ end
401
+
402
+ it "logs a response with a nil Content-type" do
403
+ log = RestClient.log = []
404
+ res = double('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd')
405
+ res.stub(:[]).with('Content-type').and_return(nil)
406
+ @request.log_response res
407
+ log[0].should eq "# => 200 OK | 4 bytes\n"
408
+ end
409
+
410
+ it "logs a response with a nil body" do
411
+ log = RestClient.log = []
412
+ res = double('result', :code => '200', :class => Net::HTTPOK, :body => nil)
413
+ res.stub(:[]).with('Content-type').and_return('text/html; charset=utf-8')
414
+ @request.log_response res
415
+ log[0].should eq "# => 200 OK | text/html 0 bytes\n"
416
+ end
417
+ end
418
+
419
+ it "strips the charset from the response content type" do
420
+ log = RestClient.log = []
421
+ res = double('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd')
422
+ res.stub(:[]).with('Content-type').and_return('text/html; charset=utf-8')
423
+ @request.log_response res
424
+ log[0].should eq "# => 200 OK | text/html 4 bytes\n"
425
+ end
426
+
427
+ describe "timeout" do
428
+ it "does not set timeouts if not specified" do
429
+ @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload')
430
+ @http.stub(:request)
431
+ @request.stub(:process_result)
432
+ @request.stub(:response_log)
433
+
434
+ @net.should_not_receive(:read_timeout=)
435
+ @net.should_not_receive(:open_timeout=)
436
+
437
+ @request.transmit(@uri, 'req', nil)
438
+ end
439
+
440
+ it "set read_timeout" do
441
+ @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :timeout => 123)
442
+ @http.stub(:request)
443
+ @request.stub(:process_result)
444
+ @request.stub(:response_log)
445
+
446
+ @net.should_receive(:read_timeout=).with(123)
447
+
448
+ @request.transmit(@uri, 'req', nil)
449
+ end
450
+
451
+ it "set open_timeout" do
452
+ @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :open_timeout => 123)
453
+ @http.stub(:request)
454
+ @request.stub(:process_result)
455
+ @request.stub(:response_log)
456
+
457
+ @net.should_receive(:open_timeout=).with(123)
458
+
459
+ @request.transmit(@uri, 'req', nil)
460
+ end
461
+
462
+ it "disable timeout by setting it to nil" do
463
+ @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :timeout => nil, :open_timeout => nil)
464
+ @http.stub(:request)
465
+ @request.stub(:process_result)
466
+ @request.stub(:response_log)
467
+
468
+ @net.should_receive(:read_timeout=).with(nil)
469
+ @net.should_receive(:open_timeout=).with(nil)
470
+
471
+ @request.transmit(@uri, 'req', nil)
472
+ end
473
+
474
+ it "deprecated: disable timeout by setting it to -1" do
475
+ @request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :timeout => -1, :open_timeout => -1)
476
+ @http.stub(:request)
477
+ @request.stub(:process_result)
478
+ @request.stub(:response_log)
479
+
480
+ @request.should_receive(:warn)
481
+ @net.should_receive(:read_timeout=).with(nil)
482
+
483
+ @request.should_receive(:warn)
484
+ @net.should_receive(:open_timeout=).with(nil)
485
+
486
+ @request.transmit(@uri, 'req', nil)
487
+ end
488
+ end
489
+
490
+ describe "ssl" do
491
+ it "uses SSL when the URI refers to a https address" do
492
+ @uri.stub(:is_a?).with(URI::HTTPS).and_return(true)
493
+ @net.should_receive(:use_ssl=).with(true)
494
+ @http.stub(:request)
495
+ @request.stub(:process_result)
496
+ @request.stub(:response_log)
497
+ @request.transmit(@uri, 'req', 'payload')
498
+ end
499
+
500
+ it "should default to verifying ssl certificates" do
501
+ @request.verify_ssl.should eq OpenSSL::SSL::VERIFY_PEER
502
+ end
503
+
504
+ it "should have expected values for VERIFY_PEER and VERIFY_NONE" do
505
+ OpenSSL::SSL::VERIFY_NONE.should eq(0)
506
+ OpenSSL::SSL::VERIFY_PEER.should eq(1)
507
+ end
508
+
509
+ it "should set net.verify_mode to OpenSSL::SSL::VERIFY_NONE if verify_ssl is false" do
510
+ @request = RestClient::Request.new(:method => :put, :verify_ssl => false, :url => 'http://some/resource', :payload => 'payload')
511
+ @net.should_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
512
+ @http.stub(:request)
513
+ @request.stub(:process_result)
514
+ @request.stub(:response_log)
515
+ @request.transmit(@uri, 'req', 'payload')
516
+ end
517
+
518
+ it "should not set net.verify_mode to OpenSSL::SSL::VERIFY_NONE if verify_ssl is true" do
519
+ @request = RestClient::Request.new(:method => :put, :url => 'https://some/resource', :payload => 'payload', :verify_ssl => true)
520
+ @net.should_not_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
521
+ @http.stub(:request)
522
+ @request.stub(:process_result)
523
+ @request.stub(:response_log)
524
+ @request.transmit(@uri, 'req', 'payload')
525
+ end
526
+
527
+ it "should set net.verify_mode to OpenSSL::SSL::VERIFY_PEER if verify_ssl is true" do
528
+ @request = RestClient::Request.new(:method => :put, :url => 'https://some/resource', :payload => 'payload', :verify_ssl => true)
529
+ @net.should_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER)
530
+ @http.stub(:request)
531
+ @request.stub(:process_result)
532
+ @request.stub(:response_log)
533
+ @request.transmit(@uri, 'req', 'payload')
534
+ end
535
+
536
+ it "should set net.verify_mode to OpenSSL::SSL::VERIFY_PEER if verify_ssl is not given" do
537
+ @request = RestClient::Request.new(:method => :put, :url => 'https://some/resource', :payload => 'payload')
538
+ @net.should_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_PEER)
539
+ @http.stub(:request)
540
+ @request.stub(:process_result)
541
+ @request.stub(:response_log)
542
+ @request.transmit(@uri, 'req', 'payload')
543
+ end
544
+
545
+ it "should set net.verify_mode to the passed value if verify_ssl is an OpenSSL constant" do
546
+ mode = OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
547
+ @request = RestClient::Request.new( :method => :put,
548
+ :url => 'https://some/resource',
549
+ :payload => 'payload',
550
+ :verify_ssl => mode )
551
+ @net.should_receive(:verify_mode=).with(mode)
552
+ @http.stub(:request)
553
+ @request.stub(:process_result)
554
+ @request.stub(:response_log)
555
+ @request.transmit(@uri, 'req', 'payload')
556
+ end
557
+
558
+ it "should default to not having an ssl_client_cert" do
559
+ @request.ssl_client_cert.should be(nil)
560
+ end
561
+
562
+ it "should set the ssl_version if provided" do
563
+ @request = RestClient::Request.new(
564
+ :method => :put,
565
+ :url => 'https://some/resource',
566
+ :payload => 'payload',
567
+ :ssl_version => "TLSv1"
568
+ )
569
+ @net.should_receive(:ssl_version=).with("TLSv1")
570
+ @http.stub(:request)
571
+ @request.stub(:process_result)
572
+ @request.stub(:response_log)
573
+ @request.transmit(@uri, 'req', 'payload')
574
+ end
575
+
576
+ it "should not set the ssl_version if not provided" do
577
+ @request = RestClient::Request.new(
578
+ :method => :put,
579
+ :url => 'https://some/resource',
580
+ :payload => 'payload'
581
+ )
582
+ @net.should_not_receive(:ssl_version=).with("TLSv1")
583
+ @http.stub(:request)
584
+ @request.stub(:process_result)
585
+ @request.stub(:response_log)
586
+ @request.transmit(@uri, 'req', 'payload')
587
+ end
588
+
589
+ it "should set the ssl_ciphers if provided" do
590
+ ciphers = 'AESGCM:HIGH:!aNULL:!eNULL:RC4+RSA'
591
+ @request = RestClient::Request.new(
592
+ :method => :put,
593
+ :url => 'https://some/resource',
594
+ :payload => 'payload',
595
+ :ssl_ciphers => ciphers
596
+ )
597
+ @net.should_receive(:ciphers=).with(ciphers)
598
+ @http.stub(:request)
599
+ @request.stub(:process_result)
600
+ @request.stub(:response_log)
601
+ @request.transmit(@uri, 'req', 'payload')
602
+ end
603
+
604
+ it "should not set the ssl_ciphers if set to nil" do
605
+ @request = RestClient::Request.new(
606
+ :method => :put,
607
+ :url => 'https://some/resource',
608
+ :payload => 'payload',
609
+ :ssl_ciphers => nil,
610
+ )
611
+ @net.should_not_receive(:ciphers=)
612
+ @http.stub(:request)
613
+ @request.stub(:process_result)
614
+ @request.stub(:response_log)
615
+ @request.transmit(@uri, 'req', 'payload')
616
+ end
617
+
618
+ it "should override ssl_ciphers with better defaults with weak default ciphers" do
619
+ stub_const(
620
+ '::OpenSSL::SSL::SSLContext::DEFAULT_PARAMS',
621
+ {
622
+ :ssl_version=>"SSLv23",
623
+ :verify_mode=>1,
624
+ :ciphers=>"ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW",
625
+ :options=>-2147480577,
626
+ }
627
+ )
628
+
629
+ @request = RestClient::Request.new(
630
+ :method => :put,
631
+ :url => 'https://some/resource',
632
+ :payload => 'payload',
633
+ )
634
+
635
+ @net.should_receive(:ciphers=).with(RestClient::Request::DefaultCiphers)
636
+
637
+ @http.stub(:request)
638
+ @request.stub(:process_result)
639
+ @request.stub(:response_log)
640
+ @request.transmit(@uri, 'req', 'payload')
641
+ end
642
+
643
+ it "should not override ssl_ciphers with better defaults with different default ciphers" do
644
+ stub_const(
645
+ '::OpenSSL::SSL::SSLContext::DEFAULT_PARAMS',
646
+ {
647
+ :ssl_version=>"SSLv23",
648
+ :verify_mode=>1,
649
+ :ciphers=>"HIGH:!aNULL:!eNULL:!EXPORT:!LOW:!MEDIUM:!SSLv2",
650
+ :options=>-2147480577,
651
+ }
652
+ )
653
+
654
+ @request = RestClient::Request.new(
655
+ :method => :put,
656
+ :url => 'https://some/resource',
657
+ :payload => 'payload',
658
+ )
659
+
660
+ @net.should_not_receive(:ciphers=)
661
+
662
+ @http.stub(:request)
663
+ @request.stub(:process_result)
664
+ @request.stub(:response_log)
665
+ @request.transmit(@uri, 'req', 'payload')
666
+ end
667
+
668
+ it "should set the ssl_client_cert if provided" do
669
+ @request = RestClient::Request.new(
670
+ :method => :put,
671
+ :url => 'https://some/resource',
672
+ :payload => 'payload',
673
+ :ssl_client_cert => "whatsupdoc!"
674
+ )
675
+ @net.should_receive(:cert=).with("whatsupdoc!")
676
+ @http.stub(:request)
677
+ @request.stub(:process_result)
678
+ @request.stub(:response_log)
679
+ @request.transmit(@uri, 'req', 'payload')
680
+ end
681
+
682
+ it "should not set the ssl_client_cert if it is not provided" do
683
+ @request = RestClient::Request.new(
684
+ :method => :put,
685
+ :url => 'https://some/resource',
686
+ :payload => 'payload'
687
+ )
688
+ @net.should_not_receive(:cert=)
689
+ @http.stub(:request)
690
+ @request.stub(:process_result)
691
+ @request.stub(:response_log)
692
+ @request.transmit(@uri, 'req', 'payload')
693
+ end
694
+
695
+ it "should default to not having an ssl_client_key" do
696
+ @request.ssl_client_key.should be(nil)
697
+ end
698
+
699
+ it "should set the ssl_client_key if provided" do
700
+ @request = RestClient::Request.new(
701
+ :method => :put,
702
+ :url => 'https://some/resource',
703
+ :payload => 'payload',
704
+ :ssl_client_key => "whatsupdoc!"
705
+ )
706
+ @net.should_receive(:key=).with("whatsupdoc!")
707
+ @http.stub(:request)
708
+ @request.stub(:process_result)
709
+ @request.stub(:response_log)
710
+ @request.transmit(@uri, 'req', 'payload')
711
+ end
712
+
713
+ it "should not set the ssl_client_key if it is not provided" do
714
+ @request = RestClient::Request.new(
715
+ :method => :put,
716
+ :url => 'https://some/resource',
717
+ :payload => 'payload'
718
+ )
719
+ @net.should_not_receive(:key=)
720
+ @http.stub(:request)
721
+ @request.stub(:process_result)
722
+ @request.stub(:response_log)
723
+ @request.transmit(@uri, 'req', 'payload')
724
+ end
725
+
726
+ it "should default to not having an ssl_ca_file" do
727
+ @request.ssl_ca_file.should be(nil)
728
+ end
729
+
730
+ it "should set the ssl_ca_file if provided" do
731
+ @request = RestClient::Request.new(
732
+ :method => :put,
733
+ :url => 'https://some/resource',
734
+ :payload => 'payload',
735
+ :ssl_ca_file => "Certificate Authority File"
736
+ )
737
+ @net.should_receive(:ca_file=).with("Certificate Authority File")
738
+ @net.should_not_receive(:cert_store=)
739
+ @http.stub(:request)
740
+ @request.stub(:process_result)
741
+ @request.stub(:response_log)
742
+ @request.transmit(@uri, 'req', 'payload')
743
+ end
744
+
745
+ it "should not set the ssl_ca_file if it is not provided" do
746
+ @request = RestClient::Request.new(
747
+ :method => :put,
748
+ :url => 'https://some/resource',
749
+ :payload => 'payload'
750
+ )
751
+ @net.should_not_receive(:ca_file=)
752
+ @http.stub(:request)
753
+ @request.stub(:process_result)
754
+ @request.stub(:response_log)
755
+ @request.transmit(@uri, 'req', 'payload')
756
+ end
757
+
758
+ it "should default to not having an ssl_ca_path" do
759
+ @request.ssl_ca_path.should be(nil)
760
+ end
761
+
762
+ it "should set the ssl_ca_path if provided" do
763
+ @request = RestClient::Request.new(
764
+ :method => :put,
765
+ :url => 'https://some/resource',
766
+ :payload => 'payload',
767
+ :ssl_ca_path => "Certificate Authority Path"
768
+ )
769
+ @net.should_receive(:ca_path=).with("Certificate Authority Path")
770
+ @net.should_not_receive(:cert_store=)
771
+ @http.stub(:request)
772
+ @request.stub(:process_result)
773
+ @request.stub(:response_log)
774
+ @request.transmit(@uri, 'req', 'payload')
775
+ end
776
+
777
+ it "should not set the ssl_ca_path if it is not provided" do
778
+ @request = RestClient::Request.new(
779
+ :method => :put,
780
+ :url => 'https://some/resource',
781
+ :payload => 'payload'
782
+ )
783
+ @net.should_not_receive(:ca_path=)
784
+ @http.stub(:request)
785
+ @request.stub(:process_result)
786
+ @request.stub(:response_log)
787
+ @request.transmit(@uri, 'req', 'payload')
788
+ end
789
+
790
+ it "should set the ssl_cert_store if provided" do
791
+ store = OpenSSL::X509::Store.new
792
+ store.set_default_paths
793
+
794
+ @request = RestClient::Request.new(
795
+ :method => :put,
796
+ :url => 'https://some/resource',
797
+ :payload => 'payload',
798
+ :ssl_cert_store => store
799
+ )
800
+ @net.should_receive(:cert_store=).with(store)
801
+ @net.should_not_receive(:ca_path=)
802
+ @net.should_not_receive(:ca_file=)
803
+ @http.stub(:request)
804
+ @request.stub(:process_result)
805
+ @request.stub(:response_log)
806
+ @request.transmit(@uri, 'req', 'payload')
807
+ end
808
+
809
+ it "should by default set the ssl_cert_store if no CA info is provided" do
810
+ @request = RestClient::Request.new(
811
+ :method => :put,
812
+ :url => 'https://some/resource',
813
+ :payload => 'payload'
814
+ )
815
+ @net.should_receive(:cert_store=)
816
+ @net.should_not_receive(:ca_path=)
817
+ @net.should_not_receive(:ca_file=)
818
+ @http.stub(:request)
819
+ @request.stub(:process_result)
820
+ @request.stub(:response_log)
821
+ @request.transmit(@uri, 'req', 'payload')
822
+ end
823
+
824
+ it "should not set the ssl_cert_store if it is set falsy" do
825
+ @request = RestClient::Request.new(
826
+ :method => :put,
827
+ :url => 'https://some/resource',
828
+ :payload => 'payload',
829
+ :ssl_cert_store => nil,
830
+ )
831
+ @net.should_not_receive(:cert_store=)
832
+ @http.stub(:request)
833
+ @request.stub(:process_result)
834
+ @request.stub(:response_log)
835
+ @request.transmit(@uri, 'req', 'payload')
836
+ end
837
+
838
+ it "should not set the ssl_verify_callback by default" do
839
+ @request = RestClient::Request.new(
840
+ :method => :put,
841
+ :url => 'https://some/resource',
842
+ :payload => 'payload',
843
+ )
844
+ @net.should_not_receive(:verify_callback=)
845
+ @http.stub(:request)
846
+ @request.stub(:process_result)
847
+ @request.stub(:response_log)
848
+ @request.transmit(@uri, 'req', 'payload')
849
+ end
850
+
851
+ it "should set the ssl_verify_callback if passed" do
852
+ callback = lambda {}
853
+ @request = RestClient::Request.new(
854
+ :method => :put,
855
+ :url => 'https://some/resource',
856
+ :payload => 'payload',
857
+ :ssl_verify_callback => callback,
858
+ )
859
+ @net.should_receive(:verify_callback=).with(callback)
860
+
861
+ # we'll read cert_store on jruby
862
+ # https://github.com/jruby/jruby/issues/597
863
+ if RestClient::Platform.jruby?
864
+ allow(@net).to receive(:cert_store)
865
+ end
866
+
867
+ @http.stub(:request)
868
+ @request.stub(:process_result)
869
+ @request.stub(:response_log)
870
+ @request.transmit(@uri, 'req', 'payload')
871
+ end
872
+
873
+ # </ssl>
874
+ end
875
+
876
+ it "should still return a response object for 204 No Content responses" do
877
+ @request = RestClient::Request.new(
878
+ :method => :put,
879
+ :url => 'https://some/resource',
880
+ :payload => 'payload'
881
+ )
882
+ net_http_res = Net::HTTPNoContent.new("", "204", "No Content")
883
+ net_http_res.stub(:read_body).and_return(nil)
884
+ @http.should_receive(:request).and_return(@request.fetch_body(net_http_res))
885
+ response = @request.transmit(@uri, 'req', 'payload')
886
+ response.should_not be_nil
887
+ response.code.should eq 204
888
+ end
889
+
890
+ describe "raw response" do
891
+ it "should read the response into a binary-mode tempfile" do
892
+ @request = RestClient::Request.new(:method => "get", :url => "example.com", :raw_response => true)
893
+
894
+ tempfile = double("tempfile")
895
+ tempfile.should_receive(:binmode)
896
+ tempfile.stub(:open)
897
+ tempfile.stub(:close)
898
+ Tempfile.should_receive(:new).with("rest-client").and_return(tempfile)
899
+
900
+ net_http_res = Net::HTTPOK.new(nil, "200", "body")
901
+ net_http_res.stub(:read_body).and_return("body")
902
+ @request.fetch_body(net_http_res)
903
+ end
904
+ end
905
+ end