Module: ActionController::Redirecting
Relationships & Source Files | |
Namespace Children | |
Exceptions:
| |
Extension / Inclusion / Inheritance Descendants | |
Included In:
| |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
::ActiveSupport::Concern
|
|
Instance Chain:
|
|
Defined in: | actionpack/lib/action_controller/metal/redirecting.rb |
Constant Summary
-
ILLEGAL_HEADER_VALUE_REGEX =
# File 'actionpack/lib/action_controller/metal/redirecting.rb', line 14/[\x00-\x08\x0A-\x1F]/
::AbstractController::Logger
- Attributes & Methods
Class Method Summary
- ._compute_redirect_to_location(request, options) mod_func Internal use only
::ActiveSupport::Concern
- Extended
class_methods | Define class methods from given block. |
included | Evaluate given block in context of base class, so that you can write class macros here. |
prepended | Evaluate given block in context of base class, so that you can write class macros here. |
append_features, prepend_features |
Instance Attribute Summary
::AbstractController::UrlFor
- Included
::ActionDispatch::Routing::UrlFor
- Included
Instance Method Summary
-
#redirect_back(fallback_location:, allow_other_host: _allow_other_host, **args)
Soft deprecated alias for #redirect_back_or_to where the
fallback_location
location is supplied as a keyword argument instead of the first positional argument. -
#redirect_back_or_to(fallback_location, allow_other_host: _allow_other_host, **options)
Redirects the browser to the page that issued the request (the referrer) if possible, otherwise redirects to the provided default fallback location.
-
#redirect_to(options = {}, response_options = {})
Redirects the browser to the target specified in
options
. -
#url_from(location)
Verifies the passed
location
is an internal URL that’s safe to redirect to and returns it, or nil if not. - #_allow_other_host private
- #_enforce_open_redirect_protection(location, allow_other_host:) private
- #_ensure_url_is_http_header_safe(url) private
- #_extract_redirect_to_status(options, response_options) private
- #_url_host_allowed?(url) ⇒ Boolean private
UrlFor
- Included
::AbstractController::UrlFor
- Included
::ActionDispatch::Routing::UrlFor
- Included
#initialize, | |
#route_for | Allows calling direct or regular named route. |
#url_for | Generate a URL based on the options provided, |
#url_options | Hook overridden in controller to add request information with |
#_routes_context, #_with_routes, #full_url_for |
::ActionDispatch::Routing::PolymorphicRoutes
- Included
#polymorphic_path | Returns the path component of a URL for the given record. |
#polymorphic_url | Constructs a call to a named RESTful route for the given record and returns the resulting URL string. |
#polymorphic_mapping, #polymorphic_path_for_action, #polymorphic_url_for_action |
::ActiveSupport::Benchmarkable
- self
#benchmark | Allows you to measure the execution time of a block in a template and records the result to the log. |
DSL Calls
included
[ GitHub ]16 17 18
# File 'actionpack/lib/action_controller/metal/redirecting.rb', line 16
included do mattr_accessor :raise_on_open_redirects, default: false end
Class Attribute Details
.logger (rw)
[ GitHub ]# File 'actionpack/lib/abstract_controller/logger.rb', line 12
config_accessor :logger
Class Method Details
._compute_redirect_to_location(request, options) (mod_func)
# File 'actionpack/lib/action_controller/metal/redirecting.rb', line 159
def _compute_redirect_to_location(request, ) # :nodoc: case # The scheme name consist of a letter followed by any combination of letters, # digits, and the plus ("+"), period ("."), or hyphen ("-") characters; and is # terminated by a colon (":"). See # https://tools.ietf.org/html/rfc3986#section-3.1 The protocol relative scheme # starts with a double slash "//". when /\A([a-z][a-z\d\-+.]*:|\/\/).*/i .to_str when String request.protocol + request.host_with_port + when Proc _compute_redirect_to_location request, instance_eval(& ) else url_for( ) end.delete("\0\r\n") end
Instance Attribute Details
#logger (rw)
[ GitHub ]# File 'actionpack/lib/abstract_controller/logger.rb', line 12
config_accessor :logger
Instance Method Details
#_allow_other_host (private)
[ GitHub ]# File 'actionpack/lib/action_controller/metal/redirecting.rb', line 209
def _allow_other_host !raise_on_open_redirects end
#_enforce_open_redirect_protection(location, allow_other_host:) (private)
[ GitHub ]# File 'actionpack/lib/action_controller/metal/redirecting.rb', line 223
def _enforce_open_redirect_protection(location, allow_other_host:) if allow_other_host || _url_host_allowed?(location) location else raise UnsafeRedirectError, "Unsafe redirect to #{location.truncate(100).inspect}, pass allow_other_host: true to redirect anyway." end end
#_ensure_url_is_http_header_safe(url) (private)
[ GitHub ]# File 'actionpack/lib/action_controller/metal/redirecting.rb', line 242
def _ensure_url_is_http_header_safe(url) # Attempt to comply with the set of valid token characters defined for an HTTP # header value in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6 if url.match?(ILLEGAL_HEADER_VALUE_REGEX) msg = "The redirect URL #{url} contains one or more illegal HTTP header field character. " \ "Set of legal characters defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6" raise UnsafeRedirectError, msg end end
#_extract_redirect_to_status(options, response_options) (private)
[ GitHub ]
#_url_host_allowed?(url) ⇒ Boolean
(private)
# File 'actionpack/lib/action_controller/metal/redirecting.rb', line 231
def _url_host_allowed?(url) host = URI(url.to_s).host return true if host == request.host return false unless host.nil? return false unless url.to_s.start_with?("/") !url.to_s.start_with?("//") rescue ArgumentError, URI::Error false end
#redirect_back(fallback_location:, allow_other_host: _allow_other_host, **args)
Soft deprecated alias for #redirect_back_or_to where the fallback_location
location is supplied as a keyword argument instead of the first positional argument.
# File 'actionpack/lib/action_controller/metal/redirecting.rb', line 122
def redirect_back(fallback_location:, allow_other_host: _allow_other_host, **args) redirect_back_or_to fallback_location, allow_other_host: allow_other_host, **args end
#redirect_back_or_to(fallback_location, allow_other_host: _allow_other_host, **options)
Redirects the browser to the page that issued the request (the referrer) if possible, otherwise redirects to the provided default fallback location.
The referrer information is pulled from the HTTP Referer
(sic) header on the request. This is an optional header and its presence on the request is subject to browser security settings and user preferences. If the request is missing this header, the fallback_location
will be used.
redirect_back_or_to({ action: "show", id: 5 })
redirect_back_or_to @post
redirect_back_or_to "http://www.rubyonrails.org"
redirect_back_or_to "/images/screenshot.jpg"
redirect_back_or_to posts_url
redirect_back_or_to proc { edit_post_url(@post) }
redirect_back_or_to '/', allow_other_host: false
#### Options
-
:allow_other_host
- Allow or disallow redirection to the host that is different to the current host, defaults to true.
All other options that can be passed to #redirect_to are accepted as options, and the behavior is identical.
# File 'actionpack/lib/action_controller/metal/redirecting.rb', line 149
def redirect_back_or_to(fallback_location, allow_other_host: _allow_other_host, ** ) if request.referer && (allow_other_host || _url_host_allowed?(request.referer)) redirect_to request.referer, allow_other_host: allow_other_host, ** else # The method level `allow_other_host` doesn't apply in the fallback case, omit # and let the `redirect_to` handling take over. redirect_to fallback_location, ** end end
#redirect_to(options = {}, response_options = {})
Redirects the browser to the target specified in options
. This parameter can be any one of:
-
::Hash
- The URL will be generated by calling url_for with theoptions
. -
Record
- The URL will be generated by calling url_for with theoptions
, which will reference a named URL for that record. -
::String
starting with protocol:// (like http://) or a protocol relative reference (like//
) - Is passed straight through as the target for redirection. -
::String
not containing a protocol - The current protocol and host is prepended to the string. -
Proc
- A block that will be executed in the controller’s context. Should return any option accepted byredirect_to
.
Examples
redirect_to action: "show", id: 5
redirect_to @post
redirect_to "http://www.rubyonrails.org"
redirect_to "/images/screenshot.jpg"
redirect_to posts_url
redirect_to proc { edit_post_url(@post) }
The redirection happens as a 302 Found
header unless otherwise specified using the :status
option:
redirect_to post_url(@post), status: :found
redirect_to action: 'atom', status: :moved_permanently
redirect_to post_url(@post), status: 301
redirect_to action: 'atom', status: 302
The status code can either be a standard [HTTP Status code](www.iana.org/assignments/http-status-codes) as an integer, or a symbol representing the downcased, underscored and symbolized description. Note that the status code must be a 3xx HTTP code, or redirection will not occur.
If you are using XHR requests other than GET or POST and redirecting after the request then some browsers will follow the redirect using the original request method. This may lead to undesirable behavior such as a double DELETE. To work around this you can return a 303 See Other
status code which will be followed using a GET request.
redirect_to posts_url, status: :see_other
redirect_to action: 'index', status: 303
It is also possible to assign a flash message as part of the redirection. There are two special accessors for the commonly used flash names alert
and notice
as well as a general purpose flash
bucket.
redirect_to post_url(@post), alert: "Watch it, mister!"
redirect_to post_url(@post), status: :found, notice: "Pay attention to the road"
redirect_to post_url(@post), status: 301, flash: { updated_post_id: @post.id }
redirect_to({ action: 'atom' }, alert: "Something serious happened")
Statements after redirect_to
in our controller get executed, so redirect_to
doesn’t stop the execution of the function. To terminate the execution of the function immediately after the redirect_to
, use return.
redirect_to post_url(@post) and return
Open Redirect protection
By default, ::Rails
protects against redirecting to external hosts for your app’s safety, so called open redirects. Note: this was a new default in ::Rails
7.0, after upgrading opt-in by uncommenting the line with raise_on_open_redirects
in config/initializers/new_framework_defaults_7_0.rb
Here #redirect_to
automatically validates the potentially-unsafe URL:
redirect_to params[:redirect_url]
Raises UnsafeRedirectError in the case of an unsafe redirect.
To allow any external redirects pass allow_other_host: true
, though using a user-provided param in that case is unsafe.
redirect_to "https://rubyonrails.org", allow_other_host: true
See #url_from for more information on what an internal and safe URL is, or how to fall back to an alternate redirect URL in the unsafe case.
# File 'actionpack/lib/action_controller/metal/redirecting.rb', line 103
def redirect_to( = {}, = {}) raise ActionControllerError.new("Cannot redirect to nil!") unless raise AbstractController::DoubleRenderError if response_body allow_other_host = .delete(:allow_other_host) { _allow_other_host } proposed_status = _extract_redirect_to_status(, ) redirect_to_location = _compute_redirect_to_location(request, ) _ensure_url_is_http_header_safe(redirect_to_location) self.location = _enforce_open_redirect_protection(redirect_to_location, allow_other_host: allow_other_host) self.response_body = "" self.status = proposed_status end
#url_from(location)
Verifies the passed location
is an internal URL that’s safe to redirect to and returns it, or nil if not. Useful to wrap a params provided redirect URL and fall back to an alternate URL to redirect to:
redirect_to url_from(params[:redirect_url]) || root_url
The location
is considered internal, and safe, if it’s on the same host as request.host
:
# If request.host is example.com:
url_from("https://example.com/profile") # => "https://example.com/profile"
url_from("http://example.com/profile") # => "http://example.com/profile"
url_from("http://evil.com/profile") # => nil
Subdomains are considered part of the host:
# If request.host is on https://example.com or https://app.example.com, you'd get:
url_from("https://dev.example.com/profile") # => nil
NOTE: there’s a similarity with [url_for](ActionDispatch::Routing::UrlFor#url_for), which generates an internal URL from various options from within the app, e.g. url_for(@post)
. However, #url_from
is meant to take an external parameter to verify as in url_from(params[:redirect_url])
.
# File 'actionpack/lib/action_controller/metal/redirecting.rb', line 203
def url_from(location) location = location.presence location if location && _url_host_allowed?(location) end