rack-cors 0.2.2 → 0.2.4

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.

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