actionpack 7.0.5 → 7.1.3.4
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 +368 -315
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/lib/abstract_controller/base.rb +20 -11
- data/lib/abstract_controller/caching/fragments.rb +2 -0
- data/lib/abstract_controller/callbacks.rb +31 -6
- data/lib/abstract_controller/deprecator.rb +7 -0
- data/lib/abstract_controller/helpers.rb +68 -22
- data/lib/abstract_controller/railties/routes_helpers.rb +1 -16
- data/lib/abstract_controller/rendering.rb +3 -3
- data/lib/abstract_controller/translation.rb +9 -6
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/abstract_controller.rb +6 -0
- data/lib/action_controller/api.rb +5 -3
- data/lib/action_controller/base.rb +3 -17
- data/lib/action_controller/caching.rb +2 -0
- data/lib/action_controller/deprecator.rb +7 -0
- data/lib/action_controller/form_builder.rb +2 -0
- data/lib/action_controller/log_subscriber.rb +16 -4
- data/lib/action_controller/metal/content_security_policy.rb +1 -1
- data/lib/action_controller/metal/data_streaming.rb +2 -0
- data/lib/action_controller/metal/default_headers.rb +2 -0
- data/lib/action_controller/metal/etag_with_flash.rb +2 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +2 -0
- data/lib/action_controller/metal/exceptions.rb +8 -0
- data/lib/action_controller/metal/head.rb +8 -6
- data/lib/action_controller/metal/helpers.rb +3 -14
- data/lib/action_controller/metal/http_authentication.rb +17 -8
- data/lib/action_controller/metal/implicit_render.rb +5 -3
- data/lib/action_controller/metal/instrumentation.rb +8 -1
- data/lib/action_controller/metal/live.rb +24 -0
- data/lib/action_controller/metal/mime_responds.rb +2 -2
- data/lib/action_controller/metal/params_wrapper.rb +4 -2
- data/lib/action_controller/metal/permissions_policy.rb +1 -1
- data/lib/action_controller/metal/redirecting.rb +24 -7
- data/lib/action_controller/metal/renderers.rb +4 -4
- data/lib/action_controller/metal/rendering.rb +0 -7
- data/lib/action_controller/metal/request_forgery_protection.rb +139 -50
- data/lib/action_controller/metal/rescue.rb +6 -3
- data/lib/action_controller/metal/streaming.rb +70 -30
- data/lib/action_controller/metal/strong_parameters.rb +158 -101
- data/lib/action_controller/metal/url_for.rb +7 -0
- data/lib/action_controller/metal.rb +79 -21
- data/lib/action_controller/railtie.rb +22 -9
- data/lib/action_controller/renderer.rb +98 -65
- data/lib/action_controller/test_case.rb +15 -5
- data/lib/action_controller.rb +8 -1
- data/lib/action_dispatch/constants.rb +32 -0
- data/lib/action_dispatch/deprecator.rb +7 -0
- data/lib/action_dispatch/http/cache.rb +1 -3
- data/lib/action_dispatch/http/content_security_policy.rb +9 -8
- data/lib/action_dispatch/http/filter_parameters.rb +11 -5
- data/lib/action_dispatch/http/headers.rb +2 -0
- data/lib/action_dispatch/http/mime_negotiation.rb +22 -22
- data/lib/action_dispatch/http/mime_type.rb +35 -12
- data/lib/action_dispatch/http/mime_types.rb +3 -1
- data/lib/action_dispatch/http/parameters.rb +1 -1
- data/lib/action_dispatch/http/permissions_policy.rb +38 -23
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +48 -14
- data/lib/action_dispatch/http/response.rb +80 -59
- data/lib/action_dispatch/http/upload.rb +2 -0
- data/lib/action_dispatch/journey/formatter.rb +8 -2
- data/lib/action_dispatch/journey/path/pattern.rb +14 -14
- data/lib/action_dispatch/journey/route.rb +3 -2
- data/lib/action_dispatch/journey/router.rb +9 -8
- data/lib/action_dispatch/journey/routes.rb +2 -2
- data/lib/action_dispatch/log_subscriber.rb +23 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +5 -6
- data/lib/action_dispatch/middleware/assume_ssl.rb +24 -0
- data/lib/action_dispatch/middleware/callbacks.rb +2 -0
- data/lib/action_dispatch/middleware/cookies.rb +81 -98
- data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -25
- data/lib/action_dispatch/middleware/debug_locks.rb +4 -1
- data/lib/action_dispatch/middleware/debug_view.rb +7 -2
- data/lib/action_dispatch/middleware/exception_wrapper.rb +186 -27
- data/lib/action_dispatch/middleware/executor.rb +1 -1
- data/lib/action_dispatch/middleware/flash.rb +7 -0
- data/lib/action_dispatch/middleware/host_authorization.rb +18 -8
- data/lib/action_dispatch/middleware/public_exceptions.rb +5 -3
- data/lib/action_dispatch/middleware/reloader.rb +7 -5
- data/lib/action_dispatch/middleware/remote_ip.rb +17 -16
- data/lib/action_dispatch/middleware/request_id.rb +2 -0
- data/lib/action_dispatch/middleware/server_timing.rb +4 -4
- data/lib/action_dispatch/middleware/session/abstract_store.rb +5 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +11 -5
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +3 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +25 -18
- data/lib/action_dispatch/middleware/ssl.rb +18 -6
- data/lib/action_dispatch/middleware/stack.rb +7 -2
- data/lib/action_dispatch/middleware/static.rb +12 -8
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -3
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -3
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +7 -7
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +17 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +16 -12
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +46 -37
- data/lib/action_dispatch/railtie.rb +14 -4
- data/lib/action_dispatch/request/session.rb +16 -6
- data/lib/action_dispatch/request/utils.rb +8 -3
- data/lib/action_dispatch/routing/inspector.rb +54 -6
- data/lib/action_dispatch/routing/mapper.rb +35 -24
- data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -0
- data/lib/action_dispatch/routing/redirection.rb +15 -6
- data/lib/action_dispatch/routing/route_set.rb +52 -22
- data/lib/action_dispatch/routing/routes_proxy.rb +10 -15
- data/lib/action_dispatch/routing/url_for.rb +5 -1
- data/lib/action_dispatch/routing.rb +7 -7
- data/lib/action_dispatch/system_test_case.rb +3 -3
- data/lib/action_dispatch/system_testing/browser.rb +20 -19
- data/lib/action_dispatch/system_testing/driver.rb +13 -21
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +27 -16
- data/lib/action_dispatch/testing/assertion_response.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +13 -6
- data/lib/action_dispatch/testing/assertions/routing.rb +67 -28
- data/lib/action_dispatch/testing/assertions.rb +3 -1
- data/lib/action_dispatch/testing/integration.rb +27 -17
- data/lib/action_dispatch/testing/request_encoder.rb +4 -1
- data/lib/action_dispatch/testing/test_process.rb +4 -3
- data/lib/action_dispatch/testing/test_request.rb +1 -1
- data/lib/action_dispatch/testing/test_response.rb +23 -9
- data/lib/action_dispatch.rb +37 -4
- data/lib/action_pack/gem_version.rb +4 -4
- data/lib/action_pack/version.rb +1 -1
- data/lib/action_pack.rb +1 -1
- metadata +67 -31
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionController
|
4
|
+
# = Action Controller Etag With Template \Digest
|
5
|
+
#
|
4
6
|
# When our views change, they should bubble up into HTTP cache freshness
|
5
7
|
# and bust browser caches. So the template digest for the current action
|
6
8
|
# is automatically included in the ETag.
|
@@ -92,5 +92,13 @@ module ActionController
|
|
92
92
|
end
|
93
93
|
|
94
94
|
class MissingExactTemplate < UnknownFormat # :nodoc:
|
95
|
+
attr_reader :controller, :action_name
|
96
|
+
|
97
|
+
def initialize(message, controller, action_name)
|
98
|
+
@controller = controller
|
99
|
+
@action_name = action_name
|
100
|
+
|
101
|
+
super(message)
|
102
|
+
end
|
95
103
|
end
|
96
104
|
end
|
@@ -18,18 +18,20 @@ module ActionController
|
|
18
18
|
# render
|
19
19
|
#
|
20
20
|
# See +Rack::Utils::SYMBOL_TO_STATUS_CODE+ for a full list of valid +status+ symbols.
|
21
|
-
def head(status, options =
|
21
|
+
def head(status, options = nil)
|
22
22
|
if status.is_a?(Hash)
|
23
23
|
raise ArgumentError, "#{status.inspect} is not a valid value for `status`."
|
24
24
|
end
|
25
25
|
|
26
26
|
status ||= :ok
|
27
27
|
|
28
|
-
|
29
|
-
|
28
|
+
if options
|
29
|
+
location = options.delete(:location)
|
30
|
+
content_type = options.delete(:content_type)
|
30
31
|
|
31
|
-
|
32
|
-
|
32
|
+
options.each do |key, value|
|
33
|
+
headers[key.to_s.split(/[-_]/).each { |v| v[0] = v[0].upcase }.join("-")] = value.to_s
|
34
|
+
end
|
33
35
|
end
|
34
36
|
|
35
37
|
self.status = status
|
@@ -37,7 +39,7 @@ module ActionController
|
|
37
39
|
|
38
40
|
if include_content?(response_code)
|
39
41
|
unless self.media_type
|
40
|
-
self.content_type = content_type || (Mime[
|
42
|
+
self.content_type = content_type || ((f = formats) && Mime[f.first]) || Mime[:html]
|
41
43
|
end
|
42
44
|
|
43
45
|
response.charset = false
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionController
|
4
|
+
# = Action Controller \Helpers
|
5
|
+
#
|
4
6
|
# The \Rails framework provides a large number of helpers for working with assets, dates, forms,
|
5
7
|
# numbers and model objects, to name a few. These helpers are available to all templates
|
6
8
|
# by default.
|
@@ -80,7 +82,7 @@ module ActionController
|
|
80
82
|
# Provides a proxy to access helper methods from outside the view.
|
81
83
|
#
|
82
84
|
# Note that the proxy is rendered under a different view context.
|
83
|
-
# This may cause incorrect
|
85
|
+
# This may cause incorrect behavior with capture methods. Consider
|
84
86
|
# using {helper}[rdoc-ref:AbstractController::Helpers::ClassMethods#helper]
|
85
87
|
# instead when using +capture+.
|
86
88
|
def helpers
|
@@ -104,19 +106,6 @@ module ActionController
|
|
104
106
|
super(args)
|
105
107
|
end
|
106
108
|
|
107
|
-
# Returns a list of helper names in a given path.
|
108
|
-
#
|
109
|
-
# ActionController::Base.all_helpers_from_path 'app/helpers'
|
110
|
-
# # => ["application", "chart", "rubygems"]
|
111
|
-
def all_helpers_from_path(path)
|
112
|
-
helpers = Array(path).flat_map do |_path|
|
113
|
-
names = Dir["#{_path}/**/*_helper.rb"].map { |file| file[_path.to_s.size + 1..-"_helper.rb".size - 1] }
|
114
|
-
names.sort!
|
115
|
-
end
|
116
|
-
helpers.uniq!
|
117
|
-
helpers
|
118
|
-
end
|
119
|
-
|
120
109
|
private
|
121
110
|
# Extract helper names from files in <tt>app/helpers/**/*_helper.rb</tt>
|
122
111
|
def all_application_helpers
|
@@ -21,7 +21,7 @@ module ActionController
|
|
21
21
|
# def edit
|
22
22
|
# render plain: "I'm only accessible if you know the password"
|
23
23
|
# end
|
24
|
-
#
|
24
|
+
# end
|
25
25
|
#
|
26
26
|
# === Advanced \Basic example
|
27
27
|
#
|
@@ -316,7 +316,7 @@ module ActionController
|
|
316
316
|
# of this document.
|
317
317
|
#
|
318
318
|
# The nonce is opaque to the client. Composed of Time, and hash of Time with secret
|
319
|
-
# key from the Rails session secret generated upon creation of project. Ensures
|
319
|
+
# key from the \Rails session secret generated upon creation of project. Ensures
|
320
320
|
# the time cannot be modified by client.
|
321
321
|
def nonce(secret_key, time = Time.now)
|
322
322
|
t = time.to_i
|
@@ -424,15 +424,20 @@ module ActionController
|
|
424
424
|
|
425
425
|
module ControllerMethods
|
426
426
|
# Authenticate using an HTTP Bearer token, or otherwise render an HTTP
|
427
|
-
# header requesting the client to send a Bearer token.
|
427
|
+
# header requesting the client to send a Bearer token. For the authentication
|
428
|
+
# to be considered successful, +login_procedure+ should return a non-nil
|
429
|
+
# value. Typically, the authenticated user is returned.
|
428
430
|
#
|
429
431
|
# See ActionController::HttpAuthentication::Token for example usage.
|
430
432
|
def authenticate_or_request_with_http_token(realm = "Application", message = nil, &login_procedure)
|
431
433
|
authenticate_with_http_token(&login_procedure) || request_http_token_authentication(realm, message)
|
432
434
|
end
|
433
435
|
|
434
|
-
# Authenticate using an HTTP Bearer token.
|
435
|
-
#
|
436
|
+
# Authenticate using an HTTP Bearer token.
|
437
|
+
# Returns the return value of +login_procedure+ if a
|
438
|
+
# token is found. Returns +nil+ if no token is found.
|
439
|
+
#
|
440
|
+
# See ActionController::HttpAuthentication::Token for example usage.
|
436
441
|
def authenticate_with_http_token(&login_procedure)
|
437
442
|
Token.authenticate(self, &login_procedure)
|
438
443
|
end
|
@@ -447,8 +452,8 @@ module ActionController
|
|
447
452
|
# If token Authorization header is present, call the login
|
448
453
|
# procedure with the present token and options.
|
449
454
|
#
|
450
|
-
# Returns the return value of
|
451
|
-
# token is found. Returns
|
455
|
+
# Returns the return value of +login_procedure+ if a
|
456
|
+
# token is found. Returns +nil+ if no token is found.
|
452
457
|
#
|
453
458
|
# ==== Parameters
|
454
459
|
#
|
@@ -502,11 +507,15 @@ module ActionController
|
|
502
507
|
array_params.each { |param| (param[1] || +"").gsub! %r/^"|"$/, "" }
|
503
508
|
end
|
504
509
|
|
510
|
+
WHITESPACED_AUTHN_PAIR_DELIMITERS = /\s*#{AUTHN_PAIR_DELIMITERS}\s*/
|
511
|
+
private_constant :WHITESPACED_AUTHN_PAIR_DELIMITERS
|
512
|
+
|
505
513
|
# This method takes an authorization body and splits up the key-value
|
506
514
|
# pairs by the standardized <tt>:</tt>, <tt>;</tt>, or <tt>\t</tt>
|
507
515
|
# delimiters defined in +AUTHN_PAIR_DELIMITERS+.
|
508
516
|
def raw_params(auth)
|
509
|
-
_raw_params = auth.sub(TOKEN_REGEX, "").split(
|
517
|
+
_raw_params = auth.sub(TOKEN_REGEX, "").split(WHITESPACED_AUTHN_PAIR_DELIMITERS)
|
518
|
+
_raw_params.reject!(&:empty?)
|
510
519
|
|
511
520
|
if !_raw_params.first&.start_with?(TOKEN_KEY)
|
512
521
|
_raw_params[0] = "#{TOKEN_KEY}#{_raw_params.first}"
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionController
|
4
|
+
# = Action Controller Implicit Render
|
5
|
+
#
|
4
6
|
# Handles implicit rendering for a controller action that does not
|
5
7
|
# explicitly respond with +render+, +respond_to+, +redirect+, or +head+.
|
6
8
|
#
|
@@ -17,12 +19,12 @@ module ActionController
|
|
17
19
|
# Second, if we DON'T find a template but the controller action does have
|
18
20
|
# templates for other formats, variants, etc., then we trust that you meant
|
19
21
|
# to provide a template for this response, too, and we raise
|
20
|
-
#
|
22
|
+
# ActionController::UnknownFormat with an explanation.
|
21
23
|
#
|
22
24
|
# Third, if we DON'T find a template AND the request is a page load in a web
|
23
25
|
# browser (technically, a non-XHR GET request for an HTML response) where
|
24
26
|
# you reasonably expect to have rendered a template, then we raise
|
25
|
-
#
|
27
|
+
# ActionController::MissingExactTemplate with an explanation.
|
26
28
|
#
|
27
29
|
# Finally, if we DON'T find a template AND the request isn't a browser page
|
28
30
|
# load, then we implicitly respond with <tt>204 No Content</tt>.
|
@@ -42,7 +44,7 @@ module ActionController
|
|
42
44
|
raise ActionController::UnknownFormat, message
|
43
45
|
elsif interactive_browser_request?
|
44
46
|
message = "#{self.class.name}\##{action_name} is missing a template for request formats: #{request.formats.map(&:to_s).join(',')}"
|
45
|
-
raise ActionController::MissingExactTemplate,
|
47
|
+
raise ActionController::MissingExactTemplate.new(message, self.class, action_name)
|
46
48
|
else
|
47
49
|
logger.info "No template found for #{self.class.name}\##{action_name}, rendering head :no_content" if logger
|
48
50
|
super
|
@@ -4,6 +4,8 @@ require "benchmark"
|
|
4
4
|
require "abstract_controller/logger"
|
5
5
|
|
6
6
|
module ActionController
|
7
|
+
# = Action Controller \Instrumentation
|
8
|
+
#
|
7
9
|
# Adds instrumentation to several ends in ActionController::Base. It also provides
|
8
10
|
# some hooks related with process_action. This allows an ORM like Active Record
|
9
11
|
# and/or DataMapper to plug in ActionController and show related information.
|
@@ -16,6 +18,11 @@ module ActionController
|
|
16
18
|
|
17
19
|
attr_internal :view_runtime
|
18
20
|
|
21
|
+
def initialize(...) # :nodoc:
|
22
|
+
super
|
23
|
+
self.view_runtime = nil
|
24
|
+
end
|
25
|
+
|
19
26
|
def render(*)
|
20
27
|
render_output = nil
|
21
28
|
self.view_runtime = cleanup_view_runtime do
|
@@ -58,7 +65,7 @@ module ActionController
|
|
58
65
|
headers: request.headers,
|
59
66
|
format: request.format.ref,
|
60
67
|
method: request.request_method,
|
61
|
-
path: request.
|
68
|
+
path: request.filtered_path
|
62
69
|
}
|
63
70
|
|
64
71
|
ActiveSupport::Notifications.instrument("start_processing.action_controller", raw_payload)
|
@@ -5,6 +5,8 @@ require "delegate"
|
|
5
5
|
require "active_support/json"
|
6
6
|
|
7
7
|
module ActionController
|
8
|
+
# = Action Controller \Live
|
9
|
+
#
|
8
10
|
# Mix this module into your controller, and all actions in that controller
|
9
11
|
# will be able to stream data to the client as it's written.
|
10
12
|
#
|
@@ -34,6 +36,21 @@ module ActionController
|
|
34
36
|
# The final caveat is that your actions are executed in a separate thread than
|
35
37
|
# the main thread. Make sure your actions are thread safe, and this shouldn't
|
36
38
|
# be a problem (don't share state across threads, etc).
|
39
|
+
#
|
40
|
+
# Note that \Rails includes +Rack::ETag+ by default, which will buffer your
|
41
|
+
# response. As a result, streaming responses may not work properly with Rack
|
42
|
+
# 2.2.x, and you may need to implement workarounds in your application.
|
43
|
+
# You can either set the +ETag+ or +Last-Modified+ response headers or remove
|
44
|
+
# +Rack::ETag+ from the middleware stack to address this issue.
|
45
|
+
#
|
46
|
+
# Here's an example of how you can set the +Last-Modified+ header if your Rack
|
47
|
+
# version is 2.2.x:
|
48
|
+
#
|
49
|
+
# def stream
|
50
|
+
# response.headers["Content-Type"] = "text/event-stream"
|
51
|
+
# response.headers["Last-Modified"] = Time.now.httpdate # Add this line if your Rack version is 2.2.x
|
52
|
+
# ...
|
53
|
+
# end
|
37
54
|
module Live
|
38
55
|
extend ActiveSupport::Concern
|
39
56
|
|
@@ -49,6 +66,8 @@ module ActionController
|
|
49
66
|
end
|
50
67
|
end
|
51
68
|
|
69
|
+
# = Action Controller \Live Server Sent Events
|
70
|
+
#
|
52
71
|
# This class provides the ability to write an SSE (Server Sent Event)
|
53
72
|
# to an IO stream. The class is initialized with a stream and can be used
|
54
73
|
# to either write a JSON string or an object which can be converted to JSON.
|
@@ -148,6 +167,11 @@ module ActionController
|
|
148
167
|
@ignore_disconnect = false
|
149
168
|
end
|
150
169
|
|
170
|
+
# ActionDispatch::Response delegates #to_ary to the internal ActionDispatch::Response::Buffer,
|
171
|
+
# defining #to_ary is an indicator that the response body can be buffered and/or cached by
|
172
|
+
# Rack middlewares, this is not the case for Live responses so we undefine it for this Buffer subclass.
|
173
|
+
undef_method :to_ary
|
174
|
+
|
151
175
|
def write(string)
|
152
176
|
unless @response.committed?
|
153
177
|
@response.headers["Cache-Control"] ||= "no-cache"
|
@@ -32,7 +32,7 @@ module ActionController # :nodoc:
|
|
32
32
|
#
|
33
33
|
# What that says is, "if the client wants HTML or JS in response to this action, just respond as we
|
34
34
|
# would have before, but if the client wants XML, return them the list of people in XML format."
|
35
|
-
# (Rails determines the desired response format from the HTTP Accept header submitted by the client.)
|
35
|
+
# (\Rails determines the desired response format from the HTTP Accept header submitted by the client.)
|
36
36
|
#
|
37
37
|
# Supposing you have an action that adds a new person, optionally creating their company
|
38
38
|
# (by name) if it does not already exist, without web-services, it might look like this:
|
@@ -98,7 +98,7 @@ module ActionController # :nodoc:
|
|
98
98
|
#
|
99
99
|
# Note that you can define your own XML parameter parser which would allow you to describe multiple entities
|
100
100
|
# in a single request (i.e., by wrapping them all in a single root node), but if you just go with the flow
|
101
|
-
# and accept Rails' defaults, life will be much easier.
|
101
|
+
# and accept \Rails' defaults, life will be much easier.
|
102
102
|
#
|
103
103
|
# If you need to use a MIME type which isn't supported by default, you can register your own handlers in
|
104
104
|
# +config/initializers/mime_types.rb+ as follows.
|
@@ -6,6 +6,8 @@ require "active_support/core_ext/module/anonymous"
|
|
6
6
|
require "action_dispatch/http/mime_type"
|
7
7
|
|
8
8
|
module ActionController
|
9
|
+
# = Action Controller Params Wrapper
|
10
|
+
#
|
9
11
|
# Wraps the parameters hash into a nested hash. This will allow clients to
|
10
12
|
# submit requests without having to specify any root elements.
|
11
13
|
#
|
@@ -68,9 +70,9 @@ module ActionController
|
|
68
70
|
# class Admin::UsersController < ApplicationController
|
69
71
|
# end
|
70
72
|
#
|
71
|
-
# will try to check if
|
73
|
+
# will try to check if +Admin::User+ or +User+ model exists, and use it to
|
72
74
|
# determine the wrapper key respectively. If both models don't exist,
|
73
|
-
# it will then
|
75
|
+
# it will then fall back to use +user+ as the key.
|
74
76
|
#
|
75
77
|
# To disable this functionality for a controller:
|
76
78
|
#
|
@@ -9,6 +9,8 @@ module ActionController
|
|
9
9
|
|
10
10
|
class UnsafeRedirectError < StandardError; end
|
11
11
|
|
12
|
+
ILLEGAL_HEADER_VALUE_REGEX = /[\x00-\x08\x0A-\x1F]/.freeze
|
13
|
+
|
12
14
|
included do
|
13
15
|
mattr_accessor :raise_on_open_redirects, default: false
|
14
16
|
end
|
@@ -21,7 +23,7 @@ module ActionController
|
|
21
23
|
# * <tt>String</tt> not containing a protocol - The current protocol and host is prepended to the string.
|
22
24
|
# * <tt>Proc</tt> - A block that will be executed in the controller's context. Should return any option accepted by +redirect_to+.
|
23
25
|
#
|
24
|
-
# === Examples
|
26
|
+
# === Examples
|
25
27
|
#
|
26
28
|
# redirect_to action: "show", id: 5
|
27
29
|
# redirect_to @post
|
@@ -65,8 +67,8 @@ module ActionController
|
|
65
67
|
#
|
66
68
|
# === Open Redirect protection
|
67
69
|
#
|
68
|
-
# By default, Rails protects against redirecting to external hosts for your app's safety, so called open redirects.
|
69
|
-
# 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>
|
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>
|
70
72
|
#
|
71
73
|
# Here #redirect_to automatically validates the potentially-unsafe URL:
|
72
74
|
#
|
@@ -85,9 +87,13 @@ module ActionController
|
|
85
87
|
|
86
88
|
allow_other_host = response_options.delete(:allow_other_host) { _allow_other_host }
|
87
89
|
|
88
|
-
self.status
|
89
|
-
|
90
|
-
|
90
|
+
self.status = _extract_redirect_to_status(options, response_options)
|
91
|
+
|
92
|
+
redirect_to_location = _compute_redirect_to_location(request, options)
|
93
|
+
_ensure_url_is_http_header_safe(redirect_to_location)
|
94
|
+
|
95
|
+
self.location = _enforce_open_redirect_protection(redirect_to_location, allow_other_host: allow_other_host)
|
96
|
+
self.response_body = ""
|
91
97
|
end
|
92
98
|
|
93
99
|
# Soft deprecated alias for #redirect_back_or_to where the +fallback_location+ location is supplied as a keyword argument instead
|
@@ -148,7 +154,7 @@ module ActionController
|
|
148
154
|
public :_compute_redirect_to_location
|
149
155
|
|
150
156
|
# Verifies the passed +location+ is an internal URL that's safe to redirect to and returns it, or nil if not.
|
151
|
-
# Useful to wrap a params provided redirect URL and
|
157
|
+
# Useful to wrap a params provided redirect URL and fall back to an alternate URL to redirect to:
|
152
158
|
#
|
153
159
|
# redirect_to url_from(params[:redirect_url]) || root_url
|
154
160
|
#
|
@@ -204,5 +210,16 @@ module ActionController
|
|
204
210
|
rescue ArgumentError, URI::Error
|
205
211
|
false
|
206
212
|
end
|
213
|
+
|
214
|
+
def _ensure_url_is_http_header_safe(url)
|
215
|
+
# Attempt to comply with the set of valid token characters
|
216
|
+
# defined for an HTTP header value in
|
217
|
+
# https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6
|
218
|
+
if url.match?(ILLEGAL_HEADER_VALUE_REGEX)
|
219
|
+
msg = "The redirect URL #{url} contains one or more illegal HTTP header field character. " \
|
220
|
+
"Set of legal characters defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6"
|
221
|
+
raise UnsafeRedirectError, msg
|
222
|
+
end
|
223
|
+
end
|
207
224
|
end
|
208
225
|
end
|
@@ -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
|
@@ -58,7 +58,7 @@ module ActionController
|
|
58
58
|
# disposition: "attachment; filename=#{filename}.csv"
|
59
59
|
# end
|
60
60
|
#
|
61
|
-
# Note that we used Mime[:csv] for the csv mime type as it comes with Rails.
|
61
|
+
# Note that we used Mime[:csv] for the csv mime type as it comes with \Rails.
|
62
62
|
# For a custom renderer, you'll need to register a mime type with
|
63
63
|
# <tt>Mime::Type.register</tt>.
|
64
64
|
#
|
@@ -100,7 +100,7 @@ module ActionController
|
|
100
100
|
#
|
101
101
|
# Both ActionController::Base and ActionController::API
|
102
102
|
# include ActionController::Renderers::All, making all renderers
|
103
|
-
# available in the controller. See
|
103
|
+
# available in the controller. See Renderers::RENDERERS and Renderers.add.
|
104
104
|
#
|
105
105
|
# Since ActionController::Metal controllers cannot render, the controller
|
106
106
|
# must include AbstractController::Rendering, ActionController::Rendering,
|
@@ -195,13 +195,6 @@ module ActionController
|
|
195
195
|
end
|
196
196
|
end
|
197
197
|
|
198
|
-
# Normalize arguments by catching blocks and setting them on :update.
|
199
|
-
def _normalize_args(action = nil, options = {}, &blk)
|
200
|
-
options = super
|
201
|
-
options[:update] = blk if block_given?
|
202
|
-
options
|
203
|
-
end
|
204
|
-
|
205
198
|
# Normalize both text and status options.
|
206
199
|
def _normalize_options(options)
|
207
200
|
_normalize_text(options)
|