rack-cors 1.0.5 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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