Class: Rack::RelativeRedirect

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/contrib/relative_redirect.rb

Overview

Rack::RelativeRedirect is a simple middleware that converts relative paths in redirects in absolute urls, so they conform to RFC2616. It allows the user to specify the absolute path to use (with a sensible default), and handles relative paths (those that don’t start with a slash) as well.

Constant Summary collapse

SCHEME_MAP =
{'http'=>'80', 'https'=>'443'}
DEFAULT_ABSOLUTE_PROC =

The default proc used if a block is not provided to .new Just uses the url scheme of the request and the server name.

proc do |env, res|
  port = env['SERVER_PORT']
  scheme = env['rack.url_scheme']
  "#{scheme}://#{env['SERVER_NAME']}#{":#{port}" unless SCHEME_MAP[scheme] == port}"
end

Instance Method Summary collapse

Constructor Details

#initialize(app, &block) ⇒ RelativeRedirect

Initialize a new RelativeRedirect object with the given arguments. Arguments:

  • app : The next middleware in the chain. This is always called.

  • &block : If provided, it is called with the environment and the response from the next middleware. It should return a string representing the scheme and server name (such as ‘example.org’).



24
25
26
27
# File 'lib/rack/contrib/relative_redirect.rb', line 24

def initialize(app, &block)
  @app = app
  @absolute_proc = block || DEFAULT_ABSOLUTE_PROC
end

Instance Method Details

#call(env) ⇒ Object

Call the next middleware with the environment. If the request was a redirect (response status 301, 302, or 303), and the location header does not start with an http or https url scheme, call the block provided by new and use that to make the Location header an absolute url. If the Location does not start with a slash, make location relative to the path requested.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/rack/contrib/relative_redirect.rb', line 34

def call(env)
  status, headers, body = @app.call(env)
  headers_klass = Rack.release < "3" ? Rack::Utils::HeaderHash : Rack::Headers
  headers = headers_klass.new.merge(headers)

  if [301,302,303, 307,308].include?(status) and loc = headers['Location'] and !%r{\Ahttps?://}o.match(loc)
    absolute = @absolute_proc.call(env, [status, headers, body])
    headers['Location'] = if %r{\A/}.match(loc)
      "#{absolute}#{loc}"
    else
      "#{absolute}#{File.dirname(Rack::Utils.unescape(env['PATH_INFO']))}/#{loc}"
    end
  end

  [status, headers, body]
end