rack-cors 1.0.5 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,20 +0,0 @@
1
- <html>
2
- <head>
3
- <meta charset="utf-8">
4
- <title>Mocha Tests</title>
5
- <link rel="stylesheet" href="mocha.css" />
6
- </head>
7
- <body>
8
- <div id="mocha"></div>
9
- <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
10
- <script src="expect.js"></script>
11
- <script src="mocha.js"></script>
12
- <script>mocha.setup('bdd')</script>
13
- <script src="test.cors.js"></script>
14
- <script>
15
- mocha.checkLeaks();
16
- mocha.globals(['jQuery']);
17
- mocha.run();
18
- </script>
19
- </body>
20
- </html>
@@ -1,47 +0,0 @@
1
- CORS_SERVER = '127.0.0.1.xip.io:9292'
2
-
3
- describe 'CORS', ->
4
-
5
- it 'should allow access to dynamic resource', (done) ->
6
- $.get "http://#{CORS_SERVER}/", (data, status, xhr) ->
7
- expect(data).to.eql('Hello world')
8
- done()
9
-
10
- it 'should allow PUT access to dynamic resource', (done) ->
11
- $.ajax("http://#{CORS_SERVER}/", type: 'PUT').done (data, textStatus, jqXHR) ->
12
- expect(data).to.eql('Hello world')
13
- done()
14
-
15
- it 'should allow PATCH access to dynamic resource', (done) ->
16
- $.ajax("http://#{CORS_SERVER}/", type: 'PATCH').done (data, textStatus, jqXHR) ->
17
- expect(data).to.eql('Hello world')
18
- done()
19
-
20
- it 'should allow HEAD access to dynamic resource', (done) ->
21
- $.ajax("http://#{CORS_SERVER}/", type: 'HEAD').done (data, textStatus, jqXHR) ->
22
- expect(jqXHR.status).to.eql(200)
23
- done()
24
-
25
- it 'should allow DELETE access to dynamic resource', (done) ->
26
- $.ajax("http://#{CORS_SERVER}/", type: 'DELETE').done (data, textStatus, jqXHR) ->
27
- expect(data).to.eql('Hello world')
28
- done()
29
-
30
- it 'should allow OPTIONS access to dynamic resource', (done) ->
31
- $.ajax("http://#{CORS_SERVER}/", type: 'OPTIONS').done (data, textStatus, jqXHR) ->
32
- expect(jqXHR.status).to.eql(200)
33
- done()
34
-
35
- it 'should allow access to static resource', (done) ->
36
- $.get "http://#{CORS_SERVER}/static.txt", (data, status, xhr) ->
37
- expect($.trim(data)).to.eql("hello world")
38
- done()
39
-
40
- it 'should allow post resource', (done) ->
41
- $.ajax
42
- type: 'POST'
43
- url: "http://#{CORS_SERVER}/cors"
44
- beforeSend: (xhr) -> xhr.setRequestHeader('X-Requested-With', 'XMLHTTPRequest')
45
- success:(data, status, xhr) ->
46
- expect($.trim(data)).to.eql("OK!")
47
- done()
@@ -1,75 +0,0 @@
1
- // Generated by CoffeeScript 2.3.1
2
- (function() {
3
- var CORS_SERVER;
4
-
5
- CORS_SERVER = '127.0.0.1.xip.io:9292';
6
-
7
- describe('CORS', function() {
8
- it('should allow access to dynamic resource', function(done) {
9
- return $.get(`http://${CORS_SERVER}/`, function(data, status, xhr) {
10
- expect(data).to.eql('Hello world');
11
- return done();
12
- });
13
- });
14
- it('should allow PUT access to dynamic resource', function(done) {
15
- return $.ajax(`http://${CORS_SERVER}/`, {
16
- type: 'PUT'
17
- }).done(function(data, textStatus, jqXHR) {
18
- expect(data).to.eql('Hello world');
19
- return done();
20
- });
21
- });
22
- it('should allow PATCH access to dynamic resource', function(done) {
23
- return $.ajax(`http://${CORS_SERVER}/`, {
24
- type: 'PATCH'
25
- }).done(function(data, textStatus, jqXHR) {
26
- expect(data).to.eql('Hello world');
27
- return done();
28
- });
29
- });
30
- it('should allow HEAD access to dynamic resource', function(done) {
31
- return $.ajax(`http://${CORS_SERVER}/`, {
32
- type: 'HEAD'
33
- }).done(function(data, textStatus, jqXHR) {
34
- expect(jqXHR.status).to.eql(200);
35
- return done();
36
- });
37
- });
38
- it('should allow DELETE access to dynamic resource', function(done) {
39
- return $.ajax(`http://${CORS_SERVER}/`, {
40
- type: 'DELETE'
41
- }).done(function(data, textStatus, jqXHR) {
42
- expect(data).to.eql('Hello world');
43
- return done();
44
- });
45
- });
46
- it('should allow OPTIONS access to dynamic resource', function(done) {
47
- return $.ajax(`http://${CORS_SERVER}/`, {
48
- type: 'OPTIONS'
49
- }).done(function(data, textStatus, jqXHR) {
50
- expect(jqXHR.status).to.eql(200);
51
- return done();
52
- });
53
- });
54
- it('should allow access to static resource', function(done) {
55
- return $.get(`http://${CORS_SERVER}/static.txt`, function(data, status, xhr) {
56
- expect($.trim(data)).to.eql("hello world");
57
- return done();
58
- });
59
- });
60
- return it('should allow post resource', function(done) {
61
- return $.ajax({
62
- type: 'POST',
63
- url: `http://${CORS_SERVER}/cors`,
64
- beforeSend: function(xhr) {
65
- return xhr.setRequestHeader('X-Requested-With', 'XMLHTTPRequest');
66
- },
67
- success: function(data, status, xhr) {
68
- expect($.trim(data)).to.eql("OK!");
69
- return done();
70
- }
71
- });
72
- });
73
- });
74
-
75
- }).call(this);
@@ -1,522 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/test'
3
- require 'mocha/setup'
4
- require 'rack/cors'
5
- require 'ostruct'
6
-
7
- Rack::Test::Session.class_eval do
8
- unless defined? :options
9
- def options(uri, params = {}, env = {}, &block)
10
- env = env_for(uri, env.merge(:method => "OPTIONS", :params => params))
11
- process_request(uri, env, &block)
12
- end
13
- end
14
- end
15
-
16
- Rack::Test::Methods.class_eval do
17
- def_delegator :current_session, :options
18
- end
19
-
20
- module MiniTest::Assertions
21
- def assert_cors_success(response)
22
- assert !response.headers['Access-Control-Allow-Origin'].nil?, "Expected a successful CORS response"
23
- end
24
-
25
- def assert_not_cors_success(response)
26
- assert response.headers['Access-Control-Allow-Origin'].nil?, "Expected a failed CORS response"
27
- end
28
- end
29
-
30
- class CaptureResult
31
- def initialize(app, options = {})
32
- @app = app
33
- @result_holder = options[:holder]
34
- end
35
-
36
- def call(env)
37
- response = @app.call(env)
38
- @result_holder.cors_result = env[Rack::Cors::RACK_CORS]
39
- return response
40
- end
41
- end
42
-
43
- class FakeProxy
44
- def initialize(app, options = {})
45
- @app = app
46
- end
47
-
48
- def call(env)
49
- status, headers, body = @app.call(env)
50
- headers['Vary'] = %w(Origin User-Agent)
51
- [status, headers, body]
52
- end
53
- end
54
-
55
- Rack::MockResponse.infect_an_assertion :assert_cors_success, :must_render_cors_success, :only_one_argument
56
- Rack::MockResponse.infect_an_assertion :assert_not_cors_success, :wont_render_cors_success, :only_one_argument
57
-
58
- describe Rack::Cors do
59
- include Rack::Test::Methods
60
-
61
- attr_accessor :cors_result
62
-
63
- def load_app(name, options = {})
64
- test = self
65
- Rack::Builder.new do
66
- use CaptureResult, :holder => test
67
- eval File.read(File.dirname(__FILE__) + "/#{name}.ru")
68
- use FakeProxy if options[:proxy]
69
- map('/') do
70
- run proc { |env|
71
- [200, {'Content-Type' => 'text/html'}, ['success']]
72
- }
73
- end
74
- end
75
- end
76
-
77
- let(:app) { load_app('test') }
78
-
79
- it 'should support simple CORS request' do
80
- successful_cors_request
81
- cors_result.must_be :hit
82
- end
83
-
84
- it "should not return CORS headers if Origin header isn't present" do
85
- get '/'
86
- last_response.wont_render_cors_success
87
- cors_result.wont_be :hit
88
- end
89
-
90
- it 'should support OPTIONS CORS request' do
91
- successful_cors_request '/options', :method => :options
92
- end
93
-
94
- it 'should support regex origins configuration' do
95
- successful_cors_request :origin => 'http://192.168.0.1:1234'
96
- end
97
-
98
- it 'should support subdomain example' do
99
- successful_cors_request :origin => 'http://subdomain.example.com'
100
- end
101
-
102
- it 'should support proc origins configuration' do
103
- successful_cors_request '/proc-origin', :origin => 'http://10.10.10.10:3000'
104
- end
105
-
106
- it 'should support lambda origin configuration' do
107
- successful_cors_request '/lambda-origin', :origin => 'http://10.10.10.10:3000'
108
- end
109
-
110
- it 'should support proc origins configuration (inverse)' do
111
- cors_request '/proc-origin', :origin => 'http://bad.guy'
112
- last_response.wont_render_cors_success
113
- end
114
-
115
- it 'should not mix up path rules across origins' do
116
- header 'Origin', 'http://10.10.10.10:3000'
117
- get '/' # / is configured in a separate rule block
118
- last_response.wont_render_cors_success
119
- end
120
-
121
- it 'should support alternative X-Origin header' do
122
- header 'X-Origin', 'http://localhost:3000'
123
- get '/'
124
- last_response.must_render_cors_success
125
- end
126
-
127
- it 'should support expose header configuration' do
128
- successful_cors_request '/expose_single_header'
129
- last_response.headers['Access-Control-Expose-Headers'].must_equal 'expose-test'
130
- end
131
-
132
- it 'should support expose multiple header configuration' do
133
- successful_cors_request '/expose_multiple_headers'
134
- last_response.headers['Access-Control-Expose-Headers'].must_equal 'expose-test-1, expose-test-2'
135
- end
136
-
137
- # Explanation: http://www.fastly.com/blog/best-practices-for-using-the-vary-header/
138
- it "should add Vary header if resource matches even if Origin header isn't present" do
139
- get '/'
140
- last_response.wont_render_cors_success
141
- last_response.headers['Vary'].must_equal 'Origin'
142
- end
143
-
144
- it "should add Vary header based on :vary option" do
145
- successful_cors_request '/vary_test'
146
- last_response.headers['Vary'].must_equal 'Origin, Host'
147
- end
148
-
149
- it "decode URL and resolve paths before resource matching" do
150
- header 'Origin', 'http://localhost:3000'
151
- get '/public/a/..%2F..%2Fprivate/stuff'
152
- last_response.wont_render_cors_success
153
- end
154
-
155
- describe 'with array of upstream Vary headers' do
156
- let(:app) { load_app('test', { proxy: true }) }
157
-
158
- it 'should add to them' do
159
- successful_cors_request '/vary_test'
160
- last_response.headers['Vary'].must_equal 'Origin, User-Agent, Host'
161
- end
162
- end
163
-
164
- it 'should add Vary header if Access-Control-Allow-Origin header was added and if it is specific' do
165
- successful_cors_request '/', :origin => "http://192.168.0.3:8080"
166
- last_response.headers['Access-Control-Allow-Origin'].must_equal 'http://192.168.0.3:8080'
167
- last_response.headers['Vary'].wont_be_nil
168
- end
169
-
170
- it 'should add Vary header even if Access-Control-Allow-Origin header was added and it is generic (*)' do
171
- successful_cors_request '/public_without_credentials', :origin => "http://192.168.1.3:8080"
172
- last_response.headers['Access-Control-Allow-Origin'].must_equal '*'
173
- last_response.headers['Vary'].must_equal 'Origin'
174
- end
175
-
176
- it 'should support multi allow configurations for the same resource' do
177
- successful_cors_request '/multi-allow-config', :origin => "http://mucho-grande.com"
178
- last_response.headers['Access-Control-Allow-Origin'].must_equal 'http://mucho-grande.com'
179
- last_response.headers['Vary'].must_equal 'Origin'
180
-
181
- successful_cors_request '/multi-allow-config', :origin => "http://192.168.1.3:8080"
182
- last_response.headers['Access-Control-Allow-Origin'].must_equal '*'
183
- last_response.headers['Vary'].must_equal 'Origin'
184
- end
185
-
186
- it "should not return CORS headers on OPTIONS request if Access-Control-Allow-Origin is not present" do
187
- options '/get-only'
188
- last_response.headers['Access-Control-Allow-Origin'].must_be_nil
189
- end
190
-
191
- it "should not apply CORS headers if it does not match conditional on resource" do
192
- header 'Origin', 'http://192.168.0.1:1234'
193
- get '/conditional'
194
- last_response.wont_render_cors_success
195
- end
196
-
197
- it "should apply CORS headers if it does match conditional on resource" do
198
- header 'X-OK', '1'
199
- successful_cors_request '/conditional', :origin => 'http://192.168.0.1:1234'
200
- end
201
-
202
- it "should not allow everything if Origin is configured as blank string" do
203
- cors_request '/blank-origin', origin: "http://example.net"
204
- last_response.wont_render_cors_success
205
- end
206
-
207
- it "should not allow credentials for public resources" do
208
- successful_cors_request '/public'
209
- last_response.headers['Access-Control-Allow-Credentials'].must_be_nil
210
- end
211
-
212
- describe 'logging' do
213
- it 'should not log debug messages if debug option is false' do
214
- app = mock
215
- app.stubs(:call).returns(200, {}, [''])
216
-
217
- logger = mock
218
- logger.expects(:debug).never
219
-
220
- cors = Rack::Cors.new(app, :debug => false, :logger => logger) {}
221
- cors.send(:debug, {}, 'testing')
222
- end
223
-
224
- it 'should log debug messages if debug option is true' do
225
- app = mock
226
- app.stubs(:call).returns(200, {}, [''])
227
-
228
- logger = mock
229
- logger.expects(:debug)
230
-
231
- cors = Rack::Cors.new(app, :debug => true, :logger => logger) {}
232
- cors.send(:debug, {}, 'testing')
233
- end
234
-
235
- it 'should use rack.logger if available' do
236
- app = mock
237
- app.stubs(:call).returns([200, {}, ['']])
238
-
239
- logger = mock
240
- logger.expects(:debug).at_least_once
241
-
242
- cors = Rack::Cors.new(app, :debug => true) {}
243
- cors.call({'rack.logger' => logger, 'HTTP_ORIGIN' => 'test.com'})
244
- end
245
-
246
- it 'should use logger proc' do
247
- app = mock
248
- app.stubs(:call).returns([200, {}, ['']])
249
-
250
- logger = mock
251
- logger.expects(:debug)
252
-
253
- cors = Rack::Cors.new(app, :debug => true, :logger => proc { logger }) {}
254
- cors.call({'HTTP_ORIGIN' => 'test.com'})
255
- end
256
-
257
- describe 'with Rails setup' do
258
- after do
259
- ::Rails.logger = nil if defined?(::Rails)
260
- end
261
-
262
- it 'should use Rails.logger if available' do
263
- app = mock
264
- app.stubs(:call).returns([200, {}, ['']])
265
-
266
- logger = mock
267
- logger.expects(:debug)
268
-
269
- ::Rails = OpenStruct.new(:logger => logger)
270
-
271
- cors = Rack::Cors.new(app, :debug => true) {}
272
- cors.call({'HTTP_ORIGIN' => 'test.com'})
273
- end
274
- end
275
-
276
- it 'should use Logger if none is set' do
277
- app = mock
278
- app.stubs(:call).returns([200, {}, ['']])
279
-
280
- logger = mock
281
- Logger.expects(:new).returns(logger)
282
- logger.expects(:tap).returns(logger)
283
- logger.expects(:debug)
284
-
285
- cors = Rack::Cors.new(app, :debug => true) {}
286
- cors.call({'HTTP_ORIGIN' => 'test.com'})
287
- end
288
- end
289
-
290
- describe 'preflight requests' do
291
- it 'should fail if origin is invalid' do
292
- preflight_request('http://allyourdataarebelongtous.com', '/')
293
- last_response.wont_render_cors_success
294
- cors_result.wont_be :hit
295
- cors_result.must_be :preflight
296
- end
297
-
298
- it 'should fail if Access-Control-Request-Method is not allowed' do
299
- preflight_request('http://localhost:3000', '/get-only', :method => :post)
300
- last_response.wont_render_cors_success
301
- cors_result.miss_reason.must_equal Rack::Cors::Result::MISS_DENY_METHOD
302
- cors_result.wont_be :hit
303
- cors_result.must_be :preflight
304
- end
305
-
306
- it 'should fail if header is not allowed' do
307
- preflight_request('http://localhost:3000', '/single_header', :headers => 'Fooey')
308
- last_response.wont_render_cors_success
309
- cors_result.miss_reason.must_equal Rack::Cors::Result::MISS_DENY_HEADER
310
- cors_result.wont_be :hit
311
- cors_result.must_be :preflight
312
- end
313
-
314
- it 'should allow any header if headers = :any' do
315
- preflight_request('http://localhost:3000', '/', :headers => 'Fooey')
316
- last_response.must_render_cors_success
317
- end
318
-
319
- it 'should allow any method if methods = :any' do
320
- preflight_request('http://localhost:3000', '/', :methods => :any)
321
- last_response.must_render_cors_success
322
- end
323
-
324
- it 'allows PATCH method' do
325
- preflight_request('http://localhost:3000', '/', :methods => [ :patch ])
326
- last_response.must_render_cors_success
327
- end
328
-
329
- it 'should allow header case insensitive match' do
330
- preflight_request('http://localhost:3000', '/single_header', :headers => 'X-Domain-Token')
331
- last_response.must_render_cors_success
332
- end
333
-
334
- it 'should allow multiple headers match' do
335
- # Webkit style
336
- preflight_request('http://localhost:3000', '/two_headers', :headers => 'X-Requested-With, X-Domain-Token')
337
- last_response.must_render_cors_success
338
-
339
- # Gecko style
340
- preflight_request('http://localhost:3000', '/two_headers', :headers => 'x-requested-with,x-domain-token')
341
- last_response.must_render_cors_success
342
- end
343
-
344
- it 'should * origin should allow any origin' do
345
- preflight_request('http://locohost:3000', '/public')
346
- last_response.must_render_cors_success
347
- last_response.headers['Access-Control-Allow-Origin'].must_equal '*'
348
- end
349
-
350
- it 'should * origin should allow any origin, and set * if no credentials required' do
351
- preflight_request('http://locohost:3000', '/public_without_credentials')
352
- last_response.must_render_cors_success
353
- last_response.headers['Access-Control-Allow-Origin'].must_equal '*'
354
- end
355
-
356
- it 'should return "file://" as header with "file://" as origin' do
357
- preflight_request('file://', '/')
358
- last_response.must_render_cors_success
359
- last_response.headers['Access-Control-Allow-Origin'].must_equal 'file://'
360
- end
361
-
362
- describe '' do
363
-
364
- let(:app) do
365
- test = self
366
- Rack::Builder.new do
367
- use CaptureResult, holder: test
368
- use Rack::Cors, debug: true, logger: Logger.new(StringIO.new) do
369
- allow do
370
- origins '*'
371
- resource '/', :methods => :post
372
- end
373
- end
374
- map('/') do
375
- run ->(env) { [500, {}, ['FAIL!']] }
376
- end
377
- end
378
- end
379
-
380
- it "should not send failed preflight requests thru the app" do
381
- preflight_request('http://localhost', '/', :method => :unsupported)
382
- last_response.wont_render_cors_success
383
- last_response.status.must_equal 200
384
- cors_result.must_be :preflight
385
- cors_result.wont_be :hit
386
- cors_result.miss_reason.must_equal Rack::Cors::Result::MISS_DENY_METHOD
387
- end
388
- end
389
- end
390
-
391
- describe "with insecure configuration" do
392
- let(:app) { load_app('insecure') }
393
-
394
- it "should raise an error" do
395
- proc { cors_request '/public' }.must_raise Rack::Cors::Resource::CorsMisconfigurationError
396
- end
397
- end
398
-
399
- describe "with non HTTP config" do
400
- let(:app) { load_app("non_http") }
401
-
402
- it 'should support non http/https origins' do
403
- successful_cors_request '/public', origin: 'content://com.company.app'
404
- end
405
- end
406
-
407
- describe 'Rack::Lint' do
408
- def app
409
- @app ||= Rack::Builder.new do
410
- use Rack::Cors
411
- use Rack::Lint
412
- run ->(env) { [200, {'Content-Type' => 'text/html'}, ['hello']] }
413
- end
414
- end
415
-
416
- it 'is lint-compliant with non-CORS request' do
417
- get '/'
418
- last_response.status.must_equal 200
419
- end
420
- end
421
-
422
- describe 'with app overriding CORS header' do
423
- let(:app) do
424
- Rack::Builder.new do
425
- use Rack::Cors, debug: true, logger: Logger.new(StringIO.new) do
426
- allow do
427
- origins '*'
428
- resource '/'
429
- end
430
- end
431
- map('/') do
432
- run ->(env) { [200, {'Access-Control-Allow-Origin' => 'http://foo.net'}, ['success']] }
433
- end
434
- end
435
- end
436
-
437
- it "should return app header" do
438
- successful_cors_request origin: "http://example.net"
439
- last_response.headers['Access-Control-Allow-Origin'].must_equal "http://foo.net"
440
- end
441
-
442
- it "should return original headers if in debug" do
443
- successful_cors_request origin: "http://example.net"
444
- last_response.headers['X-Rack-CORS-Original-Access-Control-Allow-Origin'].must_equal "*"
445
- end
446
- end
447
-
448
- describe 'with headers set to nil' do
449
- let(:app) do
450
- Rack::Builder.new do
451
- use Rack::Cors do
452
- allow do
453
- origins '*'
454
- resource '/', headers: nil
455
- end
456
- end
457
- map('/') do
458
- run ->(env) { [200, {'Content-Type' => 'text/html'}, ['hello']] }
459
- end
460
- end
461
- end
462
-
463
- it 'should succeed with CORS simple headers' do
464
- preflight_request('http://localhost:3000', '/', :headers => 'Accept')
465
- last_response.must_render_cors_success
466
- end
467
- end
468
-
469
- describe 'with custom allowed headers' do
470
- let(:app) do
471
- Rack::Builder.new do
472
- use Rack::Cors do
473
- allow do
474
- origins '*'
475
- resource '/', headers: []
476
- end
477
- end
478
- map('/') do
479
- run ->(env) { [200, {'Content-Type' => 'text/html'}, ['hello']] }
480
- end
481
- end
482
- end
483
-
484
- it 'should succeed with CORS simple headers' do
485
- preflight_request('http://localhost:3000', '/', :headers => 'Accept')
486
- last_response.must_render_cors_success
487
- preflight_request('http://localhost:3000', '/', :headers => 'Accept-Language')
488
- last_response.must_render_cors_success
489
- preflight_request('http://localhost:3000', '/', :headers => 'Content-Type')
490
- last_response.must_render_cors_success
491
- preflight_request('http://localhost:3000', '/', :headers => 'Content-Language')
492
- last_response.must_render_cors_success
493
- end
494
- end
495
-
496
- protected
497
- def cors_request(*args)
498
- path = args.first.is_a?(String) ? args.first : '/'
499
-
500
- opts = { :method => :get, :origin => 'http://localhost:3000' }
501
- opts.merge! args.last if args.last.is_a?(Hash)
502
-
503
- header 'Origin', opts[:origin]
504
- current_session.__send__ opts[:method], path, {}, test: self
505
- end
506
-
507
- def successful_cors_request(*args)
508
- cors_request(*args)
509
- last_response.must_render_cors_success
510
- end
511
-
512
- def preflight_request(origin, path, opts = {})
513
- header 'Origin', origin
514
- unless opts.key?(:method) && opts[:method].nil?
515
- header 'Access-Control-Request-Method', opts[:method] ? opts[:method].to_s.upcase : 'GET'
516
- end
517
- if opts[:headers]
518
- header 'Access-Control-Request-Headers', opts[:headers]
519
- end
520
- options path
521
- end
522
- end