rack-cors 1.0.2 → 2.0.0
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/.rubocop.yml +31 -0
- data/.travis.yml +10 -3
- data/{CHANGELOG → CHANGELOG.md} +39 -0
- data/Gemfile +3 -1
- data/README.md +67 -42
- data/Rakefile +5 -4
- data/lib/rack/cors/resource.rb +132 -0
- data/lib/rack/cors/resources/cors_misconfiguration_error.rb +14 -0
- data/lib/rack/cors/resources.rb +62 -0
- data/lib/rack/cors/result.rb +63 -0
- data/lib/rack/cors/version.rb +3 -1
- data/lib/rack/cors.rb +110 -345
- data/rack-cors.gemspec +20 -16
- data/test/.rubocop.yml +8 -0
- data/test/cors/test.cors.coffee +9 -2
- data/test/cors/test.cors.js +22 -10
- data/test/unit/cors_test.rb +209 -151
- data/test/unit/dsl_test.rb +30 -29
- data/test/unit/insecure.ru +2 -0
- data/test/unit/non_http.ru +2 -0
- data/test/unit/test.ru +25 -19
- metadata +81 -28
data/lib/rack/cors.rb
CHANGED
@@ -1,38 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'logger'
|
4
|
+
require_relative 'cors/resources'
|
5
|
+
require_relative 'cors/resource'
|
6
|
+
require_relative 'cors/result'
|
7
|
+
require_relative 'cors/version'
|
2
8
|
|
3
9
|
module Rack
|
4
10
|
class Cors
|
5
|
-
HTTP_ORIGIN = 'HTTP_ORIGIN'
|
6
|
-
HTTP_X_ORIGIN = 'HTTP_X_ORIGIN'
|
11
|
+
HTTP_ORIGIN = 'HTTP_ORIGIN'
|
12
|
+
HTTP_X_ORIGIN = 'HTTP_X_ORIGIN'
|
7
13
|
|
8
|
-
HTTP_ACCESS_CONTROL_REQUEST_METHOD = 'HTTP_ACCESS_CONTROL_REQUEST_METHOD'
|
9
|
-
HTTP_ACCESS_CONTROL_REQUEST_HEADERS = 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS'
|
14
|
+
HTTP_ACCESS_CONTROL_REQUEST_METHOD = 'HTTP_ACCESS_CONTROL_REQUEST_METHOD'
|
15
|
+
HTTP_ACCESS_CONTROL_REQUEST_HEADERS = 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS'
|
10
16
|
|
11
|
-
PATH_INFO = 'PATH_INFO'
|
12
|
-
REQUEST_METHOD = 'REQUEST_METHOD'
|
17
|
+
PATH_INFO = 'PATH_INFO'
|
18
|
+
REQUEST_METHOD = 'REQUEST_METHOD'
|
13
19
|
|
14
|
-
RACK_LOGGER = 'rack.logger'
|
20
|
+
RACK_LOGGER = 'rack.logger'
|
15
21
|
RACK_CORS =
|
16
|
-
|
17
|
-
|
22
|
+
# retaining the old key for backwards compatibility
|
23
|
+
ENV_KEY = 'rack.cors'
|
18
24
|
|
19
|
-
OPTIONS
|
20
|
-
VARY = 'Vary'.freeze
|
21
|
-
CONTENT_TYPE = 'Content-Type'.freeze
|
22
|
-
TEXT_PLAIN = 'text/plain'.freeze
|
25
|
+
OPTIONS = 'OPTIONS'
|
23
26
|
|
24
27
|
DEFAULT_VARY_HEADERS = ['Origin'].freeze
|
25
28
|
|
26
|
-
|
27
|
-
# {https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers}
|
28
|
-
CORS_SIMPLE_HEADERS = ['accept', 'accept-language', 'content-language', 'content-type'].freeze
|
29
|
-
|
30
|
-
def initialize(app, opts={}, &block)
|
29
|
+
def initialize(app, opts = {}, &block)
|
31
30
|
@app = app
|
32
31
|
@debug_mode = !!opts[:debug]
|
33
32
|
@logger = @logger_proc = nil
|
34
33
|
|
35
|
-
|
34
|
+
logger = opts[:logger]
|
35
|
+
if logger
|
36
36
|
if logger.respond_to? :call
|
37
37
|
@logger_proc = opts[:logger]
|
38
38
|
else
|
@@ -40,12 +40,12 @@ module Rack
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
43
|
+
return unless block_given?
|
44
|
+
|
45
|
+
if block.arity == 1
|
46
|
+
block.call(self)
|
47
|
+
else
|
48
|
+
instance_eval(&block)
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
@@ -66,24 +66,29 @@ module Rack
|
|
66
66
|
def call(env)
|
67
67
|
env[HTTP_ORIGIN] ||= env[HTTP_X_ORIGIN] if env[HTTP_X_ORIGIN]
|
68
68
|
|
69
|
+
path = evaluate_path(env)
|
70
|
+
|
69
71
|
add_headers = nil
|
70
72
|
if env[HTTP_ORIGIN]
|
71
73
|
debug(env) do
|
72
|
-
[
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
74
|
+
['Incoming Headers:',
|
75
|
+
" Origin: #{env[HTTP_ORIGIN]}",
|
76
|
+
" Path-Info: #{path}",
|
77
|
+
" Access-Control-Request-Method: #{env[HTTP_ACCESS_CONTROL_REQUEST_METHOD]}",
|
78
|
+
" Access-Control-Request-Headers: #{env[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]}"].join("\n")
|
77
79
|
end
|
78
|
-
|
79
|
-
|
80
|
+
|
81
|
+
if env[REQUEST_METHOD] == OPTIONS && env[HTTP_ACCESS_CONTROL_REQUEST_METHOD]
|
82
|
+
return [400, {}, []] unless Rack::Utils.valid_path?(path)
|
83
|
+
|
84
|
+
headers = process_preflight(env, path)
|
80
85
|
debug(env) do
|
81
86
|
"Preflight Headers:\n" +
|
82
|
-
|
87
|
+
headers.collect { |kv| " #{kv.join(': ')}" }.join("\n")
|
83
88
|
end
|
84
89
|
return [200, headers, []]
|
85
90
|
else
|
86
|
-
add_headers = process_cors(env)
|
91
|
+
add_headers = process_cors(env, path)
|
87
92
|
end
|
88
93
|
else
|
89
94
|
Result.miss(env, Result::MISS_NO_ORIGIN)
|
@@ -92,7 +97,7 @@ module Rack
|
|
92
97
|
# This call must be done BEFORE calling the app because for some reason
|
93
98
|
# env[PATH_INFO] gets changed after that and it won't match. (At least
|
94
99
|
# in rails 4.1.6)
|
95
|
-
vary_resource = resource_for_path(
|
100
|
+
vary_resource = resource_for_path(path)
|
96
101
|
|
97
102
|
status, headers, body = @app.call env
|
98
103
|
|
@@ -100,9 +105,7 @@ module Rack
|
|
100
105
|
headers = add_headers.merge(headers)
|
101
106
|
debug(env) do
|
102
107
|
add_headers.each_pair do |key, value|
|
103
|
-
if headers.
|
104
|
-
headers["X-Rack-CORS-Original-#{key}"] = value
|
105
|
-
end
|
108
|
+
headers["x-rack-cors-original-#{key}"] = value if headers.key?(key)
|
106
109
|
end
|
107
110
|
end
|
108
111
|
end
|
@@ -111,344 +114,106 @@ module Rack
|
|
111
114
|
# response to be different depending on the Origin header value.
|
112
115
|
# Better explained here: http://www.fastly.com/blog/best-practices-for-using-the-vary-header/
|
113
116
|
if vary_resource
|
114
|
-
vary = headers[
|
115
|
-
cors_vary_headers = if vary_resource.vary_headers
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
headers[
|
117
|
+
vary = headers['vary']
|
118
|
+
cors_vary_headers = if vary_resource.vary_headers&.any?
|
119
|
+
vary_resource.vary_headers
|
120
|
+
else
|
121
|
+
DEFAULT_VARY_HEADERS
|
122
|
+
end
|
123
|
+
headers['vary'] = ((vary ? [vary].flatten.map { |v| v.split(/,\s*/) }.flatten : []) + cors_vary_headers).uniq.join(', ')
|
121
124
|
end
|
122
125
|
|
123
|
-
|
124
|
-
|
125
|
-
end
|
126
|
+
result = env[ENV_KEY]
|
127
|
+
result.append_header(headers) if debug? && result
|
126
128
|
|
127
129
|
[status, headers, body]
|
128
130
|
end
|
129
131
|
|
130
132
|
protected
|
131
|
-
def debug(env, message = nil, &block)
|
132
|
-
(@logger || select_logger(env)).debug(message, &block) if debug?
|
133
|
-
end
|
134
133
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
@logger_proc = nil
|
139
|
-
logger_proc.call
|
134
|
+
def debug(env, message = nil, &block)
|
135
|
+
(@logger || select_logger(env)).debug(message, &block) if debug?
|
136
|
+
end
|
140
137
|
|
141
|
-
|
142
|
-
|
138
|
+
def select_logger(env)
|
139
|
+
@logger = if @logger_proc
|
140
|
+
logger_proc = @logger_proc
|
141
|
+
@logger_proc = nil
|
142
|
+
logger_proc.call
|
143
143
|
|
144
|
-
|
145
|
-
|
144
|
+
elsif defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
|
145
|
+
Rails.logger
|
146
146
|
|
147
|
-
|
148
|
-
|
149
|
-
end
|
150
|
-
end
|
147
|
+
elsif env[RACK_LOGGER]
|
148
|
+
env[RACK_LOGGER]
|
151
149
|
|
152
|
-
|
153
|
-
|
154
|
-
|
150
|
+
else
|
151
|
+
::Logger.new(STDOUT).tap { |logger| logger.level = ::Logger::Severity::DEBUG }
|
152
|
+
end
|
153
|
+
end
|
155
154
|
|
156
|
-
|
157
|
-
|
155
|
+
def evaluate_path(env)
|
156
|
+
path = env[PATH_INFO]
|
158
157
|
|
159
|
-
|
160
|
-
|
161
|
-
result.miss(error)
|
162
|
-
return {}
|
163
|
-
end
|
158
|
+
if path
|
159
|
+
path = Rack::Utils.unescape_path(path)
|
164
160
|
|
165
|
-
|
161
|
+
path = Rack::Utils.clean_path_info(path) if Rack::Utils.valid_path?(path)
|
166
162
|
end
|
167
163
|
|
168
|
-
|
169
|
-
|
170
|
-
if resource
|
171
|
-
Result.hit(env)
|
172
|
-
cors = resource.to_headers(env)
|
173
|
-
cors
|
174
|
-
|
175
|
-
else
|
176
|
-
Result.miss(env, error)
|
177
|
-
nil
|
178
|
-
end
|
179
|
-
end
|
164
|
+
path
|
165
|
+
end
|
180
166
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
return found
|
185
|
-
end
|
186
|
-
end
|
187
|
-
nil
|
188
|
-
end
|
167
|
+
def all_resources
|
168
|
+
@all_resources ||= []
|
169
|
+
end
|
189
170
|
|
190
|
-
|
191
|
-
|
192
|
-
origin = env[HTTP_ORIGIN]
|
193
|
-
|
194
|
-
origin_matched = false
|
195
|
-
all_resources.each do |r|
|
196
|
-
if r.allow_origin?(origin, env)
|
197
|
-
origin_matched = true
|
198
|
-
if found = r.match_resource(path, env)
|
199
|
-
return [found, nil]
|
200
|
-
end
|
201
|
-
end
|
202
|
-
end
|
171
|
+
def process_preflight(env, path)
|
172
|
+
result = Result.preflight(env)
|
203
173
|
|
204
|
-
|
174
|
+
resource, error = match_resource(path, env)
|
175
|
+
unless resource
|
176
|
+
result.miss(error)
|
177
|
+
return {}
|
205
178
|
end
|
206
179
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
MISS_NO_ORIGIN = 'no-origin'.freeze
|
211
|
-
MISS_NO_PATH = 'no-path'.freeze
|
212
|
-
|
213
|
-
MISS_NO_METHOD = 'no-method'.freeze
|
214
|
-
MISS_DENY_METHOD = 'deny-method'.freeze
|
215
|
-
MISS_DENY_HEADER = 'deny-header'.freeze
|
216
|
-
|
217
|
-
attr_accessor :preflight, :hit, :miss_reason
|
218
|
-
|
219
|
-
def hit?
|
220
|
-
!!hit
|
221
|
-
end
|
222
|
-
|
223
|
-
def preflight?
|
224
|
-
!!preflight
|
225
|
-
end
|
226
|
-
|
227
|
-
def miss(reason)
|
228
|
-
self.hit = false
|
229
|
-
self.miss_reason = reason
|
230
|
-
end
|
231
|
-
|
232
|
-
def self.hit(env)
|
233
|
-
r = Result.new
|
234
|
-
r.preflight = false
|
235
|
-
r.hit = true
|
236
|
-
env[RACK_CORS] = r
|
237
|
-
end
|
238
|
-
|
239
|
-
def self.miss(env, reason)
|
240
|
-
r = Result.new
|
241
|
-
r.preflight = false
|
242
|
-
r.hit = false
|
243
|
-
r.miss_reason = reason
|
244
|
-
env[RACK_CORS] = r
|
245
|
-
end
|
246
|
-
|
247
|
-
def self.preflight(env)
|
248
|
-
r = Result.new
|
249
|
-
r.preflight = true
|
250
|
-
env[RACK_CORS] = r
|
251
|
-
end
|
180
|
+
resource.process_preflight(env, result)
|
181
|
+
end
|
252
182
|
|
183
|
+
def process_cors(env, path)
|
184
|
+
resource, error = match_resource(path, env)
|
185
|
+
if resource
|
186
|
+
Result.hit(env)
|
187
|
+
cors = resource.to_headers(env)
|
188
|
+
cors
|
253
189
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
else
|
258
|
-
[
|
259
|
-
(preflight? ? 'preflight-miss' : 'miss'),
|
260
|
-
miss_reason
|
261
|
-
].join('; ')
|
262
|
-
end
|
263
|
-
end
|
190
|
+
else
|
191
|
+
Result.miss(env, error)
|
192
|
+
nil
|
264
193
|
end
|
194
|
+
end
|
265
195
|
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
def initialize
|
271
|
-
@origins = []
|
272
|
-
@resources = []
|
273
|
-
@public_resources = false
|
274
|
-
end
|
275
|
-
|
276
|
-
def origins(*args, &blk)
|
277
|
-
@origins = args.flatten.reject{ |s| s == '' }.map do |n|
|
278
|
-
case n
|
279
|
-
when Proc,
|
280
|
-
Regexp,
|
281
|
-
/^https?:\/\//,
|
282
|
-
'file://' then n
|
283
|
-
when '*' then @public_resources = true; n
|
284
|
-
else Regexp.compile("^[a-z][a-z0-9.+-]*:\\\/\\\/#{Regexp.quote(n)}$")
|
285
|
-
end
|
286
|
-
end.flatten
|
287
|
-
@origins.push(blk) if blk
|
288
|
-
end
|
289
|
-
|
290
|
-
def resource(path, opts={})
|
291
|
-
@resources << Resource.new(public_resources?, path, opts)
|
292
|
-
end
|
293
|
-
|
294
|
-
def public_resources?
|
295
|
-
@public_resources
|
296
|
-
end
|
297
|
-
|
298
|
-
def allow_origin?(source,env = {})
|
299
|
-
return true if public_resources?
|
300
|
-
|
301
|
-
return !! @origins.detect do |origin|
|
302
|
-
if origin.is_a?(Proc)
|
303
|
-
origin.call(source,env)
|
304
|
-
else
|
305
|
-
origin === source
|
306
|
-
end
|
307
|
-
end
|
308
|
-
end
|
309
|
-
|
310
|
-
def match_resource(path, env)
|
311
|
-
@resources.detect { |r| r.match?(path, env) }
|
312
|
-
end
|
313
|
-
|
314
|
-
def resource_for_path(path)
|
315
|
-
@resources.detect { |r| r.matches_path?(path) }
|
316
|
-
end
|
317
|
-
|
196
|
+
def resource_for_path(path_info)
|
197
|
+
all_resources.each do |r|
|
198
|
+
found = r.resource_for_path(path_info)
|
199
|
+
return found if found
|
318
200
|
end
|
201
|
+
nil
|
202
|
+
end
|
319
203
|
|
320
|
-
|
321
|
-
|
322
|
-
def message
|
323
|
-
"Allowing credentials for wildcard origins is insecure."\
|
324
|
-
" Please specify more restrictive origins or set 'credentials' to false in your CORS configuration."
|
325
|
-
end
|
326
|
-
end
|
327
|
-
|
328
|
-
attr_accessor :path, :methods, :headers, :expose, :max_age, :credentials, :pattern, :if_proc, :vary_headers
|
329
|
-
|
330
|
-
def initialize(public_resource, path, opts={})
|
331
|
-
raise CorsMisconfigurationError if public_resource && opts[:credentials] == true
|
332
|
-
|
333
|
-
self.path = path
|
334
|
-
self.credentials = public_resource ? false : (opts[:credentials] == true)
|
335
|
-
self.max_age = opts[:max_age] || 1728000
|
336
|
-
self.pattern = compile(path)
|
337
|
-
self.if_proc = opts[:if]
|
338
|
-
self.vary_headers = opts[:vary] && [opts[:vary]].flatten
|
339
|
-
@public_resource = public_resource
|
340
|
-
|
341
|
-
self.headers = case opts[:headers]
|
342
|
-
when :any then :any
|
343
|
-
when nil then nil
|
344
|
-
else
|
345
|
-
[opts[:headers]].flatten.collect{|h| h.downcase}
|
346
|
-
end
|
347
|
-
|
348
|
-
self.methods = case opts[:methods]
|
349
|
-
when :any then [:get, :head, :post, :put, :patch, :delete, :options]
|
350
|
-
else
|
351
|
-
ensure_enum(opts[:methods]) || [:get]
|
352
|
-
end.map{|e| e.to_s }
|
353
|
-
|
354
|
-
self.expose = opts[:expose] ? [opts[:expose]].flatten : nil
|
355
|
-
end
|
356
|
-
|
357
|
-
def matches_path?(path)
|
358
|
-
pattern =~ path
|
359
|
-
end
|
360
|
-
|
361
|
-
def match?(path, env)
|
362
|
-
matches_path?(path) && (if_proc.nil? || if_proc.call(env))
|
363
|
-
end
|
364
|
-
|
365
|
-
def process_preflight(env, result)
|
366
|
-
headers = {CONTENT_TYPE => TEXT_PLAIN}
|
367
|
-
|
368
|
-
request_method = env[HTTP_ACCESS_CONTROL_REQUEST_METHOD]
|
369
|
-
if request_method.nil?
|
370
|
-
result.miss(Result::MISS_NO_METHOD) and return headers
|
371
|
-
end
|
372
|
-
if !methods.include?(request_method.downcase)
|
373
|
-
result.miss(Result::MISS_DENY_METHOD) and return headers
|
374
|
-
end
|
375
|
-
|
376
|
-
request_headers = env[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]
|
377
|
-
if request_headers && !allow_headers?(request_headers)
|
378
|
-
result.miss(Result::MISS_DENY_HEADER) and return headers
|
379
|
-
end
|
380
|
-
|
381
|
-
result.hit = true
|
382
|
-
headers.merge(to_preflight_headers(env))
|
383
|
-
end
|
384
|
-
|
385
|
-
def to_headers(env)
|
386
|
-
h = {
|
387
|
-
'Access-Control-Allow-Origin' => origin_for_response_header(env[HTTP_ORIGIN]),
|
388
|
-
'Access-Control-Allow-Methods' => methods.collect{|m| m.to_s.upcase}.join(', '),
|
389
|
-
'Access-Control-Expose-Headers' => expose.nil? ? '' : expose.join(', '),
|
390
|
-
'Access-Control-Max-Age' => max_age.to_s }
|
391
|
-
h['Access-Control-Allow-Credentials'] = 'true' if credentials
|
392
|
-
h
|
393
|
-
end
|
394
|
-
|
395
|
-
protected
|
396
|
-
def public_resource?
|
397
|
-
@public_resource
|
398
|
-
end
|
399
|
-
|
400
|
-
def origin_for_response_header(origin)
|
401
|
-
return '*' if public_resource?
|
402
|
-
origin
|
403
|
-
end
|
404
|
-
|
405
|
-
def to_preflight_headers(env)
|
406
|
-
h = to_headers(env)
|
407
|
-
if env[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]
|
408
|
-
h.merge!('Access-Control-Allow-Headers' => env[HTTP_ACCESS_CONTROL_REQUEST_HEADERS])
|
409
|
-
end
|
410
|
-
h
|
411
|
-
end
|
412
|
-
|
413
|
-
def allow_headers?(request_headers)
|
414
|
-
headers = self.headers || []
|
415
|
-
if headers == :any
|
416
|
-
return true
|
417
|
-
end
|
418
|
-
request_headers = request_headers.split(/,\s*/) if request_headers.kind_of?(String)
|
419
|
-
request_headers.all? do |header|
|
420
|
-
header = header.downcase
|
421
|
-
CORS_SIMPLE_HEADERS.include?(header) || headers.include?(header)
|
422
|
-
end
|
423
|
-
end
|
204
|
+
def match_resource(path, env)
|
205
|
+
origin = env[HTTP_ORIGIN]
|
424
206
|
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
end
|
207
|
+
origin_matched = false
|
208
|
+
all_resources.each do |r|
|
209
|
+
next unless r.allow_origin?(origin, env)
|
429
210
|
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
pattern =
|
434
|
-
path.to_str.gsub(/((:\w+)|[\*#{special_chars.join}])/) do |match|
|
435
|
-
case match
|
436
|
-
when "*"
|
437
|
-
"(.*?)"
|
438
|
-
when *special_chars
|
439
|
-
Regexp.escape(match)
|
440
|
-
else
|
441
|
-
"([^/?&#]+)"
|
442
|
-
end
|
443
|
-
end
|
444
|
-
/^#{pattern}$/
|
445
|
-
elsif path.respond_to? :match
|
446
|
-
path
|
447
|
-
else
|
448
|
-
raise TypeError, path
|
449
|
-
end
|
450
|
-
end
|
211
|
+
origin_matched = true
|
212
|
+
found = r.match_resource(path, env)
|
213
|
+
return [found, nil] if found
|
451
214
|
end
|
452
215
|
|
216
|
+
[nil, origin_matched ? Result::MISS_NO_PATH : Result::MISS_NO_ORIGIN]
|
217
|
+
end
|
453
218
|
end
|
454
219
|
end
|
data/rack-cors.gemspec
CHANGED
@@ -1,26 +1,30 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require 'rack/cors/version'
|
5
6
|
|
6
7
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
8
|
+
spec.name = 'rack-cors'
|
8
9
|
spec.version = Rack::Cors::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
spec.description =
|
12
|
-
spec.summary =
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
10
|
+
spec.authors = ['Calvin Yu']
|
11
|
+
spec.email = ['me@sourcebender.com']
|
12
|
+
spec.description = 'Middleware that will make Rack-based apps CORS compatible. Fork the project here: https://github.com/cyu/rack-cors'
|
13
|
+
spec.summary = 'Middleware for enabling Cross-Origin Resource Sharing in Rack apps'
|
14
|
+
spec.homepage = 'https://github.com/cyu/rack-cors'
|
15
|
+
spec.license = 'MIT'
|
15
16
|
|
16
|
-
spec.files = `git ls-files`.split(
|
17
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR).reject { |f| (f == '.gitignore') || f =~ /^examples/ }
|
17
18
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
20
|
+
spec.require_paths = ['lib']
|
20
21
|
|
21
|
-
spec.
|
22
|
-
spec.add_development_dependency
|
23
|
-
spec.add_development_dependency
|
24
|
-
spec.add_development_dependency
|
25
|
-
spec.add_development_dependency
|
22
|
+
spec.add_dependency 'rack', '>= 2.0.0'
|
23
|
+
spec.add_development_dependency 'bundler', '>= 1.16.0', '< 3'
|
24
|
+
spec.add_development_dependency 'minitest', '~> 5.11.0'
|
25
|
+
spec.add_development_dependency 'mocha', '~> 1.6.0'
|
26
|
+
spec.add_development_dependency 'pry', '~> 0.12'
|
27
|
+
spec.add_development_dependency 'rack-test', '~> 1.1.0'
|
28
|
+
spec.add_development_dependency 'rake', '~> 12.3.0'
|
29
|
+
spec.add_development_dependency 'rubocop', '~> 0.80.1'
|
26
30
|
end
|
data/test/.rubocop.yml
ADDED
data/test/cors/test.cors.coffee
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
CORS_SERVER = '127.0.0.1.xip.io:
|
1
|
+
CORS_SERVER = '127.0.0.1.xip.io:3000'
|
2
|
+
|
3
|
+
mocha.setup({ignoreLeaks: true});
|
2
4
|
|
3
5
|
describe 'CORS', ->
|
4
6
|
|
@@ -12,6 +14,11 @@ describe 'CORS', ->
|
|
12
14
|
expect(data).to.eql('Hello world')
|
13
15
|
done()
|
14
16
|
|
17
|
+
it 'should allow PATCH access to dynamic resource', (done) ->
|
18
|
+
$.ajax("http://#{CORS_SERVER}/", type: 'PATCH').done (data, textStatus, jqXHR) ->
|
19
|
+
expect(data).to.eql('Hello world')
|
20
|
+
done()
|
21
|
+
|
15
22
|
it 'should allow HEAD access to dynamic resource', (done) ->
|
16
23
|
$.ajax("http://#{CORS_SERVER}/", type: 'HEAD').done (data, textStatus, jqXHR) ->
|
17
24
|
expect(jqXHR.status).to.eql(200)
|
@@ -29,7 +36,7 @@ describe 'CORS', ->
|
|
29
36
|
|
30
37
|
it 'should allow access to static resource', (done) ->
|
31
38
|
$.get "http://#{CORS_SERVER}/static.txt", (data, status, xhr) ->
|
32
|
-
expect($.trim(data)).to.eql("
|
39
|
+
expect($.trim(data)).to.eql("Hello world")
|
33
40
|
done()
|
34
41
|
|
35
42
|
it 'should allow post resource', (done) ->
|