actionpack 6.1.7.5 → 7.0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +323 -399
- 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 +27 -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
|