rack-cors 0.4.1 → 1.0.5

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,26 +1,34 @@
1
- // Generated by CoffeeScript 1.7.1
1
+ // Generated by CoffeeScript 2.3.1
2
2
  (function() {
3
3
  var CORS_SERVER;
4
4
 
5
- CORS_SERVER = 'cors-server:3000';
5
+ CORS_SERVER = '127.0.0.1.xip.io:9292';
6
6
 
7
7
  describe('CORS', function() {
8
8
  it('should allow access to dynamic resource', function(done) {
9
- return $.get("http://" + CORS_SERVER + "/", function(data, status, xhr) {
9
+ return $.get(`http://${CORS_SERVER}/`, function(data, status, xhr) {
10
10
  expect(data).to.eql('Hello world');
11
11
  return done();
12
12
  });
13
13
  });
14
14
  it('should allow PUT access to dynamic resource', function(done) {
15
- return $.ajax("http://" + CORS_SERVER + "/", {
15
+ return $.ajax(`http://${CORS_SERVER}/`, {
16
16
  type: 'PUT'
17
17
  }).done(function(data, textStatus, jqXHR) {
18
18
  expect(data).to.eql('Hello world');
19
19
  return done();
20
20
  });
21
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
+ });
22
30
  it('should allow HEAD access to dynamic resource', function(done) {
23
- return $.ajax("http://" + CORS_SERVER + "/", {
31
+ return $.ajax(`http://${CORS_SERVER}/`, {
24
32
  type: 'HEAD'
25
33
  }).done(function(data, textStatus, jqXHR) {
26
34
  expect(jqXHR.status).to.eql(200);
@@ -28,7 +36,7 @@
28
36
  });
29
37
  });
30
38
  it('should allow DELETE access to dynamic resource', function(done) {
31
- return $.ajax("http://" + CORS_SERVER + "/", {
39
+ return $.ajax(`http://${CORS_SERVER}/`, {
32
40
  type: 'DELETE'
33
41
  }).done(function(data, textStatus, jqXHR) {
34
42
  expect(data).to.eql('Hello world');
@@ -36,7 +44,7 @@
36
44
  });
37
45
  });
38
46
  it('should allow OPTIONS access to dynamic resource', function(done) {
39
- return $.ajax("http://" + CORS_SERVER + "/", {
47
+ return $.ajax(`http://${CORS_SERVER}/`, {
40
48
  type: 'OPTIONS'
41
49
  }).done(function(data, textStatus, jqXHR) {
42
50
  expect(jqXHR.status).to.eql(200);
@@ -44,7 +52,7 @@
44
52
  });
45
53
  });
46
54
  it('should allow access to static resource', function(done) {
47
- return $.get("http://" + CORS_SERVER + "/static.txt", function(data, status, xhr) {
55
+ return $.get(`http://${CORS_SERVER}/static.txt`, function(data, status, xhr) {
48
56
  expect($.trim(data)).to.eql("hello world");
49
57
  return done();
50
58
  });
@@ -52,7 +60,7 @@
52
60
  return it('should allow post resource', function(done) {
53
61
  return $.ajax({
54
62
  type: 'POST',
55
- url: "http://" + CORS_SERVER + "/cors",
63
+ url: `http://${CORS_SERVER}/cors`,
56
64
  beforeSend: function(xhr) {
57
65
  return xhr.setRequestHeader('X-Requested-With', 'XMLHTTPRequest');
58
66
  },
@@ -17,18 +17,57 @@ Rack::Test::Methods.class_eval do
17
17
  def_delegator :current_session, :options
18
18
  end
19
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
+
20
58
  describe Rack::Cors do
21
59
  include Rack::Test::Methods
22
60
 
23
61
  attr_accessor :cors_result
24
62
 
25
- def load_app(name)
63
+ def load_app(name, options = {})
26
64
  test = self
27
65
  Rack::Builder.new do
66
+ use CaptureResult, :holder => test
28
67
  eval File.read(File.dirname(__FILE__) + "/#{name}.ru")
68
+ use FakeProxy if options[:proxy]
29
69
  map('/') do
30
70
  run proc { |env|
31
- test.cors_result = env[Rack::Cors::ENV_KEY]
32
71
  [200, {'Content-Type' => 'text/html'}, ['success']]
33
72
  }
34
73
  end
@@ -38,84 +77,108 @@ describe Rack::Cors do
38
77
  let(:app) { load_app('test') }
39
78
 
40
79
  it 'should support simple CORS request' do
41
- cors_request
80
+ successful_cors_request
42
81
  cors_result.must_be :hit
43
82
  end
44
83
 
45
84
  it "should not return CORS headers if Origin header isn't present" do
46
85
  get '/'
47
- should_render_cors_failure
86
+ last_response.wont_render_cors_success
48
87
  cors_result.wont_be :hit
49
88
  end
50
89
 
51
90
  it 'should support OPTIONS CORS request' do
52
- cors_request '/options', :method => :options
91
+ successful_cors_request '/options', :method => :options
53
92
  end
54
93
 
55
94
  it 'should support regex origins configuration' do
56
- cors_request :origin => 'http://192.168.0.1:1234'
95
+ successful_cors_request :origin => 'http://192.168.0.1:1234'
57
96
  end
58
97
 
59
98
  it 'should support subdomain example' do
60
- cors_request :origin => 'http://subdomain.example.com'
99
+ successful_cors_request :origin => 'http://subdomain.example.com'
61
100
  end
62
101
 
63
102
  it 'should support proc origins configuration' do
64
- cors_request '/proc-origin', :origin => 'http://10.10.10.10:3000'
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
65
113
  end
66
114
 
67
115
  it 'should not mix up path rules across origins' do
68
116
  header 'Origin', 'http://10.10.10.10:3000'
69
117
  get '/' # / is configured in a separate rule block
70
- should_render_cors_failure
118
+ last_response.wont_render_cors_success
71
119
  end
72
120
 
73
121
  it 'should support alternative X-Origin header' do
74
122
  header 'X-Origin', 'http://localhost:3000'
75
123
  get '/'
76
- should_render_cors_success
124
+ last_response.must_render_cors_success
77
125
  end
78
126
 
79
127
  it 'should support expose header configuration' do
80
- cors_request '/expose_single_header'
128
+ successful_cors_request '/expose_single_header'
81
129
  last_response.headers['Access-Control-Expose-Headers'].must_equal 'expose-test'
82
130
  end
83
131
 
84
132
  it 'should support expose multiple header configuration' do
85
- cors_request '/expose_multiple_headers'
133
+ successful_cors_request '/expose_multiple_headers'
86
134
  last_response.headers['Access-Control-Expose-Headers'].must_equal 'expose-test-1, expose-test-2'
87
135
  end
88
136
 
89
137
  # Explanation: http://www.fastly.com/blog/best-practices-for-using-the-vary-header/
90
138
  it "should add Vary header if resource matches even if Origin header isn't present" do
91
139
  get '/'
92
- should_render_cors_failure
140
+ last_response.wont_render_cors_success
93
141
  last_response.headers['Vary'].must_equal 'Origin'
94
142
  end
95
143
 
96
144
  it "should add Vary header based on :vary option" do
97
- cors_request '/vary_test'
145
+ successful_cors_request '/vary_test'
98
146
  last_response.headers['Vary'].must_equal 'Origin, Host'
99
147
  end
100
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
+
101
164
  it 'should add Vary header if Access-Control-Allow-Origin header was added and if it is specific' do
102
- cors_request '/', :origin => "http://192.168.0.3:8080"
165
+ successful_cors_request '/', :origin => "http://192.168.0.3:8080"
103
166
  last_response.headers['Access-Control-Allow-Origin'].must_equal 'http://192.168.0.3:8080'
104
167
  last_response.headers['Vary'].wont_be_nil
105
168
  end
106
169
 
107
170
  it 'should add Vary header even if Access-Control-Allow-Origin header was added and it is generic (*)' do
108
- cors_request '/public_without_credentials', :origin => "http://192.168.1.3:8080"
171
+ successful_cors_request '/public_without_credentials', :origin => "http://192.168.1.3:8080"
109
172
  last_response.headers['Access-Control-Allow-Origin'].must_equal '*'
110
173
  last_response.headers['Vary'].must_equal 'Origin'
111
174
  end
112
175
 
113
176
  it 'should support multi allow configurations for the same resource' do
114
- cors_request '/multi-allow-config', :origin => "http://mucho-grande.com"
177
+ successful_cors_request '/multi-allow-config', :origin => "http://mucho-grande.com"
115
178
  last_response.headers['Access-Control-Allow-Origin'].must_equal 'http://mucho-grande.com'
116
179
  last_response.headers['Vary'].must_equal 'Origin'
117
180
 
118
- cors_request '/multi-allow-config', :origin => "http://192.168.1.3:8080"
181
+ successful_cors_request '/multi-allow-config', :origin => "http://192.168.1.3:8080"
119
182
  last_response.headers['Access-Control-Allow-Origin'].must_equal '*'
120
183
  last_response.headers['Vary'].must_equal 'Origin'
121
184
  end
@@ -128,15 +191,25 @@ describe Rack::Cors do
128
191
  it "should not apply CORS headers if it does not match conditional on resource" do
129
192
  header 'Origin', 'http://192.168.0.1:1234'
130
193
  get '/conditional'
131
- should_render_cors_failure
194
+ last_response.wont_render_cors_success
132
195
  end
133
196
 
134
197
  it "should apply CORS headers if it does match conditional on resource" do
135
198
  header 'X-OK', '1'
136
- cors_request '/conditional', :origin => 'http://192.168.0.1:1234'
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
137
210
  end
138
211
 
139
- describe 'logging' do
212
+ describe 'logging' do
140
213
  it 'should not log debug messages if debug option is false' do
141
214
  app = mock
142
215
  app.stubs(:call).returns(200, {}, [''])
@@ -199,79 +272,127 @@ describe Rack::Cors do
199
272
  cors.call({'HTTP_ORIGIN' => 'test.com'})
200
273
  end
201
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
202
288
  end
203
289
 
204
290
  describe 'preflight requests' do
205
291
  it 'should fail if origin is invalid' do
206
292
  preflight_request('http://allyourdataarebelongtous.com', '/')
207
- should_render_cors_failure
293
+ last_response.wont_render_cors_success
208
294
  cors_result.wont_be :hit
209
295
  cors_result.must_be :preflight
210
296
  end
211
297
 
212
298
  it 'should fail if Access-Control-Request-Method is not allowed' do
213
299
  preflight_request('http://localhost:3000', '/get-only', :method => :post)
214
- should_render_cors_failure
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
215
304
  end
216
305
 
217
306
  it 'should fail if header is not allowed' do
218
307
  preflight_request('http://localhost:3000', '/single_header', :headers => 'Fooey')
219
- should_render_cors_failure
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
220
312
  end
221
313
 
222
314
  it 'should allow any header if headers = :any' do
223
315
  preflight_request('http://localhost:3000', '/', :headers => 'Fooey')
224
- should_render_cors_success
316
+ last_response.must_render_cors_success
225
317
  end
226
318
 
227
319
  it 'should allow any method if methods = :any' do
228
320
  preflight_request('http://localhost:3000', '/', :methods => :any)
229
- should_render_cors_success
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
230
327
  end
231
328
 
232
329
  it 'should allow header case insensitive match' do
233
330
  preflight_request('http://localhost:3000', '/single_header', :headers => 'X-Domain-Token')
234
- should_render_cors_success
331
+ last_response.must_render_cors_success
235
332
  end
236
333
 
237
334
  it 'should allow multiple headers match' do
238
335
  # Webkit style
239
336
  preflight_request('http://localhost:3000', '/two_headers', :headers => 'X-Requested-With, X-Domain-Token')
240
- should_render_cors_success
337
+ last_response.must_render_cors_success
241
338
 
242
339
  # Gecko style
243
340
  preflight_request('http://localhost:3000', '/two_headers', :headers => 'x-requested-with,x-domain-token')
244
- should_render_cors_success
341
+ last_response.must_render_cors_success
245
342
  end
246
343
 
247
344
  it 'should * origin should allow any origin' do
248
345
  preflight_request('http://locohost:3000', '/public')
249
- should_render_cors_success
250
- last_response.headers['Access-Control-Allow-Origin'].must_equal 'http://locohost:3000'
346
+ last_response.must_render_cors_success
347
+ last_response.headers['Access-Control-Allow-Origin'].must_equal '*'
251
348
  end
252
349
 
253
350
  it 'should * origin should allow any origin, and set * if no credentials required' do
254
351
  preflight_request('http://locohost:3000', '/public_without_credentials')
255
- should_render_cors_success
352
+ last_response.must_render_cors_success
256
353
  last_response.headers['Access-Control-Allow-Origin'].must_equal '*'
257
354
  end
258
355
 
259
- it 'should "null" origin, allowed as "file://", returned as "null" in header' do
260
- preflight_request('null', '/')
261
- should_render_cors_success
262
- last_response.headers['Access-Control-Allow-Origin'].must_equal 'null'
263
- end
264
-
265
356
  it 'should return "file://" as header with "file://" as origin' do
266
357
  preflight_request('file://', '/')
267
- should_render_cors_success
358
+ last_response.must_render_cors_success
268
359
  last_response.headers['Access-Control-Allow-Origin'].must_equal 'file://'
269
360
  end
270
361
 
271
- it 'should return a Content-Type' do
272
- preflight_request('http://localhost:3000', '/')
273
- should_render_cors_success
274
- last_response.headers['Content-Type'].wont_be_nil
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
275
396
  end
276
397
  end
277
398
 
@@ -279,7 +400,7 @@ describe Rack::Cors do
279
400
  let(:app) { load_app("non_http") }
280
401
 
281
402
  it 'should support non http/https origins' do
282
- cors_request '/public', origin: 'content://com.company.app'
403
+ successful_cors_request '/public', origin: 'content://com.company.app'
283
404
  end
284
405
  end
285
406
 
@@ -308,19 +429,67 @@ describe Rack::Cors do
308
429
  end
309
430
  end
310
431
  map('/') do
311
- run ->(env) { [200, {'Content-Type' => 'text/plain', 'Access-Control-Allow-Origin' => 'http://foo.net'}, ['success']] }
432
+ run ->(env) { [200, {'Access-Control-Allow-Origin' => 'http://foo.net'}, ['success']] }
312
433
  end
313
434
  end
314
435
  end
315
436
 
316
437
  it "should return app header" do
317
- cors_request origin: "http://example.net"
438
+ successful_cors_request origin: "http://example.net"
318
439
  last_response.headers['Access-Control-Allow-Origin'].must_equal "http://foo.net"
319
440
  end
320
441
 
321
442
  it "should return original headers if in debug" do
322
- cors_request origin: "http://example.net"
323
- last_response.headers['X-Rack-CORS-Original-Access-Control-Allow-Origin'].must_equal "http://example.net"
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
324
493
  end
325
494
  end
326
495
 
@@ -333,7 +502,11 @@ describe Rack::Cors do
333
502
 
334
503
  header 'Origin', opts[:origin]
335
504
  current_session.__send__ opts[:method], path, {}, test: self
336
- should_render_cors_success
505
+ end
506
+
507
+ def successful_cors_request(*args)
508
+ cors_request(*args)
509
+ last_response.must_render_cors_success
337
510
  end
338
511
 
339
512
  def preflight_request(origin, path, opts = {})
@@ -346,12 +519,4 @@ describe Rack::Cors do
346
519
  end
347
520
  options path
348
521
  end
349
-
350
- def should_render_cors_success
351
- last_response.headers['Access-Control-Allow-Origin'].wont_be_nil
352
- end
353
-
354
- def should_render_cors_failure
355
- last_response.headers['Access-Control-Allow-Origin'].must_be_nil
356
- end
357
522
  end
@@ -55,4 +55,15 @@ describe Rack::Cors, 'DSL' do
55
55
 
56
56
  resources.first.allow_origin?('file://').must_equal true
57
57
  end
58
+
59
+ it 'should default credentials option to false' do
60
+ cors = Rack::Cors.new(Proc.new {}) do
61
+ allow do
62
+ origins 'example.net'
63
+ resource '/', :headers => :any
64
+ end
65
+ end
66
+ resources = cors.send :all_resources
67
+ resources.first.resources.first.credentials.must_equal false
68
+ end
58
69
  end
@@ -0,0 +1,8 @@
1
+ require 'rack/cors'
2
+
3
+ use Rack::Cors do
4
+ allow do
5
+ origins '*'
6
+ resource '/public', credentials: true
7
+ end
8
+ end
data/test/unit/test.ru CHANGED
@@ -19,6 +19,7 @@ use Rack::Cors do
19
19
  resource '/expose_multiple_headers', :expose => %w{expose-test-1 expose-test-2}
20
20
  resource '/conditional', :methods => :get, :if => proc { |env| !!env['HTTP_X_OK'] }
21
21
  resource '/vary_test', :methods => :get, :vary => %w{ Origin Host }
22
+ resource '/patch_test', :methods => :patch
22
23
  # resource '/file/at/*',
23
24
  # :methods => [:get, :post, :put, :delete],
24
25
  # :headers => :any,
@@ -32,9 +33,15 @@ use Rack::Cors do
32
33
  resource '/proc-origin'
33
34
  end
34
35
 
36
+ allow do
37
+ origins -> (source, env) { source.end_with?("10.10.10.10:3000") }
38
+ resource '/lambda-origin'
39
+ end
40
+
35
41
  allow do
36
42
  origins '*'
37
43
  resource '/public'
44
+ resource '/public/*'
38
45
  resource '/public_without_credentials', :credentials => false
39
46
  end
40
47
 
@@ -47,4 +54,9 @@ use Rack::Cors do
47
54
  origins '*'
48
55
  resource '/multi-allow-config', :max_age => 300, :credentials => false
49
56
  end
57
+
58
+ allow do
59
+ origins ''
60
+ resource '/blank-origin'
61
+ end
50
62
  end