rack-cors 1.0.0 → 2.0.1

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

Potentially problematic release.


This version of rack-cors might be problematic. Click here for more details.

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