rack-cors 0.2.2 → 0.2.4

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.

data/.gitignore CHANGED
@@ -1 +1,2 @@
1
1
  pkg
2
+ Gemfile.lock
@@ -23,18 +23,22 @@ In your Gemfile:
23
23
 
24
24
  You configure Rack::Cors by passing a block to the <tt>use</tt> command:
25
25
 
26
- use Rack::Cors do |cfg|
27
- cfg.allow do |allow|
28
- allow.origins 'localhost:3000', '127.0.0.1:3000'
29
-
30
- allow.resource '/file/list_all/', :headers => 'x-domain-token'
31
- allow.resource '/file/at/*',
26
+ use Rack::Cors do
27
+ allow do
28
+ origins 'localhost:3000', '127.0.0.1:3000',
29
+ /http:\/\/192\.168\.0\.\d{1,3}(:\d+)?/
30
+ # regular expressions can be used here
31
+
32
+ resource '/file/list_all/', :headers => 'x-domain-token'
33
+ resource '/file/at/*',
32
34
  :methods => [:get, :post, :put, :delete],
33
- :headers => 'x-domain-token'
35
+ :headers => 'x-domain-token',
36
+ :expose => ['Some-Custom-Response-Header']
37
+ # headers to expose
34
38
  end
35
39
 
36
- cfg.allow do |allow|
37
- allow.origins '*'
38
- allow.resource '/public/*', :headers => :any, :methods => :get
40
+ allow do
41
+ origins '*'
42
+ resource '/public/*', :headers => :any, :methods => :get
39
43
  end
40
44
  end
data/Rakefile CHANGED
@@ -1,13 +1,30 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ desc 'Run tests'
5
+ Rake::TestTask.new(:test) do |t|
6
+ t.pattern = 'test/*_test.rb'
7
+ t.verbose = true
8
+ t.warning = true
9
+ end
10
+
11
+ # ==================================================
12
+ # JEWELER TASKS
13
+ # ==================================================
1
14
  begin
2
15
  require 'jeweler'
3
16
  Jeweler::Tasks.new do |gemspec|
4
17
  gemspec.name = "rack-cors"
5
18
  gemspec.summary = "Middleware for enabling Cross-Origin Resource Sharing in Rack apps"
19
+ gemspec.description = "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: http://github.com/cyu/rack-cors"
6
20
  gemspec.email = "csyu77@gmail.com"
7
21
  gemspec.homepage = "http://github.com/cyu/rack-cors"
8
22
  gemspec.authors = ["Calvin Yu"]
23
+ gemspec.add_dependency 'rack'
24
+ gemspec.files.exclude 'Gemfile'
9
25
  end
10
26
  Jeweler::GemcutterTasks.new
11
27
  rescue LoadError
12
28
  puts "Jeweler not available. Install it with: gem install jeweler"
13
29
  end
30
+
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.2
1
+ 0.2.4
@@ -2,18 +2,31 @@ require 'logger'
2
2
 
3
3
  module Rack
4
4
  class Cors
5
- def initialize(app, opts={})
5
+ def initialize(app, opts={}, &block)
6
6
  @app = app
7
7
  @logger = opts[:logger]
8
- yield self if block_given?
8
+
9
+ if block.arity == 1
10
+ block.call(self)
11
+ else
12
+ instance_eval(&block)
13
+ end
9
14
  end
10
15
 
11
- def allow
16
+ def allow(&block)
12
17
  all_resources << (resources = Resources.new)
13
- yield resources
18
+
19
+ if block.arity == 1
20
+ block.call(resources)
21
+ else
22
+ resources.instance_eval(&block)
23
+ end
14
24
  end
15
25
 
16
26
  def call(env)
27
+ env['HTTP_ORIGIN'] = 'file://' if env['HTTP_ORIGIN'] == 'null'
28
+ env['HTTP_ORIGIN'] ||= env['HTTP_X_ORIGIN']
29
+
17
30
  cors_headers = nil
18
31
  if env['HTTP_ORIGIN']
19
32
  debug(env) do
@@ -77,12 +90,9 @@ module Rack
77
90
  def origins(*args)
78
91
  @origins = args.flatten.collect do |n|
79
92
  case n
80
- when /^https?:\/\// then n
81
- when '*'
82
- @public_resources = true
83
- n
84
- else
85
- "http://#{n}"
93
+ when Regexp, /^https?:\/\// then n
94
+ when '*' then @public_resources = true; n
95
+ else "http://#{n}"
86
96
  end
