actionpack 6.1.7.5 → 7.0.8
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +319 -401
- data/MIT-LICENSE +1 -0
- data/README.rdoc +4 -5
- data/lib/abstract_controller/asset_paths.rb +1 -1
- data/lib/abstract_controller/base.rb +13 -26
- data/lib/abstract_controller/caching/fragments.rb +2 -2
- data/lib/abstract_controller/caching.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +21 -7
- data/lib/abstract_controller/collector.rb +2 -2
- data/lib/abstract_controller/error.rb +1 -1
- data/lib/abstract_controller/helpers.rb +17 -12
- data/lib/abstract_controller/logger.rb +1 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/rendering.rb +9 -11
- data/lib/abstract_controller/translation.rb +5 -4
- data/lib/abstract_controller/url_for.rb +4 -6
- data/lib/action_controller/api.rb +7 -7
- data/lib/action_controller/base.rb +5 -4
- data/lib/action_controller/form_builder.rb +2 -2
- data/lib/action_controller/log_subscriber.rb +4 -3
- data/lib/action_controller/metal/basic_implicit_render.rb +3 -1
- data/lib/action_controller/metal/conditional_get.rb +137 -102
- data/lib/action_controller/metal/content_security_policy.rb +36 -2
- data/lib/action_controller/metal/cookies.rb +1 -1
- data/lib/action_controller/metal/data_streaming.rb +23 -31
- data/lib/action_controller/metal/etag_with_flash.rb +1 -1
- data/lib/action_controller/metal/exceptions.rb +19 -30
- data/lib/action_controller/metal/flash.rb +6 -2
- data/lib/action_controller/metal/head.rb +1 -1
- data/lib/action_controller/metal/helpers.rb +2 -2
- data/lib/action_controller/metal/http_authentication.rb +66 -39
- data/lib/action_controller/metal/instrumentation.rb +57 -52
- data/lib/action_controller/metal/live.rb +43 -2
- data/lib/action_controller/metal/mime_responds.rb +3 -3
- data/lib/action_controller/metal/params_wrapper.rb +20 -11
- data/lib/action_controller/metal/permissions_policy.rb +19 -28
- data/lib/action_controller/metal/redirecting.rb +95 -22
- data/lib/action_controller/metal/renderers.rb +12 -13
- data/lib/action_controller/metal/rendering.rb +121 -9
- data/lib/action_controller/metal/request_forgery_protection.rb +83 -32
- data/lib/action_controller/metal/rescue.rb +5 -4
- data/lib/action_controller/metal/streaming.rb +7 -9
- data/lib/action_controller/metal/strong_parameters.rb +138 -115
- data/lib/action_controller/metal/testing.rb +9 -2
- data/lib/action_controller/metal/url_for.rb +3 -5
- data/lib/action_controller/metal.rb +10 -13
- data/lib/action_controller/railtie.rb +50 -6
- data/lib/action_controller/renderer.rb +1 -20
- data/lib/action_controller/test_case.rb +28 -7
- data/lib/action_controller.rb +2 -5
- data/lib/action_dispatch/http/cache.rb +20 -13
- data/lib/action_dispatch/http/content_security_policy.rb +113 -36
- data/lib/action_dispatch/http/filter_parameters.rb +4 -19
- data/lib/action_dispatch/http/headers.rb +1 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +15 -5
- data/lib/action_dispatch/http/mime_type.rb +9 -11
- data/lib/action_dispatch/http/parameters.rb +5 -5
- data/lib/action_dispatch/http/permissions_policy.rb +17 -1
- data/lib/action_dispatch/http/request.rb +27 -37
- data/lib/action_dispatch/http/response.rb +3 -20
- data/lib/action_dispatch/http/upload.rb +13 -2
- data/lib/action_dispatch/http/url.rb +11 -19
- data/lib/action_dispatch/journey/gtg/builder.rb +11 -12
- data/lib/action_dispatch/journey/gtg/simulator.rb +10 -4
- data/lib/action_dispatch/journey/gtg/transition_table.rb +77 -21
- data/lib/action_dispatch/journey/nodes/node.rb +70 -5
- data/lib/action_dispatch/journey/path/pattern.rb +22 -13
- data/lib/action_dispatch/journey/route.rb +6 -13
- data/lib/action_dispatch/journey/router/utils.rb +2 -2
- data/lib/action_dispatch/journey/router.rb +1 -1
- data/lib/action_dispatch/journey/routes.rb +3 -3
- data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
- data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +0 -1
- data/lib/action_dispatch/middleware/cookies.rb +20 -13
- data/lib/action_dispatch/middleware/debug_exceptions.rb +6 -4
- data/lib/action_dispatch/middleware/debug_locks.rb +3 -3
- data/lib/action_dispatch/middleware/exception_wrapper.rb +4 -0
- data/lib/action_dispatch/middleware/executor.rb +3 -0
- data/lib/action_dispatch/middleware/flash.rb +17 -18
- data/lib/action_dispatch/middleware/host_authorization.rb +13 -17
- data/lib/action_dispatch/middleware/remote_ip.rb +20 -8
- data/lib/action_dispatch/middleware/request_id.rb +3 -3
- data/lib/action_dispatch/middleware/server_timing.rb +76 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +1 -1
- data/lib/action_dispatch/middleware/session/cookie_store.rb +9 -9
- data/lib/action_dispatch/middleware/show_exceptions.rb +17 -16
- data/lib/action_dispatch/middleware/stack.rb +27 -9
- data/lib/action_dispatch/middleware/static.rb +5 -9
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +4 -11
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +10 -5
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +7 -3
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +28 -18
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +22 -22
- data/lib/action_dispatch/railtie.rb +8 -2
- data/lib/action_dispatch/request/session.rb +43 -13
- data/lib/action_dispatch/routing/inspector.rb +1 -1
- data/lib/action_dispatch/routing/mapper.rb +82 -83
- data/lib/action_dispatch/routing/redirection.rb +5 -2
- data/lib/action_dispatch/routing/route_set.rb +17 -7
- data/lib/action_dispatch/routing/routes_proxy.rb +1 -1
- data/lib/action_dispatch/routing/url_for.rb +24 -25
- data/lib/action_dispatch/routing.rb +5 -6
- data/lib/action_dispatch/system_test_case.rb +5 -5
- data/lib/action_dispatch/system_testing/browser.rb +3 -13
- data/lib/action_dispatch/system_testing/driver.rb +34 -10
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +11 -7
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +0 -8
- data/lib/action_dispatch/testing/assertions/response.rb +1 -1
- data/lib/action_dispatch/testing/assertions/routing.rb +3 -2
- data/lib/action_dispatch/testing/assertions.rb +2 -5
- data/lib/action_dispatch/testing/integration.rb +6 -8
- data/lib/action_dispatch/testing/test_process.rb +3 -29
- data/lib/action_dispatch/testing/test_response.rb +20 -2
- data/lib/action_dispatch.rb +1 -0
- data/lib/action_pack/gem_version.rb +5 -5
- data/lib/action_pack/version.rb +1 -1
- metadata +16 -15
@@ -9,11 +9,14 @@ module ActionController
|
|
9
9
|
# Wraps the parameters hash into a nested hash. This will allow clients to
|
10
10
|
# submit requests without having to specify any root elements.
|
11
11
|
#
|
12
|
-
# This functionality is enabled
|
13
|
-
#
|
12
|
+
# This functionality is enabled by default for JSON, and can be customized by
|
13
|
+
# setting the format array:
|
14
14
|
#
|
15
|
-
#
|
16
|
-
#
|
15
|
+
# class ApplicationController < ActionController::Base
|
16
|
+
# wrap_parameters format: [:json, :xml]
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# You could also turn it on per controller:
|
17
20
|
#
|
18
21
|
# class UsersController < ApplicationController
|
19
22
|
# wrap_parameters format: [:json, :xml, :url_encoded_form, :multipart_form]
|
@@ -68,6 +71,12 @@ module ActionController
|
|
68
71
|
# will try to check if <tt>Admin::User</tt> or +User+ model exists, and use it to
|
69
72
|
# determine the wrapper key respectively. If both models don't exist,
|
70
73
|
# it will then fallback to use +user+ as the key.
|
74
|
+
#
|
75
|
+
# To disable this functionality for a controller:
|
76
|
+
#
|
77
|
+
# class UsersController < ApplicationController
|
78
|
+
# wrap_parameters false
|
79
|
+
# end
|
71
80
|
module ParamsWrapper
|
72
81
|
extend ActiveSupport::Concern
|
73
82
|
|
@@ -242,14 +251,14 @@ module ActionController
|
|
242
251
|
end
|
243
252
|
end
|
244
253
|
|
245
|
-
# Performs parameters wrapping upon the request. Called automatically
|
246
|
-
# by the metal call stack.
|
247
|
-
def process_action(*)
|
248
|
-
_perform_parameter_wrapping if _wrapper_enabled?
|
249
|
-
super
|
250
|
-
end
|
251
|
-
|
252
254
|
private
|
255
|
+
# Performs parameters wrapping upon the request. Called automatically
|
256
|
+
# by the metal call stack.
|
257
|
+
def process_action(*)
|
258
|
+
_perform_parameter_wrapping if _wrapper_enabled?
|
259
|
+
super
|
260
|
+
end
|
261
|
+
|
253
262
|
# Returns the wrapper key which will be used to store wrapped parameters.
|
254
263
|
def _wrapper_key
|
255
264
|
_wrapper_options.name
|
@@ -1,37 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module ActionController
|
4
|
-
# HTTP Permissions Policy is a web standard for defining a mechanism to
|
5
|
-
# allow and deny the use of browser permissions in its own context, and
|
6
|
-
# in content within any <iframe> elements in the document.
|
7
|
-
#
|
8
|
-
# Full details of HTTP Permissions Policy specification and guidelines can
|
9
|
-
# be found at MDN:
|
10
|
-
#
|
11
|
-
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy
|
12
|
-
#
|
13
|
-
# Examples of usage:
|
14
|
-
#
|
15
|
-
# # Global policy
|
16
|
-
# Rails.application.config.permissions_policy do |f|
|
17
|
-
# f.camera :none
|
18
|
-
# f.gyroscope :none
|
19
|
-
# f.microphone :none
|
20
|
-
# f.usb :none
|
21
|
-
# f.fullscreen :self
|
22
|
-
# f.payment :self, "https://secure.example.com"
|
23
|
-
# end
|
24
|
-
#
|
25
|
-
# # Controller level policy
|
26
|
-
# class PagesController < ApplicationController
|
27
|
-
# permissions_policy do |p|
|
28
|
-
# p.geolocation "https://example.com"
|
29
|
-
# end
|
30
|
-
# end
|
3
|
+
module ActionController # :nodoc:
|
31
4
|
module PermissionsPolicy
|
32
5
|
extend ActiveSupport::Concern
|
33
6
|
|
34
7
|
module ClassMethods
|
8
|
+
# Overrides parts of the globally configured +Feature-Policy+
|
9
|
+
# header:
|
10
|
+
#
|
11
|
+
# class PagesController < ApplicationController
|
12
|
+
# permissions_policy do |policy|
|
13
|
+
# policy.geolocation "https://example.com"
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# Options can be passed similar to +before_action+. For example, pass
|
18
|
+
# <tt>only: :index</tt> to override the header on the index action only:
|
19
|
+
#
|
20
|
+
# class PagesController < ApplicationController
|
21
|
+
# permissions_policy(only: :index) do |policy|
|
22
|
+
# policy.camera :self
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
#
|
35
26
|
def permissions_policy(**options, &block)
|
36
27
|
before_action(options) do
|
37
28
|
if block_given?
|
@@ -4,13 +4,17 @@ module ActionController
|
|
4
4
|
module Redirecting
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
|
+
ILLEGAL_HEADER_VALUE_REGEX = /[\x00-\x08\x0A-\x1F]/.freeze
|
8
|
+
|
7
9
|
include AbstractController::Logger
|
8
10
|
include ActionController::UrlFor
|
9
11
|
|
10
|
-
ILLEGAL_HEADER_VALUE_REGEX = /[\x00-\x08\x0A-\x1F]/.freeze
|
11
|
-
|
12
12
|
class UnsafeRedirectError < StandardError; end
|
13
13
|
|
14
|
+
included do
|
15
|
+
mattr_accessor :raise_on_open_redirects, default: false
|
16
|
+
end
|
17
|
+
|
14
18
|
# Redirects the browser to the target specified in +options+. This parameter can be any one of:
|
15
19
|
#
|
16
20
|
# * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
|
@@ -58,20 +62,46 @@ module ActionController
|
|
58
62
|
#
|
59
63
|
# Statements after +redirect_to+ in our controller get executed, so +redirect_to+ doesn't stop the execution of the function.
|
60
64
|
# To terminate the execution of the function immediately after the +redirect_to+, use return.
|
65
|
+
#
|
61
66
|
# redirect_to post_url(@post) and return
|
67
|
+
#
|
68
|
+
# === Open Redirect protection
|
69
|
+
#
|
70
|
+
# By default, Rails protects against redirecting to external hosts for your app's safety, so called open redirects.
|
71
|
+
# Note: this was a new default in Rails 7.0, after upgrading opt-in by uncommenting the line with +raise_on_open_redirects+ in <tt>config/initializers/new_framework_defaults_7_0.rb</tt>
|
72
|
+
#
|
73
|
+
# Here #redirect_to automatically validates the potentially-unsafe URL:
|
74
|
+
#
|
75
|
+
# redirect_to params[:redirect_url]
|
76
|
+
#
|
77
|
+
# Raises UnsafeRedirectError in the case of an unsafe redirect.
|
78
|
+
#
|
79
|
+
# To allow any external redirects pass <tt>allow_other_host: true</tt>, though using a user-provided param in that case is unsafe.
|
80
|
+
#
|
81
|
+
# redirect_to "https://rubyonrails.org", allow_other_host: true
|
82
|
+
#
|
83
|
+
# 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.
|
62
84
|
def redirect_to(options = {}, response_options = {})
|
63
85
|
raise ActionControllerError.new("Cannot redirect to nil!") unless options
|
64
86
|
raise AbstractController::DoubleRenderError if response_body
|
65
87
|
|
66
|
-
|
88
|
+
allow_other_host = response_options.delete(:allow_other_host) { _allow_other_host }
|
89
|
+
|
90
|
+
self.status = _extract_redirect_to_status(options, response_options)
|
67
91
|
|
68
92
|
redirect_to_location = _compute_redirect_to_location(request, options)
|
69
93
|
_ensure_url_is_http_header_safe(redirect_to_location)
|
70
94
|
|
71
|
-
self.location = redirect_to_location
|
95
|
+
self.location = _enforce_open_redirect_protection(redirect_to_location, allow_other_host: allow_other_host)
|
72
96
|
self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(response.location)}\">redirected</a>.</body></html>"
|
73
97
|
end
|
74
98
|
|
99
|
+
# Soft deprecated alias for #redirect_back_or_to where the +fallback_location+ location is supplied as a keyword argument instead
|
100
|
+
# of the first positional argument.
|
101
|
+
def redirect_back(fallback_location:, allow_other_host: _allow_other_host, **args)
|
102
|
+
redirect_back_or_to fallback_location, allow_other_host: allow_other_host, **args
|
103
|
+
end
|
104
|
+
|
75
105
|
# Redirects the browser to the page that issued the request (the referrer)
|
76
106
|
# if possible, otherwise redirects to the provided default fallback
|
77
107
|
# location.
|
@@ -81,35 +111,37 @@ module ActionController
|
|
81
111
|
# subject to browser security settings and user preferences. If the request
|
82
112
|
# is missing this header, the <tt>fallback_location</tt> will be used.
|
83
113
|
#
|
84
|
-
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
114
|
+
# redirect_back_or_to({ action: "show", id: 5 })
|
115
|
+
# redirect_back_or_to @post
|
116
|
+
# redirect_back_or_to "http://www.rubyonrails.org"
|
117
|
+
# redirect_back_or_to "/images/screenshot.jpg"
|
118
|
+
# redirect_back_or_to posts_url
|
119
|
+
# redirect_back_or_to proc { edit_post_url(@post) }
|
120
|
+
# redirect_back_or_to '/', allow_other_host: false
|
91
121
|
#
|
92
122
|
# ==== Options
|
93
|
-
# * <tt>:fallback_location</tt> - The default fallback location that will be used on missing +Referer+ header.
|
94
123
|
# * <tt>:allow_other_host</tt> - Allow or disallow redirection to the host that is different to the current host, defaults to true.
|
95
124
|
#
|
96
125
|
# All other options that can be passed to #redirect_to are accepted as
|
97
|
-
# options and the behavior is identical.
|
98
|
-
def
|
99
|
-
referer
|
100
|
-
|
101
|
-
|
126
|
+
# options, and the behavior is identical.
|
127
|
+
def redirect_back_or_to(fallback_location, allow_other_host: _allow_other_host, **options)
|
128
|
+
if request.referer && (allow_other_host || _url_host_allowed?(request.referer))
|
129
|
+
redirect_to request.referer, allow_other_host: allow_other_host, **options
|
130
|
+
else
|
131
|
+
# The method level `allow_other_host` doesn't apply in the fallback case, omit and let the `redirect_to` handling take over.
|
132
|
+
redirect_to fallback_location, **options
|
133
|
+
end
|
102
134
|
end
|
103
135
|
|
104
|
-
def _compute_redirect_to_location(request, options)
|
136
|
+
def _compute_redirect_to_location(request, options) # :nodoc:
|
105
137
|
case options
|
106
138
|
# The scheme name consist of a letter followed by any combination of
|
107
139
|
# letters, digits, and the plus ("+"), period ("."), or hyphen ("-")
|
108
140
|
# characters; and is terminated by a colon (":").
|
109
141
|
# See https://tools.ietf.org/html/rfc3986#section-3.1
|
110
142
|
# The protocol relative scheme starts with a double slash "//".
|
111
|
-
when /\A([a-z][a-z\d
|
112
|
-
options
|
143
|
+
when /\A([a-z][a-z\d\-+.]*:|\/\/).*/i
|
144
|
+
options.to_str
|
113
145
|
when String
|
114
146
|
request.protocol + request.host_with_port + options
|
115
147
|
when Proc
|
@@ -121,7 +153,35 @@ module ActionController
|
|
121
153
|
module_function :_compute_redirect_to_location
|
122
154
|
public :_compute_redirect_to_location
|
123
155
|
|
156
|
+
# Verifies the passed +location+ is an internal URL that's safe to redirect to and returns it, or nil if not.
|
157
|
+
# Useful to wrap a params provided redirect URL and fallback to an alternate URL to redirect to:
|
158
|
+
#
|
159
|
+
# redirect_to url_from(params[:redirect_url]) || root_url
|
160
|
+
#
|
161
|
+
# The +location+ is considered internal, and safe, if it's on the same host as <tt>request.host</tt>:
|
162
|
+
#
|
163
|
+
# # If request.host is example.com:
|
164
|
+
# url_from("https://example.com/profile") # => "https://example.com/profile"
|
165
|
+
# url_from("http://example.com/profile") # => "http://example.com/profile"
|
166
|
+
# url_from("http://evil.com/profile") # => nil
|
167
|
+
#
|
168
|
+
# Subdomains are considered part of the host:
|
169
|
+
#
|
170
|
+
# # If request.host is on https://example.com or https://app.example.com, you'd get:
|
171
|
+
# url_from("https://dev.example.com/profile") # => nil
|
172
|
+
#
|
173
|
+
# NOTE: there's a similarity with {url_for}[rdoc-ref:ActionDispatch::Routing::UrlFor#url_for], which generates an internal URL from various options from within the app, e.g. <tt>url_for(@post)</tt>.
|
174
|
+
# However, #url_from is meant to take an external parameter to verify as in <tt>url_from(params[:redirect_url])</tt>.
|
175
|
+
def url_from(location)
|
176
|
+
location = location.presence
|
177
|
+
location if location && _url_host_allowed?(location)
|
178
|
+
end
|
179
|
+
|
124
180
|
private
|
181
|
+
def _allow_other_host
|
182
|
+
!raise_on_open_redirects
|
183
|
+
end
|
184
|
+
|
125
185
|
def _extract_redirect_to_status(options, response_options)
|
126
186
|
if options.is_a?(Hash) && options.key?(:status)
|
127
187
|
Rack::Utils.status_code(options.delete(:status))
|
@@ -132,8 +192,21 @@ module ActionController
|
|
132
192
|
end
|
133
193
|
end
|
134
194
|
|
195
|
+
def _enforce_open_redirect_protection(location, allow_other_host:)
|
196
|
+
if allow_other_host || _url_host_allowed?(location)
|
197
|
+
location
|
198
|
+
else
|
199
|
+
raise UnsafeRedirectError, "Unsafe redirect to #{location.truncate(100).inspect}, pass allow_other_host: true to redirect anyway."
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
135
203
|
def _url_host_allowed?(url)
|
136
|
-
URI(url.to_s).host
|
204
|
+
host = URI(url.to_s).host
|
205
|
+
|
206
|
+
return true if host == request.host
|
207
|
+
return false unless host.nil?
|
208
|
+
return false unless url.to_s.start_with?("/")
|
209
|
+
!url.to_s.start_with?("//")
|
137
210
|
rescue ArgumentError, URI::Error
|
138
211
|
false
|
139
212
|
end
|
@@ -142,7 +215,7 @@ module ActionController
|
|
142
215
|
# Attempt to comply with the set of valid token characters
|
143
216
|
# defined for an HTTP header value in
|
144
217
|
# https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6
|
145
|
-
if url.match(ILLEGAL_HEADER_VALUE_REGEX)
|
218
|
+
if url.match?(ILLEGAL_HEADER_VALUE_REGEX)
|
146
219
|
msg = "The redirect URL #{url} contains one or more illegal HTTP header field character. " \
|
147
220
|
"Set of legal characters defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6"
|
148
221
|
raise UnsafeRedirectError, msg
|
@@ -3,12 +3,12 @@
|
|
3
3
|
require "set"
|
4
4
|
|
5
5
|
module ActionController
|
6
|
-
# See
|
6
|
+
# See Renderers.add
|
7
7
|
def self.add_renderer(key, &block)
|
8
8
|
Renderers.add(key, &block)
|
9
9
|
end
|
10
10
|
|
11
|
-
# See
|
11
|
+
# See Renderers.remove
|
12
12
|
def self.remove_renderer(key)
|
13
13
|
Renderers.remove(key)
|
14
14
|
end
|
@@ -31,8 +31,7 @@ module ActionController
|
|
31
31
|
class_attribute :_renderers, default: Set.new.freeze
|
32
32
|
end
|
33
33
|
|
34
|
-
# Used in
|
35
|
-
# and <tt>ActionController::API</tt> to include all
|
34
|
+
# Used in ActionController::Base and ActionController::API to include all
|
36
35
|
# renderers by default.
|
37
36
|
module All
|
38
37
|
extend ActiveSupport::Concern
|
@@ -45,7 +44,7 @@ module ActionController
|
|
45
44
|
|
46
45
|
# Adds a new renderer to call within controller actions.
|
47
46
|
# A renderer is invoked by passing its name as an option to
|
48
|
-
#
|
47
|
+
# AbstractController::Rendering#render. To create a renderer
|
49
48
|
# pass it a name and a block. The block takes two arguments, the first
|
50
49
|
# is the value paired with its key and the second is the remaining
|
51
50
|
# hash of options passed to +render+.
|
@@ -96,18 +95,18 @@ module ActionController
|
|
96
95
|
# Adds, by name, a renderer or renderers to the +_renderers+ available
|
97
96
|
# to call within controller actions.
|
98
97
|
#
|
99
|
-
# It is useful when rendering from an
|
98
|
+
# It is useful when rendering from an ActionController::Metal controller or
|
100
99
|
# otherwise to add an available renderer proc to a specific controller.
|
101
100
|
#
|
102
|
-
# Both
|
103
|
-
# include
|
101
|
+
# Both ActionController::Base and ActionController::API
|
102
|
+
# include ActionController::Renderers::All, making all renderers
|
104
103
|
# available in the controller. See <tt>Renderers::RENDERERS</tt> and <tt>Renderers.add</tt>.
|
105
104
|
#
|
106
|
-
# Since
|
107
|
-
# must include
|
108
|
-
# and
|
105
|
+
# Since ActionController::Metal controllers cannot render, the controller
|
106
|
+
# must include AbstractController::Rendering, ActionController::Rendering,
|
107
|
+
# and ActionController::Renderers, and have at least one renderer.
|
109
108
|
#
|
110
|
-
# Rather than including
|
109
|
+
# Rather than including ActionController::Renderers::All and including all renderers,
|
111
110
|
# you may specify which renderers to include by passing the renderer name or names to
|
112
111
|
# +use_renderers+. For example, a controller that includes only the <tt>:json</tt> renderer
|
113
112
|
# (+_render_with_renderer_json+) might look like:
|
@@ -133,7 +132,7 @@ module ActionController
|
|
133
132
|
alias use_renderer use_renderers
|
134
133
|
end
|
135
134
|
|
136
|
-
# Called by +render+ in
|
135
|
+
# Called by +render+ in AbstractController::Rendering
|
137
136
|
# which sets the return value as the +response_body+.
|
138
137
|
#
|
139
138
|
# If no renderer is found, +super+ returns control to
|
@@ -24,19 +24,125 @@ module ActionController
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
# Renders a template and assigns the result to +self.response_body+.
|
28
|
+
#
|
29
|
+
# If no rendering mode option is specified, the template will be derived
|
30
|
+
# from the first argument.
|
31
|
+
#
|
32
|
+
# render "posts/show"
|
33
|
+
# # => renders app/views/posts/show.html.erb
|
34
|
+
#
|
35
|
+
# # In a PostsController action...
|
36
|
+
# render :show
|
37
|
+
# # => renders app/views/posts/show.html.erb
|
38
|
+
#
|
39
|
+
# If the first argument responds to +render_in+, the template will be
|
40
|
+
# rendered by calling +render_in+ with the current view context.
|
41
|
+
#
|
42
|
+
# ==== \Rendering Mode
|
43
|
+
#
|
44
|
+
# [+:partial+]
|
45
|
+
# See ActionView::PartialRenderer for details.
|
46
|
+
#
|
47
|
+
# render partial: "posts/form", locals: { post: Post.new }
|
48
|
+
# # => renders app/views/posts/_form.html.erb
|
49
|
+
#
|
50
|
+
# [+:file+]
|
51
|
+
# Renders the contents of a file. This option should <b>not</b> be used
|
52
|
+
# with unsanitized user input.
|
53
|
+
#
|
54
|
+
# render file: "/path/to/some/file"
|
55
|
+
# # => renders /path/to/some/file
|
56
|
+
#
|
57
|
+
# [+:inline+]
|
58
|
+
# Renders an ERB template string.
|
59
|
+
#
|
60
|
+
# @name = "World"
|
61
|
+
# render inline: "<h1>Hello, <%= @name %>!</h1>"
|
62
|
+
# # => renders "<h1>Hello, World!</h1>"
|
63
|
+
#
|
64
|
+
# [+:body+]
|
65
|
+
# Renders the provided text, and sets the content type as +text/plain+.
|
66
|
+
#
|
67
|
+
# render body: "Hello, World!"
|
68
|
+
# # => renders "Hello, World!"
|
69
|
+
#
|
70
|
+
# [+:plain+]
|
71
|
+
# Renders the provided text, and sets the content type as +text/plain+.
|
72
|
+
#
|
73
|
+
# render plain: "Hello, World!"
|
74
|
+
# # => renders "Hello, World!"
|
75
|
+
#
|
76
|
+
# [+:html+]
|
77
|
+
# Renders the provided HTML string, and sets the content type as +text/html+.
|
78
|
+
# If the string is not +html_safe?+, performs HTML escaping on the string
|
79
|
+
# before rendering.
|
80
|
+
#
|
81
|
+
# render html: "<h1>Hello, World!</h1>".html_safe
|
82
|
+
# # => renders "<h1>Hello, World!</h1>"
|
83
|
+
#
|
84
|
+
# render html: "<h1>Hello, World!</h1>"
|
85
|
+
# # => renders "<h1>Hello, World!</h1>"
|
86
|
+
#
|
87
|
+
# [+:json+]
|
88
|
+
# Renders the provided object as JSON, and sets the content type as
|
89
|
+
# +application/json+. If the object is not a string, it will be converted
|
90
|
+
# to JSON by calling +to_json+.
|
91
|
+
#
|
92
|
+
# render json: { hello: "world" }
|
93
|
+
# # => renders "{\"hello\":\"world\"}"
|
94
|
+
#
|
95
|
+
# By default, when a rendering mode is specified, no layout template is
|
96
|
+
# rendered.
|
97
|
+
#
|
98
|
+
# ==== Options
|
99
|
+
#
|
100
|
+
# [+:assigns+]
|
101
|
+
# Hash of instance variable assignments for the template.
|
102
|
+
#
|
103
|
+
# render inline: "<h1>Hello, <%= @name %>!</h1>", assigns: { name: "World" }
|
104
|
+
# # => renders "<h1>Hello, World!</h1>"
|
105
|
+
#
|
106
|
+
# [+:locals+]
|
107
|
+
# Hash of local variable assignments for the template.
|
108
|
+
#
|
109
|
+
# render inline: "<h1>Hello, <%= name %>!</h1>", locals: { name: "World" }
|
110
|
+
# # => renders "<h1>Hello, World!</h1>"
|
111
|
+
#
|
112
|
+
# [+:layout+]
|
113
|
+
# The layout template to render. Can also be +false+ or +true+ to disable
|
114
|
+
# or (re)enable the default layout template.
|
115
|
+
#
|
116
|
+
# render "posts/show", layout: "holiday"
|
117
|
+
# # => renders app/views/posts/show.html.erb with the app/views/layouts/holiday.html.erb layout
|
118
|
+
#
|
119
|
+
# render "posts/show", layout: false
|
120
|
+
# # => renders app/views/posts/show.html.erb with no layout
|
121
|
+
#
|
122
|
+
# render inline: "<h1>Hello, World!</h1>", layout: true
|
123
|
+
# # => renders "<h1>Hello, World!</h1>" with the default layout
|
124
|
+
#
|
125
|
+
# [+:status+]
|
126
|
+
# The HTTP status code to send with the response. Can be specified as a
|
127
|
+
# number or as the status name in Symbol form. Defaults to 200.
|
128
|
+
#
|
129
|
+
# render "posts/new", status: 422
|
130
|
+
# # => renders app/views/posts/new.html.erb with HTTP status code 422
|
131
|
+
#
|
132
|
+
# render "posts/new", status: :unprocessable_entity
|
133
|
+
# # => renders app/views/posts/new.html.erb with HTTP status code 422
|
134
|
+
#
|
135
|
+
#--
|
33
136
|
# Check for double render errors and set the content_type after rendering.
|
34
|
-
def render(*args)
|
137
|
+
def render(*args)
|
35
138
|
raise ::AbstractController::DoubleRenderError if response_body
|
36
139
|
super
|
37
140
|
end
|
38
141
|
|
39
|
-
#
|
142
|
+
# Similar to #render, but only returns the rendered template as a string,
|
143
|
+
# instead of setting +self.response_body+.
|
144
|
+
#--
|
145
|
+
# Override render_to_string because body can now be set to a Rack body.
|
40
146
|
def render_to_string(*)
|
41
147
|
result = super
|
42
148
|
if result.respond_to?(:each)
|
@@ -48,11 +154,17 @@ module ActionController
|
|
48
154
|
end
|
49
155
|
end
|
50
156
|
|
51
|
-
def render_to_body(options = {})
|
157
|
+
def render_to_body(options = {}) # :nodoc:
|
52
158
|
super || _render_in_priorities(options) || " "
|
53
159
|
end
|
54
160
|
|
55
161
|
private
|
162
|
+
# Before processing, set the request formats in current controller formats.
|
163
|
+
def process_action(*) # :nodoc:
|
164
|
+
self.formats = request.formats.filter_map(&:ref)
|
165
|
+
super
|
166
|
+
end
|
167
|
+
|
56
168
|
def _process_variant(options)
|
57
169
|
if defined?(request) && !request.nil? && request.variant.present?
|
58
170
|
options[:variant] = request.variant
|