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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: aaa518c3408420a39bd3c41bd822cdda6309beb2
4
- data.tar.gz: 8fa4c9d5141e4d6c4df8600175f44ba6803ebe9f
2
+ SHA256:
3
+ metadata.gz: a12cdfc5aca2abf0cf86fb1ca217619fa6b40cad19721118016e064554f46ba0
4
+ data.tar.gz: 2874199b748909fdfd3e8ec601bd8620bc0235e60c66226259a79ff2404dbaf8
5
5
  SHA512:
6
- metadata.gz: 633c772b16e08fad8fb93a7d1bf5d62a398abb534a27ce0d44df843242c5e1077112e98b1eb7e2d3849da952fec1754cd2e8451195c1a2c86ac567d69652b859
7
- data.tar.gz: 8e0265d2d82db72ac68871dcf0eaf974809638d5a52514f99392b731fe09050ab07968c5e538a35d7bba2b7892cc62b3d6b7b401fe8a05c4648f5ad57a092abf
6
+ metadata.gz: 2b71fe191ad396ab85e8c1966e979fa3516ee768bae6ed93fd1d43644eada8a455dbab00990ef22440ee7f82dab16a37b283897403d4eba674547bda1f0b86f5
7
+ data.tar.gz: a31481b3f6d9d45bdc522c444e923438f7f513a57796bf2cf6eaaa665d87f7479bf5f1e5f5ea8d380ce7194f0d3690823e1a681e55c17317cab29bf87b7a7303
data/.travis.yml CHANGED
@@ -1,6 +1,8 @@
1
1
  language: ruby
2
2
  sudo: false
3
3
  rvm:
4
- - 2.2.5
5
- - 2.3.0
6
- - 2.3.1
4
+ - 2.2
5
+ - 2.3
6
+ - 2.4
7
+ - 2.5
8
+ - 2.6
data/CHANGELOG.md ADDED
@@ -0,0 +1,73 @@
1
+ # Change Log
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ ## 1.0.5 - 2019-11-14
5
+ ### Changed
6
+ - Update Gem spec to require rack >= 1.6.0
7
+
8
+ ## 1.0.4 - 2019-11-13
9
+ ### Security
10
+ - Escape and resolve path before evaluating resource rules (thanks to Colby Morgan)
11
+
12
+ ## 1.0.3 - 2019-03-24
13
+ ### Changed
14
+ - Don't send 'Content-Type' header with pre-flight requests
15
+ - Allow ruby array for vary header config
16
+
17
+ ## 1.0.2 - 2017-10-22
18
+ ### Fixed
19
+ - Automatically allow simple headers when headers are set
20
+
21
+ ## 1.0.1 - 2017-07-18
22
+ ### Fixed
23
+ - Allow lambda origin configuration
24
+
25
+ ## 1.0.0 - 2017-07-15
26
+ ### Security
27
+ - Don't implicitly accept 'null' origins when 'file://' is specified
28
+ (https://github.com/cyu/rack-cors/pull/134)
29
+ - Ignore '' origins (https://github.com/cyu/rack-cors/issues/139)
30
+ - Default credentials option on resources to false
31
+ (https://github.com/cyu/rack-cors/issues/95)
32
+ - Don't allow credentials option to be true if '*' is specified is origin
33
+ (https://github.com/cyu/rack-cors/pull/142)
34
+ - Don't reflect Origin header when '*' is specified as origin
35
+ (https://github.com/cyu/rack-cors/pull/142)
36
+
37
+ ### Fixed
38
+ - Don't respond immediately on non-matching preflight requests instead of
39
+ sending them through the app (https://github.com/cyu/rack-cors/pull/106)
40
+
41
+ ## 0.4.1 - 2017-02-01
42
+ ### Fixed
43
+ - Return miss result in X-Rack-CORS instead of incorrectly returning
44
+ preflight-hit
45
+
46
+ ## 0.4.0 - 2015-04-15
47
+ ### Changed
48
+ - Don't set HTTP_ORIGIN with HTTP_X_ORIGIN if nil
49
+
50
+ ### Added
51
+ - Calculate vary headers for non-CORS resources
52
+ - Support custom vary headers for resource
53
+ - Support :if option for resource
54
+ - Support :any as a possible value for :methods option
55
+
56
+ ### Fixed
57
+ - Don't symbolize incoming HTTP request methods
58
+
59
+ ## 0.3.1 - 2014-12-27
60
+ ### Changed
61
+ - Changed the env key to rack.cors to avoid Rack::Lint warnings
62
+
63
+ ## 0.3.0 - 2014-10-19
64
+ ### Added
65
+ - Added support for defining a logger with a Proc
66
+ - Return a X-Rack-CORS header when in debug mode detailing how Rack::Cors
67
+ processed a request
68
+ - Added support for non HTTP/HTTPS origins when just a domain is specified
69
+
70
+ ### Changed
71
+ - Changed the log level of the fallback logger to DEBUG
72
+ - Print warning when attempting to use :any as an allowed method
73
+ - Treat incoming `Origin: null` headers as file://
data/Gemfile CHANGED
@@ -3,4 +3,4 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in rack-cors.gemspec
4
4
  gemspec
5
5
 
6
- gem 'pry-byebug'
6
+ gem 'pry-byebug', '~> 3.6.0'
data/README.md CHANGED
@@ -13,7 +13,7 @@ Install the gem:
13
13
  Or in your Gemfile:
14
14
 
15
15
  ```ruby
16
- gem 'rack-cors', :require => 'rack/cors'
16
+ gem 'rack-cors'
17
17
  ```
18
18
 
19
19
 
@@ -25,31 +25,30 @@ Put something like the code below in `config/application.rb` of your Rails appli
25
25
  ```ruby
26
26
  module YourApp
27
27
  class Application < Rails::Application
28
-
29
28
  # ...
30
29
 
31
- # Rails 3/4
30
+ # Rails 5
32
31
 
33
- config.middleware.insert_before 0, "Rack::Cors" do
32
+ config.middleware.insert_before 0, Rack::Cors do
34
33
  allow do
35
34
  origins '*'
36
- resource '*', :headers => :any, :methods => [:get, :post, :options]
35
+ resource '*', headers: :any, methods: [:get, :post, :options]
37
36
  end
38
37
  end
39
-
40
- # Rails 5
41
38
 
42
- config.middleware.insert_before 0, Rack::Cors do
39
+ # Rails 3/4
40
+
41
+ config.middleware.insert_before 0, "Rack::Cors" do
43
42
  allow do
44
43
  origins '*'
45
- resource '*', :headers => :any, :methods => [:get, :post, :options]
44
+ resource '*', headers: :any, methods: [:get, :post, :options]
46
45
  end
47
46
  end
48
-
49
47
  end
50
48
  end
51
49
  ```
52
- Refer to [rails 3 example](https://github.com/cyu/rack-cors/tree/master/examples/rails3) and [rails 4 example](https://github.com/cyu/rack-cors/tree/master/examples/rails4) for more details.
50
+
51
+ We use `insert_before` to make sure `Rack::Cors` runs at the beginning of the stack to make sure it isn't interfered with by other middleware (see `Rack::Cache` note in **Common Gotchas** section). Check out the [rails 4 example](https://github.com/cyu/rack-cors/tree/master/examples/rails4) and [rails 3 example](https://github.com/cyu/rack-cors/tree/master/examples/rails3).
53
52
 
54
53
  See The [Rails Guide to Rack](http://guides.rubyonrails.org/rails_on_rack.html) for more details on rack middlewares or watch the [railscast](http://railscasts.com/episodes/151-rack-middleware).
55
54
 
@@ -68,16 +67,22 @@ use Rack::Cors do
68
67
 
69
68
  resource '/file/list_all/', :headers => 'x-domain-token'
70
69
  resource '/file/at/*',
71
- :methods => [:get, :post, :delete, :put, :patch, :options, :head],
72
- :headers => 'x-domain-token',
73
- :expose => ['Some-Custom-Response-Header'],
74
- :max_age => 600
70
+ methods: [:get, :post, :delete, :put, :patch, :options, :head],
71
+ headers: 'x-domain-token',
72
+ expose: ['Some-Custom-Response-Header'],
73
+ max_age: 600
75
74
  # headers to expose
76
75
  end
77
76
 
78
77
  allow do
79
78
  origins '*'
80
- resource '/public/*', :headers => :any, :methods => :get
79
+ resource '/public/*', headers: :any, methods: :get
80
+
81
+ # Only allow a request for a specific host
82
+ resource '/api/v1/*',
83
+ headers: :any,
84
+ methods: :get,
85
+ if: proc { |env| env['HTTP_HOST'] == 'api.example.com' }
81
86
  end
82
87
  end
83
88
  ```
@@ -98,13 +103,12 @@ Additionally, origins can be specified dynamically via a block of the following
98
103
  origins { |source, env| true || false }
99
104
  ```
100
105
 
101
- #### Resource
102
- A Resource path can be specified as exact string match (`/path/to/file.txt`) or with a '\*' wildcard (`/all/files/in/*`). A resource can take the following options:
106
+ A Resource path can be specified as exact string match (`/path/to/file.txt`) or with a '\*' wildcard (`/all/files/in/*`). To include all of a directory's files and the files in its subdirectories, use this form: `/assets/**/*`. A resource can take the following options:
103
107
 
104
108
  * **methods** (string or array or `:any`): The HTTP methods allowed for the resource.
105
109
  * **headers** (string or array or `:any`): The HTTP headers that will be allowed in the CORS resource request. Use `:any` to allow for any headers in the actual request.
106
110
  * **expose** (string or array): The HTTP headers in the resource response can be exposed to the client.
107
- * **credentials** (boolean): Sets the `Access-Control-Allow-Credentials` response header.
111
+ * **credentials** (boolean, default: `false`): Sets the `Access-Control-Allow-Credentials` response header. **Note:** If a wildcard (`*`) origin is specified, this option cannot be set to `true`. Read this [security article](http://web-in-security.blogspot.de/2017/07/cors-misconfigurations-on-large-scale.html) for more information.
108
112
  * **max_age** (number): Sets the `Access-Control-Max-Age` response header.
109
113
  * **if** (Proc): If the result of the proc is true, will process the request as a valid CORS request.
110
114
  * **vary** (string or array): A list of HTTP headers to add to the 'Vary' header.
@@ -1,5 +1,5 @@
1
1
  module Rack
2
2
  class Cors
3
- VERSION = "0.4.1"
3
+ VERSION = "1.0.5"
4
4
  end
5
5
  end
data/lib/rack/cors.rb CHANGED
@@ -2,13 +2,28 @@ require 'logger'
2
2
 
3
3
  module Rack
4
4
  class Cors
5
- ENV_KEY = 'rack.cors'.freeze
5
+ HTTP_ORIGIN = 'HTTP_ORIGIN'.freeze
6
+ HTTP_X_ORIGIN = 'HTTP_X_ORIGIN'.freeze
6
7
 
7
- ORIGIN_HEADER_KEY = 'HTTP_ORIGIN'.freeze
8
- ORIGIN_X_HEADER_KEY = 'HTTP_X_ORIGIN'.freeze
9
- PATH_INFO_HEADER_KEY = 'PATH_INFO'.freeze
10
- VARY_HEADER_KEY = 'Vary'.freeze
11
- DEFAULT_VARY_HEADERS = ['Origin'].freeze
8
+ HTTP_ACCESS_CONTROL_REQUEST_METHOD = 'HTTP_ACCESS_CONTROL_REQUEST_METHOD'.freeze
9
+ HTTP_ACCESS_CONTROL_REQUEST_HEADERS = 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS'.freeze
10
+
11
+ PATH_INFO = 'PATH_INFO'.freeze
12
+ REQUEST_METHOD = 'REQUEST_METHOD'.freeze
13
+
14
+ RACK_LOGGER = 'rack.logger'.freeze
15
+ RACK_CORS =
16
+ # retaining the old key for backwards compatibility
17
+ ENV_KEY = 'rack.cors'.freeze
18
+
19
+ OPTIONS = 'OPTIONS'.freeze
20
+ VARY = 'Vary'.freeze
21
+
22
+ DEFAULT_VARY_HEADERS = ['Origin'].freeze
23
+
24
+ # All CORS routes need to accept CORS simple headers at all times
25
+ # {https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers}
26
+ CORS_SIMPLE_HEADERS = ['accept', 'accept-language', 'content-language', 'content-type'].freeze
12
27
 
13
28
  def initialize(app, opts={}, &block)
14
29
  @app = app
@@ -47,36 +62,38 @@ module Rack
47
62
  end
48
63
 
49
64
  def call(env)
50
- env[ORIGIN_HEADER_KEY] ||= env[ORIGIN_X_HEADER_KEY] if env[ORIGIN_X_HEADER_KEY]
65
+ env[HTTP_ORIGIN] ||= env[HTTP_X_ORIGIN] if env[HTTP_X_ORIGIN]
66
+
67
+ path = evaluate_path(env)
51
68
 
52
69
  add_headers = nil
53
- if env[ORIGIN_HEADER_KEY]
70
+ if env[HTTP_ORIGIN]
54
71
  debug(env) do
55
72
  [ 'Incoming Headers:',
56
- " Origin: #{env[ORIGIN_HEADER_KEY]}",
57
- " Access-Control-Request-Method: #{env['HTTP_ACCESS_CONTROL_REQUEST_METHOD']}",
58
- " Access-Control-Request-Headers: #{env['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}"
73
+ " Origin: #{env[HTTP_ORIGIN]}",
74
+ " Path-Info: #{path}",
75
+ " Access-Control-Request-Method: #{env[HTTP_ACCESS_CONTROL_REQUEST_METHOD]}",
76
+ " Access-Control-Request-Headers: #{env[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]}"
59
77
  ].join("\n")
60
78
  end
61
- if env['REQUEST_METHOD'] == 'OPTIONS' and env['HTTP_ACCESS_CONTROL_REQUEST_METHOD']
62
- if headers = process_preflight(env)
63
- debug(env) do
64
- "Preflight Headers:\n" +
65
- headers.collect{|kv| " #{kv.join(': ')}"}.join("\n")
66
- end
67
- return [200, headers, []]
79
+ if env[REQUEST_METHOD] == OPTIONS and env[HTTP_ACCESS_CONTROL_REQUEST_METHOD]
80
+ headers = process_preflight(env, path)
81
+ debug(env) do
82
+ "Preflight Headers:\n" +
83
+ headers.collect{|kv| " #{kv.join(': ')}"}.join("\n")
68
84
  end
85
+ return [200, headers, []]
69
86
  else
70
- add_headers = process_cors(env)
87
+ add_headers = process_cors(env, path)
71
88
  end
72
89
  else
73
90
  Result.miss(env, Result::MISS_NO_ORIGIN)
74
91
  end
75
92
 
76
93
  # This call must be done BEFORE calling the app because for some reason
77
- # env[PATH_INFO_HEADER_KEY] gets changed after that and it won't match.
78
- # (At least in rails 4.1.6)
79
- vary_resource = resource_for_path(env[PATH_INFO_HEADER_KEY])
94
+ # env[PATH_INFO] gets changed after that and it won't match. (At least
95
+ # in rails 4.1.6)
96
+ vary_resource = resource_for_path(path)
80
97
 
81
98
  status, headers, body = @app.call env
82
99
 
@@ -95,16 +112,16 @@ module Rack
95
112
  # response to be different depending on the Origin header value.
96
113
  # Better explained here: http://www.fastly.com/blog/best-practices-for-using-the-vary-header/
97
114
  if vary_resource
98
- vary = headers[VARY_HEADER_KEY]
115
+ vary = headers[VARY]
99
116
  cors_vary_headers = if vary_resource.vary_headers && vary_resource.vary_headers.any?
100
117
  vary_resource.vary_headers
101
118
  else
102
119
  DEFAULT_VARY_HEADERS
103
120
  end
104
- headers[VARY_HEADER_KEY] = ((vary ? vary.split(/,\s*/) : []) + cors_vary_headers).uniq.join(', ')
121
+ headers[VARY] = ((vary ? ([vary].flatten.map { |v| v.split(/,\s*/) }.flatten) : []) + cors_vary_headers).uniq.join(', ')
105
122
  end
106
123
 
107
- if debug? && result = env[ENV_KEY]
124
+ if debug? && result = env[RACK_CORS]
108
125
  result.append_header(headers)
109
126
  end
110
127
 
@@ -122,36 +139,41 @@ module Rack
122
139
  @logger_proc = nil
123
140
  logger_proc.call
124
141
 
125
- elsif defined?(Rails) && Rails.logger
142
+ elsif defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
126
143
  Rails.logger
127
144
 
128
- elsif env['rack.logger']
129
- env['rack.logger']
145
+ elsif env[RACK_LOGGER]
146
+ env[RACK_LOGGER]
130
147
 
131
148
  else
132
149
  ::Logger.new(STDOUT).tap { |logger| logger.level = ::Logger::Severity::DEBUG }
133
150
  end
134
151
  end
135
152
 
153
+ def evaluate_path(env)
154
+ path = env[PATH_INFO]
155
+ path = Rack::Utils.clean_path_info(Rack::Utils.unescape_path(path)) if path
156
+ path
157
+ end
158
+
136
159
  def all_resources
137
160
  @all_resources ||= []
138
161
  end
139
162
 
140
- def process_preflight(env)
141
- resource, error = match_resource(env)
142
- if resource
143
- Result.preflight_hit(env)
144
- preflight = resource.process_preflight(env)
145
- preflight
163
+ def process_preflight(env, path)
164
+ result = Result.preflight(env)
146
165
 
147
- else
148
- Result.preflight_miss(env, error)
149
- nil
166
+ resource, error = match_resource(path, env)
167
+ unless resource
168
+ result.miss(error)
169
+ return {}
150
170
  end
171
+
172
+ return resource.process_preflight(env, result)
151
173
  end
152
174
 
153
- def process_cors(env)
154
- resource, error = match_resource(env)
175
+ def process_cors(env, path)
176
+ resource, error = match_resource(path, env)
155
177
  if resource
156
178
  Result.hit(env)
157
179
  cors = resource.to_headers(env)
@@ -172,9 +194,8 @@ module Rack
172
194
  nil
173
195
  end
174
196
 
175
- def match_resource(env)
176
- path = env[PATH_INFO_HEADER_KEY]
177
- origin = env[ORIGIN_HEADER_KEY]
197
+ def match_resource(path, env)
198
+ origin = env[HTTP_ORIGIN]
178
199
 
179
200
  origin_matched = false
180
201
  all_resources.each do |r|
@@ -195,6 +216,10 @@ module Rack
195
216
  MISS_NO_ORIGIN = 'no-origin'.freeze
196
217
  MISS_NO_PATH = 'no-path'.freeze
197
218
 
219
+ MISS_NO_METHOD = 'no-method'.freeze
220
+ MISS_DENY_METHOD = 'deny-method'.freeze
221
+ MISS_DENY_HEADER = 'deny-header'.freeze
222
+
198
223
  attr_accessor :preflight, :hit, :miss_reason
199
224
 
200
225
  def hit?
@@ -205,11 +230,16 @@ module Rack
205
230
  !!preflight
206
231
  end
207
232
 
233
+ def miss(reason)
234
+ self.hit = false
235
+ self.miss_reason = reason
236
+ end
237
+
208
238
  def self.hit(env)
209
239
  r = Result.new
210
240
  r.preflight = false
211
241
  r.hit = true
212
- env[ENV_KEY] = r
242
+ env[RACK_CORS] = r
213
243
  end
214
244
 
215
245
  def self.miss(env, reason)
@@ -217,23 +247,15 @@ module Rack
217
247
  r.preflight = false
218
248
  r.hit = false
219
249
  r.miss_reason = reason
220
- env[ENV_KEY] = r
250
+ env[RACK_CORS] = r
221
251
  end
222
252
 
223
- def self.preflight_hit(env)
253
+ def self.preflight(env)
224
254
  r = Result.new
225
255
  r.preflight = true
226
- r.hit = true
227
- env[ENV_KEY] = r
256
+ env[RACK_CORS] = r
228
257
  end
229
258
 
230
- def self.preflight_miss(env, reason)
231
- r = Result.new
232
- r.preflight = true
233
- r.hit = false
234
- r.miss_reason = reason
235
- env[ENV_KEY] = r
236
- end
237
259
 
238
260
  def append_header(headers)
239
261
  headers[HEADER_KEY] = if hit?
@@ -248,6 +270,9 @@ module Rack
248
270
  end
249
271
 
250
272
  class Resources
273
+
274
+ attr_reader :resources
275
+
251
276
  def initialize
252
277
  @origins = []
253
278
  @resources = []
@@ -255,9 +280,10 @@ module Rack
255
280
  end
256
281
 
257
282
  def origins(*args, &blk)
258
- @origins = args.flatten.collect do |n|
283
+ @origins = args.flatten.reject{ |s| s == '' }.map do |n|
259
284
  case n
260
- when Regexp,
285
+ when Proc,
286
+ Regexp,
261
287
  /^https?:\/\//,
262
288
  'file://' then n
263
289
  when '*' then @public_resources = true; n
@@ -278,13 +304,11 @@ module Rack
278
304
  def allow_origin?(source,env = {})
279
305
  return true if public_resources?
280
306
 
281
- effective_source = (source == 'null' ? 'file://' : source)
282
-
283
307
  return !! @origins.detect do |origin|
284
308
  if origin.is_a?(Proc)
285
309
  origin.call(source,env)
286
310
  else
287
- origin === effective_source
311
+ origin === source
288
312
  end
289
313
  end
290
314
  end
@@ -300,12 +324,21 @@ module Rack
300
324
  end
301
325
 
302
326
  class Resource
327
+ class CorsMisconfigurationError < StandardError
328
+ def message
329
+ "Allowing credentials for wildcard origins is insecure."\
330
+ " Please specify more restrictive origins or set 'credentials' to false in your CORS configuration."
331
+ end
332
+ end
333
+
303
334
  attr_accessor :path, :methods, :headers, :expose, :max_age, :credentials, :pattern, :if_proc, :vary_headers
304
335
 
305
336
  def initialize(public_resource, path, opts={})
337
+ raise CorsMisconfigurationError if public_resource && opts[:credentials] == true
338
+
306
339
  self.path = path
307
- self.credentials = opts[:credentials].nil? ? true : opts[:credentials]
308
- self.max_age = opts[:max_age] || 1728000
340
+ self.credentials = public_resource ? false : (opts[:credentials] == true)
341
+ self.max_age = opts[:max_age] || 7200
309
342
  self.pattern = compile(path)
310
343
  self.if_proc = opts[:if]
311
344
  self.vary_headers = opts[:vary] && [opts[:vary]].flatten
@@ -323,7 +356,7 @@ module Rack
323
356
  else
324
357
  ensure_enum(opts[:methods]) || [:get]
325
358
  end.map{|e| e.to_s }
326
-
359
+
327
360
  self.expose = opts[:expose] ? [opts[:expose]].flatten : nil
328
361
  end
329
362
 
@@ -335,14 +368,29 @@ module Rack
335
368
  matches_path?(path) && (if_proc.nil? || if_proc.call(env))
336
369
  end
337
370
 
338
- def process_preflight(env)
339
- return nil if invalid_method_request?(env) || invalid_headers_request?(env)
340
- {'Content-Type' => 'text/plain'}.merge(to_preflight_headers(env))
371
+ def process_preflight(env, result)
372
+ headers = {}
373
+
374
+ request_method = env[HTTP_ACCESS_CONTROL_REQUEST_METHOD]
375
+ if request_method.nil?
376
+ result.miss(Result::MISS_NO_METHOD) and return headers
377
+ end
378
+ if !methods.include?(request_method.downcase)
379
+ result.miss(Result::MISS_DENY_METHOD) and return headers
380
+ end
381
+
382
+ request_headers = env[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]
383
+ if request_headers && !allow_headers?(request_headers)
384
+ result.miss(Result::MISS_DENY_HEADER) and return headers
385
+ end
386
+
387
+ result.hit = true
388
+ headers.merge(to_preflight_headers(env))
341
389
  end
342
390
 
343
391
  def to_headers(env)
344
392
  h = {
345
- 'Access-Control-Allow-Origin' => origin_for_response_header(env[ORIGIN_HEADER_KEY]),
393
+ 'Access-Control-Allow-Origin' => origin_for_response_header(env[HTTP_ORIGIN]),
346
394
  'Access-Control-Allow-Methods' => methods.collect{|m| m.to_s.upcase}.join(', '),
347
395
  'Access-Control-Expose-Headers' => expose.nil? ? '' : expose.join(', '),
348
396
  'Access-Control-Max-Age' => max_age.to_s }
@@ -356,33 +404,27 @@ module Rack
356
404
  end
357
405
 
358
406
  def origin_for_response_header(origin)
359
- return '*' if public_resource? && !credentials
407
+ return '*' if public_resource?
360
408
  origin
361
409
  end
362
410
 
363
411
  def to_preflight_headers(env)
364
412
  h = to_headers(env)
365
- if env['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']
366
- h.merge!('Access-Control-Allow-Headers' => env['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])
413
+ if env[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]
414
+ h.merge!('Access-Control-Allow-Headers' => env[HTTP_ACCESS_CONTROL_REQUEST_HEADERS])
367
415
  end
368
416
  h
369
417
  end
370
418
 
371
- def invalid_method_request?(env)
372
- request_method = env['HTTP_ACCESS_CONTROL_REQUEST_METHOD']
373
- request_method.nil? || !methods.include?(request_method.downcase)
374
- end
375
-
376
- def invalid_headers_request?(env)
377
- request_headers = env['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']
378
- request_headers && !allow_headers?(request_headers)
379
- end
380
-
381
419
  def allow_headers?(request_headers)
382
- return false if headers.nil?
383
- headers == :any || begin
384
- request_headers = request_headers.split(/,\s*/) if request_headers.kind_of?(String)
385
- request_headers.all?{|h| headers.include?(h.downcase)}
420
+ headers = self.headers || []
421
+ if headers == :any
422
+ return true
423
+ end
424
+ request_headers = request_headers.split(/,\s*/) if request_headers.kind_of?(String)
425
+ request_headers.all? do |header|
426
+ header = header.downcase
427
+ CORS_SIMPLE_HEADERS.include?(header) || headers.include?(header)
386
428
  end
387
429
  end
388
430
 
data/rack-cors.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Rack::Cors::VERSION
9
9
  spec.authors = ["Calvin Yu"]
10
10
  spec.email = ["me@sourcebender.com"]
11
- spec.description = %q{Middleware that will make Rack-based apps CORS compatible. Read more here: http://blog.sourcebender.com/2010/06/09/introducin-rack-cors.html. Fork the project here: https://github.com/cyu/rack-cors}
11
+ spec.description = %q{Middleware that will make Rack-based apps CORS compatible. Fork the project here: https://github.com/cyu/rack-cors}
12
12
  spec.summary = %q{Middleware for enabling Cross-Origin Resource Sharing in Rack apps}
13
13
  spec.homepage = "https://github.com/cyu/rack-cors"
14
14
  spec.license = "MIT"
@@ -18,9 +18,10 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.3"
22
- spec.add_development_dependency "rake"
23
- spec.add_development_dependency "minitest", ">= 5.3.0"
24
- spec.add_development_dependency "mocha", ">= 0.14.0"
25
- spec.add_development_dependency "rack-test", ">= 0"
21
+ spec.add_dependency "rack", ">= 1.6.0"
22
+ spec.add_development_dependency "bundler", ">= 1.16.0", '< 3'
23
+ spec.add_development_dependency "rake", "~> 12.3.0"
24
+ spec.add_development_dependency "minitest", "~> 5.11.0"
25
+ spec.add_development_dependency "mocha", "~> 1.6.0"
26
+ spec.add_development_dependency "rack-test", "~> 1.1.0"
26
27
  end
@@ -1,4 +1,4 @@
1
- CORS_SERVER = 'cors-server:3000'
1
+ CORS_SERVER = '127.0.0.1.xip.io:9292'
2
2
 
3
3
  describe 'CORS', ->
4
4
 
@@ -12,6 +12,11 @@ describe 'CORS', ->
12
12
  expect(data).to.eql('Hello world')
13
13
  done()
14
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
+
15
20
  it 'should allow HEAD access to dynamic resource', (done) ->
16
21
  $.ajax("http://#{CORS_SERVER}/", type: 'HEAD').done (data, textStatus, jqXHR) ->
17
22
  expect(jqXHR.status).to.eql(200)