Class: Philiprehberger::Cors::Middleware

Inherits:
Object
  • Object
show all
Defined in:
lib/philiprehberger/cors/middleware.rb

Overview

Rack middleware for handling CORS requests.

Supports wildcard, exact, and regex origin matching, preflight handling, credentials, exposed headers, header reflection, and Chrome’s Private Network Access (PNA) preflight extension.

Examples:

Basic usage

use Philiprehberger::Cors::Middleware,
  origins: ['https://example.com'],
  methods: %w[GET POST PUT DELETE],
  headers: %w[Content-Type Authorization],
  credentials: true,
  max_age: 86_400

Reflect request headers

use Philiprehberger::Cors::Middleware,
  origins: ['https://app.example.com'],
  headers: :reflect

Private Network Access

use Philiprehberger::Cors::Middleware,
  origins: ['https://app.example.com'],
  allow_private_network: true

Constant Summary collapse

DEFAULT_METHODS =
%w[GET POST PUT PATCH DELETE HEAD OPTIONS].freeze
DEFAULT_HEADERS =
%w[Content-Type Accept Authorization].freeze
DEFAULT_MAX_AGE =
86_400

Instance Method Summary collapse

Constructor Details

#initialize(app, origins: '*', methods: DEFAULT_METHODS, headers: DEFAULT_HEADERS, credentials: false, max_age: DEFAULT_MAX_AGE, expose_headers: [], allow_private_network: false) ⇒ Middleware

Create a new CORS middleware instance.

Parameters:

  • app (#call)

    the Rack application

  • origins (Array<String, Regexp>, String) (defaults to: '*')

    allowed origins (‘*’ for all)

  • methods (Array<String>) (defaults to: DEFAULT_METHODS)

    allowed HTTP methods

  • headers (Array<String>, Symbol) (defaults to: DEFAULT_HEADERS)

    allowed request headers, or :reflect to echo the Access-Control-Request-Headers header back to the client on preflight requests

  • credentials (Boolean) (defaults to: false)

    whether to allow credentials

  • max_age (Integer) (defaults to: DEFAULT_MAX_AGE)

    preflight cache duration in seconds

  • expose_headers (Array<String>) (defaults to: [])

    headers the client is allowed to read

  • allow_private_network (Boolean) (defaults to: false)

    enable Chrome’s Private Network Access preflight response header (Access-Control-Allow-Private-Network)



47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/philiprehberger/cors/middleware.rb', line 47

def initialize(app, origins: '*', methods: DEFAULT_METHODS, headers: DEFAULT_HEADERS,
               credentials: false, max_age: DEFAULT_MAX_AGE, expose_headers: [],
               allow_private_network: false)
  @app = app
  @origins = origins
  @methods = Array(methods).map { |m| m.to_s.upcase }
  @headers = headers
  @reflect_headers = headers == :reflect
  @allowed_headers = @reflect_headers ? [] : Array(headers)
  @credentials = credentials
  @max_age = max_age
  @expose_headers = Array(expose_headers)
  @allow_private_network = allow_private_network
end

Instance Method Details

#allowed_originsArray<String, Regexp>, Symbol

Return the configured origins for introspection or logging.

Wildcard configurations (+‘*’+) are surfaced as the symbol :any. Any other configuration is normalized to an Array of the original entries (strings and/or Regexp objects).

Returns:

  • (Array<String, Regexp>, Symbol)

    configured origins, or :any



69
70
71
72
73
# File 'lib/philiprehberger/cors/middleware.rb', line 69

def allowed_origins
  return :any if @origins == '*'

  Array(@origins)
end

#call(env) ⇒ Array(Integer, Hash, #each)

Process a Rack request.

Parameters:

  • env (Hash)

    the Rack environment

Returns:

  • (Array(Integer, Hash, #each))

    Rack response triplet



79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/philiprehberger/cors/middleware.rb', line 79

def call(env)
  origin = env['HTTP_ORIGIN']
  return @app.call(env) unless origin
  return @app.call(env) unless origin_allowed?(origin)

  if preflight?(env)
    preflight_response(origin, env)
  else
    status, headers, body = @app.call(env)
    headers = add_cors_headers(headers, origin)
    [status, headers, body]
  end
end