class Rack::Cors
Constants
- DEFAULT_VARY_HEADERS
- ENV_KEY
- HTTP_ACCESS_CONTROL_REQUEST_HEADERS
- HTTP_ACCESS_CONTROL_REQUEST_METHOD
- HTTP_ORIGIN
- HTTP_X_ORIGIN
- OPTIONS
- PATH_INFO
- RACK_CORS
- RACK_LOGGER
- REQUEST_METHOD
- VERSION
Public Class Methods
new(app, opts = {}, &block)
click to toggle source
# File lib/rack/cors.rb, line 29 def initialize(app, opts = {}, &block) @app = app @debug_mode = !!opts[:debug] @logger = @logger_proc = nil logger = opts[:logger] if logger if logger.respond_to? :call @logger_proc = opts[:logger] else @logger = logger end end return unless block_given? if block.arity == 1 block.call(self) else instance_eval(&block) end end
Public Instance Methods
allow(&block)
click to toggle source
# File lib/rack/cors.rb, line 56 def allow(&block) all_resources << (resources = Resources.new) if block.arity == 1 block.call(resources) else resources.instance_eval(&block) end end
call(env)
click to toggle source
# File lib/rack/cors.rb, line 66 def call(env) env[HTTP_ORIGIN] ||= env[HTTP_X_ORIGIN] if env[HTTP_X_ORIGIN] path = evaluate_path(env) add_headers = nil if env[HTTP_ORIGIN] debug(env) do ['Incoming Headers:', " Origin: #{env[HTTP_ORIGIN]}", " Path-Info: #{path}", " Access-Control-Request-Method: #{env[HTTP_ACCESS_CONTROL_REQUEST_METHOD]}", " Access-Control-Request-Headers: #{env[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]}"].join("\n") end if env[REQUEST_METHOD] == OPTIONS && env[HTTP_ACCESS_CONTROL_REQUEST_METHOD] return [400, {}, []] unless Rack::Utils.valid_path?(path) headers = process_preflight(env, path) debug(env) do "Preflight Headers:\n" + headers.collect { |kv| " #{kv.join(': ')}" }.join("\n") end return [200, headers, []] else add_headers = process_cors(env, path) end else Result.miss(env, Result::MISS_NO_ORIGIN) end # This call must be done BEFORE calling the app because for some reason # env[PATH_INFO] gets changed after that and it won't match. (At least # in rails 4.1.6) vary_resource = resource_for_path(path) status, headers, body = @app.call env if add_headers headers = add_headers.merge(headers) debug(env) do add_headers.each_pair do |key, value| headers["x-rack-cors-original-#{key}"] = value if headers.key?(key) end end end # Vary header should ALWAYS mention Origin if there's ANY chance for the # response to be different depending on the Origin header value. # Better explained here: http://www.fastly.com/blog/best-practices-for-using-the-vary-header/ if vary_resource vary = headers['vary'] cors_vary_headers = if vary_resource.vary_headers&.any? vary_resource.vary_headers else DEFAULT_VARY_HEADERS end headers['vary'] = ((vary ? [vary].flatten.map { |v| v.split(/,\s*/) }.flatten : []) + cors_vary_headers).uniq.join(', ') end result = env[ENV_KEY] result.append_header(headers) if debug? && result [status, headers, body] end
debug?()
click to toggle source
# File lib/rack/cors.rb, line 52 def debug? @debug_mode end
Protected Instance Methods
all_resources()
click to toggle source
# File lib/rack/cors.rb, line 167 def all_resources @all_resources ||= [] end
debug(env, message = nil, &block)
click to toggle source
# File lib/rack/cors.rb, line 134 def debug(env, message = nil, &block) (@logger || select_logger(env)).debug(message, &block) if debug? end
evaluate_path(env)
click to toggle source
# File lib/rack/cors.rb, line 155 def evaluate_path(env) path = env[PATH_INFO] if path path = Rack::Utils.unescape_path(path) path = Rack::Utils.clean_path_info(path) if Rack::Utils.valid_path?(path) end path end
match_resource(path, env)
click to toggle source
# File lib/rack/cors.rb, line 204 def match_resource(path, env) origin = env[HTTP_ORIGIN] origin_matched = false all_resources.each do |r| next unless r.allow_origin?(origin, env) origin_matched = true found = r.match_resource(path, env) return [found, nil] if found end [nil, origin_matched ? Result::MISS_NO_PATH : Result::MISS_NO_ORIGIN] end
process_cors(env, path)
click to toggle source
# File lib/rack/cors.rb, line 183 def process_cors(env, path) resource, error = match_resource(path, env) if resource Result.hit(env) cors = resource.to_headers(env) cors else Result.miss(env, error) nil end end
process_preflight(env, path)
click to toggle source
# File lib/rack/cors.rb, line 171 def process_preflight(env, path) result = Result.preflight(env) resource, error = match_resource(path, env) unless resource result.miss(error) return {} end resource.process_preflight(env, result) end
resource_for_path(path_info)
click to toggle source
# File lib/rack/cors.rb, line 196 def resource_for_path(path_info) all_resources.each do |r| found = r.resource_for_path(path_info) return found if found end nil end
select_logger(env)
click to toggle source
# File lib/rack/cors.rb, line 138 def select_logger(env) @logger = if @logger_proc logger_proc = @logger_proc @logger_proc = nil logger_proc.call elsif defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger Rails.logger elsif env[RACK_LOGGER] env[RACK_LOGGER] else ::Logger.new(STDOUT).tap { |logger| logger.level = ::Logger::Severity::DEBUG } end end