rack-cors 0.4.1 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +5 -3
- data/CHANGELOG.md +73 -0
- data/Gemfile +1 -1
- data/README.md +23 -19
- data/lib/rack/cors/version.rb +1 -1
- data/lib/rack/cors.rb +125 -83
- data/rack-cors.gemspec +7 -6
- data/test/cors/test.cors.coffee +6 -1
- data/test/cors/test.cors.js +17 -9
- data/test/unit/cors_test.rb +222 -57
- data/test/unit/dsl_test.rb +11 -0
- data/test/unit/insecure.ru +8 -0
- data/test/unit/test.ru +12 -0
- metadata +47 -27
- data/CHANGELOG +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a12cdfc5aca2abf0cf86fb1ca217619fa6b40cad19721118016e064554f46ba0
|
4
|
+
data.tar.gz: 2874199b748909fdfd3e8ec601bd8620bc0235e60c66226259a79ff2404dbaf8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b71fe191ad396ab85e8c1966e979fa3516ee768bae6ed93fd1d43644eada8a455dbab00990ef22440ee7f82dab16a37b283897403d4eba674547bda1f0b86f5
|
7
|
+
data.tar.gz: a31481b3f6d9d45bdc522c444e923438f7f513a57796bf2cf6eaaa665d87f7479bf5f1e5f5ea8d380ce7194f0d3690823e1a681e55c17317cab29bf87b7a7303
|
data/.travis.yml
CHANGED
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
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'
|
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
|
30
|
+
# Rails 5
|
32
31
|
|
33
|
-
config.middleware.insert_before 0,
|
32
|
+
config.middleware.insert_before 0, Rack::Cors do
|
34
33
|
allow do
|
35
34
|
origins '*'
|
36
|
-
resource '*', :
|
35
|
+
resource '*', headers: :any, methods: [:get, :post, :options]
|
37
36
|
end
|
38
37
|
end
|
39
|
-
|
40
|
-
# Rails 5
|
41
38
|
|
42
|
-
|
39
|
+
# Rails 3/4
|
40
|
+
|
41
|
+
config.middleware.insert_before 0, "Rack::Cors" do
|
43
42
|
allow do
|
44
43
|
origins '*'
|
45
|
-
resource '*', :
|
44
|
+
resource '*', headers: :any, methods: [:get, :post, :options]
|
46
45
|
end
|
47
46
|
end
|
48
|
-
|
49
47
|
end
|
50
48
|
end
|
51
49
|
```
|
52
|
-
|
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
|
-
:
|
72
|
-
:
|
73
|
-
:
|
74
|
-
:
|
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/*', :
|
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
|
-
|
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.
|
data/lib/rack/cors/version.rb
CHANGED
data/lib/rack/cors.rb
CHANGED
@@ -2,13 +2,28 @@ require 'logger'
|
|
2
2
|
|
3
3
|
module Rack
|
4
4
|
class Cors
|
5
|
-
|
5
|
+
HTTP_ORIGIN = 'HTTP_ORIGIN'.freeze
|
6
|
+
HTTP_X_ORIGIN = 'HTTP_X_ORIGIN'.freeze
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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[
|
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[
|
70
|
+
if env[HTTP_ORIGIN]
|
54
71
|
debug(env) do
|
55
72
|
[ 'Incoming Headers:',
|
56
|
-
" Origin: #{env[
|
57
|
-
"
|
58
|
-
" Access-Control-Request-
|
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[
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
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[
|
78
|
-
#
|
79
|
-
vary_resource = resource_for_path(
|
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[
|
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[
|
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[
|
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[
|
129
|
-
env[
|
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
|
-
|
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
|
-
|
148
|
-
|
149
|
-
|
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
|
-
|
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[
|
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[
|
250
|
+
env[RACK_CORS] = r
|
221
251
|
end
|
222
252
|
|
223
|
-
def self.
|
253
|
+
def self.preflight(env)
|
224
254
|
r = Result.new
|
225
255
|
r.preflight = true
|
226
|
-
|
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.
|
283
|
+
@origins = args.flatten.reject{ |s| s == '' }.map do |n|
|
259
284
|
case n
|
260
|
-
when
|
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 ===
|
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 =
|
308
|
-
self.max_age = opts[:max_age] ||
|
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
|
-
|
340
|
-
|
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[
|
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?
|
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[
|
366
|
-
h.merge!('Access-Control-Allow-Headers' => env[
|
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
|
-
|
383
|
-
headers == :any
|
384
|
-
|
385
|
-
|
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.
|
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.
|
22
|
-
spec.add_development_dependency "
|
23
|
-
spec.add_development_dependency "
|
24
|
-
spec.add_development_dependency "
|
25
|
-
spec.add_development_dependency "
|
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
|
data/test/cors/test.cors.coffee
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
CORS_SERVER = '
|
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)
|