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 +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)
|