diff --git a/README.rdoc b/README.rdoc index 080c36e..44c87b5 100644 --- a/README.rdoc +++ b/README.rdoc @@ -25,12 +25,16 @@ You configure Rack::Cors by passing a block to the use command: use Rack::Cors do |cfg| cfg.allow do |allow| - allow.origins 'localhost:3000', '127.0.0.1:3000' + allow.origins 'localhost:3000', '127.0.0.1:3000', + /http:\/\/192\.168\.0\.\d{1,3}(:\d+)?/ + # regular expressions can be used here allow.resource '/file/list_all/', :headers => 'x-domain-token' allow.resource '/file/at/*', :methods => [:get, :post, :put, :delete], - :headers => 'x-domain-token' + :headers => 'x-domain-token', + :expose => ['Some-Custom-Response-Header'] + # headers to expose end cfg.allow do |allow| diff --git a/lib/rack/cors.rb b/lib/rack/cors.rb index 83b3cb1..976d99c 100644 --- a/lib/rack/cors.rb +++ b/lib/rack/cors.rb @@ -14,6 +14,13 @@ def allow end def call(env) + if env['HTTP_ORIGIN'] == 'null' + env['HTTP_ORIGIN'] = 'file://' + end + if env['HTTP_X_ORIGIN'] and not env['HTTP_ORIGIN'] + puts 'ORIGIN header is empty, X-ORIGIN workaround header applied.' + env['HTTP_ORIGIN'] = env['HTTP_X_ORIGIN'] + end cors_headers = nil if env['HTTP_ORIGIN'] debug(env) do @@ -76,13 +83,17 @@ def initialize def origins(*args) @origins = args.flatten.collect do |n| - case n - when /^https?:\/\// then n - when '*' - @public_resources = true + if n.class == Regexp n else - "http://#{n}" + case n + when /^https?:\/\// then n + when '*' + @public_resources = true + n + else + "http://#{n}" + end end end end @@ -96,7 +107,9 @@ def public_resources? end def allow_origin?(source) - public_resources? || @origins.include?(source) + result = public_resources? || @origins.include?(source) || + (not (@origins.select {|n| n.class == Regexp && n.match(source)}).empty?) + result end def find_resource(path) @@ -105,7 +118,7 @@ def find_resource(path) end class Resource - attr_accessor :path, :methods, :headers, :max_age, :credentials, :pattern + attr_accessor :path, :methods, :headers, :expose, :max_age, :credentials, :pattern def initialize(public_resource, path, opts={}) self.path = path @@ -121,6 +134,12 @@ def initialize(public_resource, path, opts={}) else [opts[:headers]].flatten.collect{|h| h.downcase} end + + self.expose = case opts[:expose] + when nil then nil + else + [opts[:expose]].flatten + end end def match?(path) @@ -133,8 +152,10 @@ def process_preflight(env) end def to_headers(env) + x_origin = env['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'] h = { 'Access-Control-Allow-Origin' => public_resource? ? '*' : env['HTTP_ORIGIN'], 'Access-Control-Allow-Methods' => methods.collect{|m| m.to_s.upcase}.join(', '), + 'Access-Control-Expose-Headers' => expose.nil? ? '' : expose.join(', '), 'Access-Control-Max-Age' => max_age.to_s } h['Access-Control-Allow-Credentials'] = 'true' if credentials h