87
97
  end
88
98
  end
@@ -96,7 +106,7 @@ module Rack
96
106
  end
97
107
 
98
108
  def allow_origin?(source)
99
- public_resources? || @origins.include?(source)
109
+ public_resources? || !!@origins.detect {|origin| origin === source}
100
110
  end
101
111
 
102
112
  def find_resource(path)
@@ -105,7 +115,7 @@ module Rack
105
115
  end
106
116
 
107
117
  class Resource
108
- attr_accessor :path, :methods, :headers, :max_age, :credentials, :pattern
118
+ attr_accessor :path, :methods, :headers, :expose, :max_age, :credentials, :pattern
109
119
 
110
120
  def initialize(public_resource, path, opts={})
111
121
  self.path = path
@@ -121,6 +131,8 @@ module Rack
121
131
  else
122
132
  [opts[:headers]].flatten.collect{|h| h.downcase}
123
133
  end
134
+
135
+ self.expose = opts[:expose] ? [opts[:expose]].flatten : nil
124
136
  end
125
137
 
126
138
  def match?(path)
@@ -133,8 +145,10 @@ module Rack
133
145
  end
134
146
 
135
147
  def to_headers(env)
148
+ x_origin = env['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']
136
149
  h = { 'Access-Control-Allow-Origin' => public_resource? ? '*' : env['HTTP_ORIGIN'],
137
150
  'Access-Control-Allow-Methods' => methods.collect{|m| m.to_s.upcase}.join(', '),
151
+ 'Access-Control-Expose-Headers' => expose.nil? ? '' : expose.join(', '),
138
152
  'Access-Control-Max-Age' => max_age.to_s }
139
153
  h['Access-Control-Allow-Credentials'] = 'true' if credentials
140
154
  h
@@ -5,11 +5,12 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{rack-cors}
8
- s.version = "0.2.2"
8
+ s.version = "0.2.4"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Calvin Yu"]
12
- s.date = %q{2010-08-26}
12
+ s.date = %q{2011-06-04}
13
+ s.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: http://github.com/cyu/rack-cors}
13
14
  s.email = %q{csyu77@gmail.com}
14
15
  s.extra_rdoc_files = [
15
16
  "README.rdoc"
@@ -22,6 +23,7 @@ Gem::Specification.new do |s|
22
23
  "lib/rack/cors.rb",
23
24
  "rack-cors.gemspec",
24
25
  "test/cors_test.rb",
26
+ "test/dsl_test.rb",
25
27
  "test/test.ru"
26
28
  ]
27
29
  s.homepage = %q{http://github.com/cyu/rack-cors}
@@ -30,7 +32,8 @@ Gem::Specification.new do |s|
30
32
  s.rubygems_version = %q{1.3.7}
31
33
  s.summary = %q{Middleware for enabling Cross-Origin Resource Sharing in Rack apps}
32
34
  s.test_files = [
33
- "test/cors_test.rb"
35
+ "test/cors_test.rb",
36
+ "test/dsl_test.rb"
34
37
  ]
35
38
 
36
39
  if s.respond_to? :specification_version then
@@ -38,9 +41,12 @@ Gem::Specification.new do |s|
38
41
  s.specification_version = 3
39
42
 
40
43
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
44
+ s.add_runtime_dependency(%q<rack>, [">= 0"])
41
45
  else
46
+ s.add_dependency(%q<rack>, [">= 0"])
42
47
  end
43
48
  else
49
+ s.add_dependency(%q<rack>, [">= 0"])
44
50
  end
45
51
  end
46
52
 
@@ -6,7 +6,7 @@ Rack::Test::Session.class_eval do
6
6
  def options(uri, params = {}, env = {}, &block)
7
7
  env = env_for(uri, env.merge(:method => "OPTIONS", :params => params))
8
8
  process_request(uri, env, &block)
9
- end
9
+ end
10
10
  end
11
11
 
12
12
  Rack::Test::Methods.class_eval do
@@ -20,61 +20,95 @@ class CorsTest < Test::Unit::TestCase
20
20
  eval "Rack::Builder.new {( " + File.read(File.dirname(__FILE__) + '/test.ru') + "\n )}"
21
21
  end
22
22
 
23
+ should('support simple cors request') { cors_request }
24
+
25
+ should 'support regex origins configuration' do
26
+ cors_request :origin => 'http://192.168.0.1:1234'
27
+ end
28
+
29
+ should 'support alternative X-Origin header' do
30
+ header 'X-Origin', 'http://localhost:3000'
31
+ get '/'
32
+ assert_cors_success
33
+ end
34
+
35
+ should 'support expose header configuration' do
36
+ cors_request '/expose_single_header'
37
+ assert_equal 'expose-test', last_response.headers['Access-Control-Expose-Headers']
38
+
39
+ end
40
+
41
+ should 'support expose multiple header configuration' do
42
+ cors_request '/expose_multiple_headers'
43
+ assert_equal 'expose-test-1, expose-test-2', last_response.headers['Access-Control-Expose-Headers']
44
+ end
45
+
23
46
  context 'preflight requests' do
24
47
  should 'fail if origin is invalid' do
25
48
  preflight_request('http://allyourdataarebelongtous.com', '/')
26
- assert_preflight_failure
49
+ assert_cors_failure
27
50
  end
28
51
 
29
52
  should 'fail if Access-Control-Request-Method does not exist' do
30
53
  preflight_request('http://localhost:3000', '/', :method => nil)
31
- assert_preflight_failure
54
+ assert_cors_failure
32
55
  end
33
56
 
34
57
  should 'fail if Access-Control-Request-Method is not allowed' do
35
58
  preflight_request('http://localhost:3000', '/get-only', :method => :post)
36
- assert_preflight_failure
59
+ assert_cors_failure
37
60
  end
38
61
 
39
62
  should 'fail if header is not allowed' do
40
63
  preflight_request('http://localhost:3000', '/single_header', :headers => 'Fooey')
41
- assert_preflight_failure
64
+ assert_cors_failure
42
65
  end
43
66
 
44
67
  should 'allow any header if headers = :any' do
45
68
  preflight_request('http://localhost:3000', '/', :headers => 'Fooey')
46
- assert_preflight_success
69
+ assert_cors_success
47
70
  end
48
71
 
49
72
  should 'allow header case insensitive match' do
50
73
  preflight_request('http://localhost:3000', '/single_header', :headers => 'X-Domain-Token')
51
- assert_preflight_success
74
+ assert_cors_success
52
75
  end
53
76
 
54
77
  should 'allow multiple headers match' do
55
78
  # Webkit style
56
79
  preflight_request('http://localhost:3000', '/two_headers', :headers => 'X-Requested-With, X-Domain-Token')
57
- assert_preflight_success
80
+ assert_cors_success
58
81
 
59
82
  # Gecko style
60
83
  preflight_request('http://localhost:3000', '/two_headers', :headers => 'x-requested-with,x-domain-token')
61
- assert_preflight_success
84
+ assert_cors_success
62
85
  end
63
86
 
64
87
  should '* origin should allow any origin' do
65
88
  preflight_request('http://locohost:3000', '/public')
66
- assert_preflight_success
89
+ assert_cors_success
67
90
  assert_equal '*', last_response.headers['Access-Control-Allow-Origin']
68
91
  end
69
92
 
70
93
  should 'return a Content-Type' do
71
94
  preflight_request('http://localhost:3000', '/')
72
- assert_preflight_success
95
+ assert_cors_success
73
96
  assert_not_nil last_response.headers['Content-Type']
74
97
  end
75
98
  end
76
99
 
77
100
  protected
101
+ def cors_request(*args)
102
+ path = args.first.is_a?(String) ? args.first : '/'
103
+
104
+ opts = args.last.is_a?(Hash) ? args.last : {:origin => 'http://localhost:3000'}
105
+ origin = opts[:origin]
106
+
107
+ header 'Origin', origin
108
+ get path
109
+ assert_cors_success
110
+ end
111
+
78
112
  def preflight_request(origin, path, opts = {})
79
113
  header 'Origin', origin
80
114
  unless opts.key?(:method) && opts[:method].nil?
@@ -86,11 +120,11 @@ class CorsTest < Test::Unit::TestCase
86
120
  options path
87
121
  end
88
122
 
89
- def assert_preflight_success
90
- assert_not_nil last_response.headers['Access-Control-Allow-Origin']
123
+ def assert_cors_success
124
+ assert_not_nil last_response.headers['Access-Control-Allow-Origin'], 'missing Access-Control-Allow-Origin header'
91
125
  end
92
126
 
93
- def assert_preflight_failure
94
- assert_nil last_response.headers['Access-Control-Allow-Origin']
127
+ def assert_cors_failure
128
+ assert_nil last_response.headers['Access-Control-Allow-Origin'], 'no expecting Access-Control-Allow-Origin header'
95
129
  end
96
130
  end
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'rack/cors'
3
+ require 'shoulda'
4
+
5
+
6
+ class DSLTest < Test::Unit::TestCase
7
+ should 'support explicit config object dsl mode' do
8
+ cors = Rack::Cors.new(Proc.new {}) do |cfg|
9
+ cfg.allow do |allow|
10
+ allow.origins 'localhost:3000', '127.0.0.1:3000'
11
+ allow.resource '/get-only', :methods => :get
12
+ allow.resource '/', :headers => :any
13
+ end
14
+ end
15
+ resources = cors.send :all_resources
16
+ assert_equal 1, resources.length
17
+ assert resources.first.allow_origin?('http://localhost:3000')
18
+ end
19
+
20
+ should 'support implicit config object dsl mode' do
21
+ cors = Rack::Cors.new(Proc.new {}) do
22
+ allow do
23
+ origins 'localhost:3000', '127.0.0.1:3000'
24
+ resource '/get-only', :methods => :get
25
+ resource '/', :headers => :any
26
+ end
27
+ end
28
+ resources = cors.send :all_resources
29
+ assert_equal 1, resources.length
30
+ assert resources.first.allow_origin?('http://localhost:3000')
31
+ end
32
+ end
@@ -1,22 +1,24 @@
1
1
  require 'rack/cors'
2
2
 
3
- use Rack::Cors do |cfg|
4
- cfg.allow do |allow|
5
- allow.origins 'localhost:3000', '127.0.0.1:3000'
3
+ use Rack::Cors do
4
+ allow do
5
+ origins 'localhost:3000', '127.0.0.1:3000', /http:\/\/192\.168\.0\.\d{1,3}(:\d+)?/
6
6
 
7
- allow.resource '/get-only', :methods => :get
8
- allow.resource '/', :headers => :any
9
- allow.resource '/single_header', :headers => 'x-domain-token'
10
- allow.resource '/two_headers', :headers => %w{x-domain-token x-requested-with}
11
- # allow.resource '/file/at/*',
7
+ resource '/get-only', :methods => :get
8
+ resource '/', :headers => :any
9
+ resource '/single_header', :headers => 'x-domain-token'
10
+ resource '/two_headers', :headers => %w{x-domain-token x-requested-with}
11
+ resource '/expose_single_header', :expose => 'expose-test'
12
+ resource '/expose_multiple_headers', :expose => %w{expose-test-1 expose-test-2}
13
+ # resource '/file/at/*',
12
14
  # :methods => [:get, :post, :put, :delete],
13
15
  # :headers => :any,
14
16
  # :max_age => 0
15
17
  end
16
18
 
17
- cfg.allow do |allow|
18
- allow.origins '*'
19
- allow.resource '/public'
19
+ allow do
20
+ origins '*'
21
+ resource '/public'
20
22
  end
21
23
  end
22
24
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-cors
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 31
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 2
10
- version: 0.2.2
9
+ - 4
10
+ version: 0.2.4
11
11
  platform: ruby
12
12
  authors:
13
13
  - Calvin Yu
@@ -15,11 +15,24 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-08-26 00:00:00 -04:00
18
+ date: 2011-06-04 00:00:00 -04:00
19
19
  default_executable:
20
- dependencies: []
21
-
22
- description:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rack
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ description: "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: http://github.com/cyu/rack-cors"
23
36
  email: csyu77@gmail.com
24
37
  executables: []
25
38
 
@@ -35,6 +48,7 @@ files:
35
48
  - lib/rack/cors.rb
36
49
  - rack-cors.gemspec
37
50
  - test/cors_test.rb
51
+ - test/dsl_test.rb
38
52
  - test/test.ru
39
53
  has_rdoc: true
40
54
  homepage: http://github.com/cyu/rack-cors
@@ -72,3 +86,4 @@ specification_version: 3
72
86
  summary: Middleware for enabling Cross-Origin Resource Sharing in Rack apps
73
87
  test_files:
74
88
  - test/cors_test.rb
89
+ - test/dsl_test.rb