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
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
require "active_support/core_ext/array/extract_options"
|
4
4
|
require "action_dispatch/middleware/stack"
|
5
|
-
require "action_dispatch/http/request"
|
6
|
-
require "action_dispatch/http/response"
|
7
5
|
|
8
6
|
module ActionController
|
9
7
|
# Extend ActionDispatch middleware stack to make it aware of options
|
@@ -13,8 +11,8 @@ module ActionController
|
|
13
11
|
# use AuthenticationMiddleware, except: [:index, :show]
|
14
12
|
# end
|
15
13
|
#
|
16
|
-
class MiddlewareStack < ActionDispatch::MiddlewareStack
|
17
|
-
class Middleware < ActionDispatch::MiddlewareStack::Middleware
|
14
|
+
class MiddlewareStack < ActionDispatch::MiddlewareStack # :nodoc:
|
15
|
+
class Middleware < ActionDispatch::MiddlewareStack::Middleware # :nodoc:
|
18
16
|
def initialize(klass, args, actions, strategy, block)
|
19
17
|
@actions = actions
|
20
18
|
@strategy = strategy
|
@@ -62,7 +60,7 @@ module ActionController
|
|
62
60
|
|
63
61
|
# <tt>ActionController::Metal</tt> is the simplest possible controller, providing a
|
64
62
|
# valid Rack interface without the additional niceties provided by
|
65
|
-
#
|
63
|
+
# ActionController::Base.
|
66
64
|
#
|
67
65
|
# A sample metal controller might look like this:
|
68
66
|
#
|
@@ -113,7 +111,7 @@ module ActionController
|
|
113
111
|
#
|
114
112
|
# == Other Helpers
|
115
113
|
#
|
116
|
-
# You can refer to the modules included in
|
114
|
+
# You can refer to the modules included in ActionController::Base to see
|
117
115
|
# other features you can bring into your metal controller.
|
118
116
|
#
|
119
117
|
class Metal < AbstractController::Base
|
@@ -139,7 +137,7 @@ module ActionController
|
|
139
137
|
false
|
140
138
|
end
|
141
139
|
|
142
|
-
# Delegates to the class'
|
140
|
+
# Delegates to the class's ::controller_name.
|
143
141
|
def controller_name
|
144
142
|
self.class.controller_name
|
145
143
|
end
|
@@ -184,7 +182,7 @@ module ActionController
|
|
184
182
|
response_body || response.committed?
|
185
183
|
end
|
186
184
|
|
187
|
-
def dispatch(name, request, response)
|
185
|
+
def dispatch(name, request, response) # :nodoc:
|
188
186
|
set_request!(request)
|
189
187
|
set_response!(response)
|
190
188
|
process(name)
|
@@ -196,12 +194,12 @@ module ActionController
|
|
196
194
|
@_response = response
|
197
195
|
end
|
198
196
|
|
199
|
-
def set_request!(request)
|
197
|
+
def set_request!(request) # :nodoc:
|
200
198
|
@_request = request
|
201
199
|
@_request.controller_instance = self
|
202
200
|
end
|
203
201
|
|
204
|
-
def to_a
|
202
|
+
def to_a # :nodoc:
|
205
203
|
response.to_a
|
206
204
|
end
|
207
205
|
|
@@ -219,10 +217,9 @@ module ActionController
|
|
219
217
|
class << self
|
220
218
|
# Pushes the given Rack middleware and its arguments to the bottom of the
|
221
219
|
# middleware stack.
|
222
|
-
def use(
|
223
|
-
middleware_stack.use(
|
220
|
+
def use(...)
|
221
|
+
middleware_stack.use(...)
|
224
222
|
end
|
225
|
-
ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true)
|
226
223
|
end
|
227
224
|
|
228
225
|
# Alias for +middleware_stack+.
|
@@ -8,8 +8,11 @@ require "action_controller/railties/helpers"
|
|
8
8
|
require "action_view/railtie"
|
9
9
|
|
10
10
|
module ActionController
|
11
|
-
class Railtie < Rails::Railtie
|
11
|
+
class Railtie < Rails::Railtie # :nodoc:
|
12
12
|
config.action_controller = ActiveSupport::OrderedOptions.new
|
13
|
+
config.action_controller.raise_on_open_redirects = false
|
14
|
+
config.action_controller.log_query_tags_around_actions = true
|
15
|
+
config.action_controller.wrap_parameters_by_default = false
|
13
16
|
|
14
17
|
config.eager_load_namespaces << ActionController
|
15
18
|
|
@@ -25,14 +28,19 @@ module ActionController
|
|
25
28
|
options = app.config.action_controller
|
26
29
|
|
27
30
|
ActiveSupport.on_load(:action_controller, run_once: true) do
|
28
|
-
ActionController::Parameters.permit_all_parameters = options.
|
31
|
+
ActionController::Parameters.permit_all_parameters = options.permit_all_parameters || false
|
29
32
|
if app.config.action_controller[:always_permitted_parameters]
|
30
33
|
ActionController::Parameters.always_permitted_parameters =
|
31
|
-
app.config.action_controller.
|
34
|
+
app.config.action_controller.always_permitted_parameters
|
32
35
|
end
|
33
|
-
|
34
|
-
|
36
|
+
|
37
|
+
action_on_unpermitted_parameters = options.action_on_unpermitted_parameters
|
38
|
+
|
39
|
+
if action_on_unpermitted_parameters.nil?
|
40
|
+
action_on_unpermitted_parameters = (Rails.env.test? || Rails.env.development?) ? :log : false
|
35
41
|
end
|
42
|
+
|
43
|
+
ActionController::Parameters.action_on_unpermitted_parameters = action_on_unpermitted_parameters
|
36
44
|
end
|
37
45
|
end
|
38
46
|
|
@@ -55,7 +63,18 @@ module ActionController
|
|
55
63
|
extend ::AbstractController::Railties::RoutesHelpers.with(app.routes)
|
56
64
|
extend ::ActionController::Railties::Helpers
|
57
65
|
|
58
|
-
options.
|
66
|
+
wrap_parameters format: [:json] if options.wrap_parameters_by_default && respond_to?(:wrap_parameters)
|
67
|
+
|
68
|
+
# Configs used in other initializers
|
69
|
+
filtered_options = options.except(
|
70
|
+
:log_query_tags_around_actions,
|
71
|
+
:permit_all_parameters,
|
72
|
+
:action_on_unpermitted_parameters,
|
73
|
+
:always_permitted_parameters,
|
74
|
+
:wrap_parameters_by_default
|
75
|
+
)
|
76
|
+
|
77
|
+
filtered_options.each do |k, v|
|
59
78
|
k = "#{k}="
|
60
79
|
if respond_to?(k)
|
61
80
|
send(k, v)
|
@@ -85,5 +104,30 @@ module ActionController
|
|
85
104
|
ActionController::Metal.descendants.each(&:action_methods) if config.eager_load
|
86
105
|
end
|
87
106
|
end
|
107
|
+
|
108
|
+
initializer "action_controller.query_log_tags" do |app|
|
109
|
+
query_logs_tags_enabled = app.config.respond_to?(:active_record) &&
|
110
|
+
app.config.active_record.query_log_tags_enabled &&
|
111
|
+
app.config.action_controller.log_query_tags_around_actions
|
112
|
+
|
113
|
+
if query_logs_tags_enabled
|
114
|
+
app.config.active_record.query_log_tags |= [:controller] unless app.config.active_record.query_log_tags.include?(:namespaced_controller)
|
115
|
+
app.config.active_record.query_log_tags |= [:action]
|
116
|
+
|
117
|
+
ActiveSupport.on_load(:active_record) do
|
118
|
+
ActiveRecord::QueryLogs.taggings.merge!(
|
119
|
+
controller: ->(context) { context[:controller]&.controller_name },
|
120
|
+
action: ->(context) { context[:controller]&.action_name },
|
121
|
+
namespaced_controller: ->(context) { context[:controller].class.name if context[:controller] }
|
122
|
+
)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
initializer "action_controller.test_case" do |app|
|
128
|
+
ActiveSupport.on_load(:action_controller_test_case) do
|
129
|
+
ActionController::TestCase.executor_around_each_request = app.config.active_support.executor_around_test_case
|
130
|
+
end
|
131
|
+
end
|
88
132
|
end
|
89
133
|
end
|
@@ -68,26 +68,7 @@ module ActionController
|
|
68
68
|
@env = normalize_keys defaults, env
|
69
69
|
end
|
70
70
|
|
71
|
-
#
|
72
|
-
#
|
73
|
-
# The primary options are:
|
74
|
-
# * <tt>:partial</tt> - See <tt>ActionView::PartialRenderer</tt> for details.
|
75
|
-
# * <tt>:file</tt> - Renders an explicit template file. Add <tt>:locals</tt> to pass in, if so desired.
|
76
|
-
# It shouldn’t be used directly with unsanitized user input due to lack of validation.
|
77
|
-
# * <tt>:inline</tt> - Renders an ERB template string.
|
78
|
-
# * <tt>:plain</tt> - Renders provided text and sets the content type as <tt>text/plain</tt>.
|
79
|
-
# * <tt>:html</tt> - Renders the provided HTML safe string, otherwise
|
80
|
-
# performs HTML escape on the string first. Sets the content type as <tt>text/html</tt>.
|
81
|
-
# * <tt>:json</tt> - Renders the provided hash or object in JSON. You don't
|
82
|
-
# need to call <tt>.to_json</tt> on the object you want to render.
|
83
|
-
# * <tt>:body</tt> - Renders provided text and sets content type of <tt>text/plain</tt>.
|
84
|
-
#
|
85
|
-
# If no <tt>options</tt> hash is passed or if <tt>:update</tt> is specified, then:
|
86
|
-
#
|
87
|
-
# If an object responding to +render_in+ is passed, +render_in+ is called on the object,
|
88
|
-
# passing in the current view context.
|
89
|
-
#
|
90
|
-
# Otherwise, a partial is rendered using the second parameter as the locals hash.
|
71
|
+
# Renders a template to a string, just like ActionController::Rendering#render_to_string.
|
91
72
|
def render(*args)
|
92
73
|
raise "missing controller" unless controller
|
93
74
|
|
@@ -31,7 +31,7 @@ module ActionController
|
|
31
31
|
|
32
32
|
# ActionController::TestCase will be deprecated and moved to a gem in the future.
|
33
33
|
# Please use ActionDispatch::IntegrationTest going forward.
|
34
|
-
class TestRequest < ActionDispatch::TestRequest
|
34
|
+
class TestRequest < ActionDispatch::TestRequest # :nodoc:
|
35
35
|
DEFAULT_ENV = ActionDispatch::TestRequest::DEFAULT_ENV.dup
|
36
36
|
DEFAULT_ENV.delete "PATH_INFO"
|
37
37
|
|
@@ -179,7 +179,7 @@ module ActionController
|
|
179
179
|
|
180
180
|
# Methods #destroy and #load! are overridden to avoid calling methods on the
|
181
181
|
# @store object, which does not exist for the TestSession class.
|
182
|
-
class TestSession < Rack::Session::Abstract::PersistedSecure::SecureSessionHash
|
182
|
+
class TestSession < Rack::Session::Abstract::PersistedSecure::SecureSessionHash # :nodoc:
|
183
183
|
DEFAULT_OPTIONS = Rack::Session::Abstract::Persisted::DEFAULT_OPTIONS
|
184
184
|
|
185
185
|
def initialize(session = {})
|
@@ -214,6 +214,10 @@ module ActionController
|
|
214
214
|
@data.fetch(key.to_s, *args, &block)
|
215
215
|
end
|
216
216
|
|
217
|
+
def enabled?
|
218
|
+
true
|
219
|
+
end
|
220
|
+
|
217
221
|
private
|
218
222
|
def load!
|
219
223
|
@id
|
@@ -237,7 +241,7 @@ module ActionController
|
|
237
241
|
# == Basic example
|
238
242
|
#
|
239
243
|
# Functional tests are written as follows:
|
240
|
-
# 1. First, one uses the +get+, +post+, +patch+, +put+, +delete
|
244
|
+
# 1. First, one uses the +get+, +post+, +patch+, +put+, +delete+, or +head+ method to simulate
|
241
245
|
# an HTTP request.
|
242
246
|
# 2. Then, one asserts whether the current state is as expected. "State" can be anything:
|
243
247
|
# the controller's HTTP response, the database contents, etc.
|
@@ -329,6 +333,8 @@ module ActionController
|
|
329
333
|
#
|
330
334
|
# assert_redirected_to page_url(title: 'foo')
|
331
335
|
class TestCase < ActiveSupport::TestCase
|
336
|
+
singleton_class.attr_accessor :executor_around_each_request
|
337
|
+
|
332
338
|
module Behavior
|
333
339
|
extend ActiveSupport::Concern
|
334
340
|
include ActionDispatch::TestProcess
|
@@ -385,7 +391,7 @@ module ActionController
|
|
385
391
|
#
|
386
392
|
# You can also simulate POST, PATCH, PUT, DELETE, and HEAD requests with
|
387
393
|
# +post+, +patch+, +put+, +delete+, and +head+.
|
388
|
-
# Example sending parameters, session and setting a flash message:
|
394
|
+
# Example sending parameters, session, and setting a flash message:
|
389
395
|
#
|
390
396
|
# get :show,
|
391
397
|
# params: { id: 7 },
|
@@ -455,13 +461,19 @@ module ActionController
|
|
455
461
|
# session: { user_id: 1 },
|
456
462
|
# flash: { notice: 'This is flash message' }
|
457
463
|
#
|
458
|
-
# To simulate +GET+, +POST+, +PATCH+, +PUT+, +DELETE
|
464
|
+
# To simulate +GET+, +POST+, +PATCH+, +PUT+, +DELETE+, and +HEAD+ requests
|
459
465
|
# prefer using #get, #post, #patch, #put, #delete and #head methods
|
460
466
|
# respectively which will make tests more expressive.
|
461
467
|
#
|
468
|
+
# It's not recommended to make more than one request in the same test. Instance
|
469
|
+
# variables that are set in one request will not persist to the next request,
|
470
|
+
# but it's not guaranteed that all Rails internal state will be reset. Prefer
|
471
|
+
# ActionDispatch::IntegrationTest for making multiple requests in the same test.
|
472
|
+
#
|
462
473
|
# Note that the request method is not verified.
|
463
474
|
def process(action, method: "GET", params: nil, session: nil, body: nil, flash: {}, format: nil, xhr: false, as: nil)
|
464
475
|
check_required_ivars
|
476
|
+
@controller.clear_instance_variables_between_requests
|
465
477
|
|
466
478
|
action = +action.to_s
|
467
479
|
http_method = method.to_s.upcase
|
@@ -574,10 +586,19 @@ module ActionController
|
|
574
586
|
end
|
575
587
|
end
|
576
588
|
|
589
|
+
def wrap_execution(&block)
|
590
|
+
if ActionController::TestCase.executor_around_each_request && defined?(Rails.application) && Rails.application
|
591
|
+
Rails.application.executor.wrap(&block)
|
592
|
+
else
|
593
|
+
yield
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
577
597
|
def process_controller_response(action, cookies, xhr)
|
578
598
|
begin
|
579
599
|
@controller.recycle!
|
580
|
-
|
600
|
+
|
601
|
+
wrap_execution { @controller.dispatch(action, @request, @response) }
|
581
602
|
ensure
|
582
603
|
@request = @controller.request
|
583
604
|
@response = @controller.response
|
@@ -623,7 +644,7 @@ module ActionController
|
|
623
644
|
end
|
624
645
|
|
625
646
|
def check_required_ivars
|
626
|
-
#
|
647
|
+
# Check for required instance variables so we can give an
|
627
648
|
# understandable error message.
|
628
649
|
[:@routes, :@controller, :@request, :@response].each do |iv_name|
|
629
650
|
if !instance_variable_defined?(iv_name) || instance_variable_get(iv_name).nil?
|
data/lib/action_controller.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "abstract_controller"
|
4
4
|
require "action_dispatch"
|
5
5
|
require "action_controller/metal/strong_parameters"
|
6
|
+
require "action_controller/metal/exceptions"
|
6
7
|
|
7
8
|
module ActionController
|
8
9
|
extend ActiveSupport::Autoload
|
@@ -18,10 +19,6 @@ module ActionController
|
|
18
19
|
end
|
19
20
|
|
20
21
|
autoload_under "metal" do
|
21
|
-
eager_autoload do
|
22
|
-
autoload :Live
|
23
|
-
end
|
24
|
-
|
25
22
|
autoload :ConditionalGet
|
26
23
|
autoload :ContentSecurityPolicy
|
27
24
|
autoload :Cookies
|
@@ -37,6 +34,7 @@ module ActionController
|
|
37
34
|
autoload :BasicImplicitRender
|
38
35
|
autoload :ImplicitRender
|
39
36
|
autoload :Instrumentation
|
37
|
+
autoload :Live
|
40
38
|
autoload :Logging
|
41
39
|
autoload :MimeResponds
|
42
40
|
autoload :ParamsWrapper
|
@@ -65,5 +63,4 @@ require "active_support/core_ext/module/attribute_accessors"
|
|
65
63
|
require "active_support/core_ext/load_error"
|
66
64
|
require "active_support/core_ext/module/attr_internal"
|
67
65
|
require "active_support/core_ext/name_error"
|
68
|
-
require "active_support/core_ext/uri"
|
69
66
|
require "active_support/inflector"
|
@@ -32,8 +32,8 @@ module ActionDispatch
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
# Check response freshness (Last-Modified and ETag) against request
|
36
|
-
# If-Modified-Since and If-None-Match conditions. If both headers are
|
35
|
+
# Check response freshness (+Last-Modified+ and ETag) against request
|
36
|
+
# +If-Modified-Since+ and +If-None-Match+ conditions. If both headers are
|
37
37
|
# supplied, both must match, or the request is not considered fresh.
|
38
38
|
def fresh?(response)
|
39
39
|
last_modified = if_modified_since
|
@@ -81,8 +81,8 @@ module ActionDispatch
|
|
81
81
|
|
82
82
|
# This method sets a weak ETag validator on the response so browsers
|
83
83
|
# and proxies may cache the response, keyed on the ETag. On subsequent
|
84
|
-
# requests, the If-None-Match header is set to the cached ETag. If it
|
85
|
-
# matches the current ETag, we can return a 304 Not Modified response
|
84
|
+
# requests, the +If-None-Match+ header is set to the cached ETag. If it
|
85
|
+
# matches the current ETag, we can return a <tt>304 Not Modified</tt> response
|
86
86
|
# with no body, letting the browser or proxy know that their cache is
|
87
87
|
# current. Big savings in request time and network bandwidth.
|
88
88
|
#
|
@@ -92,7 +92,7 @@ module ActionDispatch
|
|
92
92
|
# is viewing.
|
93
93
|
#
|
94
94
|
# Strong ETags are considered byte-for-byte identical. They allow a
|
95
|
-
# browser or proxy cache to support Range requests, useful for paging
|
95
|
+
# browser or proxy cache to support +Range+ requests, useful for paging
|
96
96
|
# through a PDF file or scrubbing through a video. Some CDNs only
|
97
97
|
# support strong ETags and will ignore weak ETags entirely.
|
98
98
|
#
|
@@ -112,12 +112,12 @@ module ActionDispatch
|
|
112
112
|
|
113
113
|
def etag?; etag; end
|
114
114
|
|
115
|
-
# True if an ETag is set and it's a weak validator (preceded with W
|
115
|
+
# True if an ETag is set, and it's a weak validator (preceded with <tt>W/</tt>).
|
116
116
|
def weak_etag?
|
117
117
|
etag? && etag.start_with?('W/"')
|
118
118
|
end
|
119
119
|
|
120
|
-
# True if an ETag is set and it isn't a weak validator (not preceded with W
|
120
|
+
# True if an ETag is set, and it isn't a weak validator (not preceded with <tt>W/</tt>).
|
121
121
|
def strong_etag?
|
122
122
|
etag? && !weak_etag?
|
123
123
|
end
|
@@ -187,13 +187,20 @@ module ActionDispatch
|
|
187
187
|
|
188
188
|
return if control.empty? && cache_control.empty? # Let middleware handle default behavior
|
189
189
|
|
190
|
-
if
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
190
|
+
if cache_control.any?
|
191
|
+
# Any caching directive coming from a controller overrides
|
192
|
+
# no-cache/no-store in the default Cache-Control header.
|
193
|
+
control.delete(:no_cache)
|
194
|
+
control.delete(:no_store)
|
195
195
|
|
196
|
-
|
196
|
+
if extras = control.delete(:extras)
|
197
|
+
cache_control[:extras] ||= []
|
198
|
+
cache_control[:extras] += extras
|
199
|
+
cache_control[:extras].uniq!
|
200
|
+
end
|
201
|
+
|
202
|
+
control.merge! cache_control
|
203
|
+
end
|
197
204
|
|
198
205
|
options = []
|
199
206
|
|
@@ -3,7 +3,24 @@
|
|
3
3
|
require "active_support/core_ext/object/deep_dup"
|
4
4
|
require "active_support/core_ext/array/wrap"
|
5
5
|
|
6
|
-
module ActionDispatch
|
6
|
+
module ActionDispatch # :nodoc:
|
7
|
+
# Configures the HTTP
|
8
|
+
# {Content-Security-Policy}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy]
|
9
|
+
# response header to help protect against XSS and injection attacks.
|
10
|
+
#
|
11
|
+
# Example global policy:
|
12
|
+
#
|
13
|
+
# Rails.application.config.content_security_policy do |policy|
|
14
|
+
# policy.default_src :self, :https
|
15
|
+
# policy.font_src :self, :https, :data
|
16
|
+
# policy.img_src :self, :https, :data
|
17
|
+
# policy.object_src :none
|
18
|
+
# policy.script_src :self, :https
|
19
|
+
# policy.style_src :self, :https
|
20
|
+
#
|
21
|
+
# # Specify URI for violation reports
|
22
|
+
# policy.report_uri "/csp-violation-report-endpoint"
|
23
|
+
# end
|
7
24
|
class ContentSecurityPolicy
|
8
25
|
class Middleware
|
9
26
|
CONTENT_TYPE = "Content-Type"
|
@@ -16,7 +33,11 @@ module ActionDispatch #:nodoc:
|
|
16
33
|
|
17
34
|
def call(env)
|
18
35
|
request = ActionDispatch::Request.new env
|
19
|
-
|
36
|
+
status, headers, _ = response = @app.call(env)
|
37
|
+
|
38
|
+
# Returning CSP headers with a 304 Not Modified is harmful, since nonces in the new
|
39
|
+
# CSP headers might not match nonces in the cached HTML.
|
40
|
+
return response if status == 304
|
20
41
|
|
21
42
|
return response if policy_present?(headers)
|
22
43
|
|
@@ -100,43 +121,47 @@ module ActionDispatch #:nodoc:
|
|
100
121
|
end
|
101
122
|
|
102
123
|
MAPPINGS = {
|
103
|
-
self:
|
104
|
-
unsafe_eval:
|
105
|
-
unsafe_inline:
|
106
|
-
none:
|
107
|
-
http:
|
108
|
-
https:
|
109
|
-
data:
|
110
|
-
mediastream:
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
124
|
+
self: "'self'",
|
125
|
+
unsafe_eval: "'unsafe-eval'",
|
126
|
+
unsafe_inline: "'unsafe-inline'",
|
127
|
+
none: "'none'",
|
128
|
+
http: "http:",
|
129
|
+
https: "https:",
|
130
|
+
data: "data:",
|
131
|
+
mediastream: "mediastream:",
|
132
|
+
allow_duplicates: "'allow-duplicates'",
|
133
|
+
blob: "blob:",
|
134
|
+
filesystem: "filesystem:",
|
135
|
+
report_sample: "'report-sample'",
|
136
|
+
script: "'script'",
|
137
|
+
strict_dynamic: "'strict-dynamic'",
|
138
|
+
ws: "ws:",
|
139
|
+
wss: "wss:"
|
117
140
|
}.freeze
|
118
141
|
|
119
142
|
DIRECTIVES = {
|
120
|
-
base_uri:
|
121
|
-
child_src:
|
122
|
-
connect_src:
|
123
|
-
default_src:
|
124
|
-
font_src:
|
125
|
-
form_action:
|
126
|
-
frame_ancestors:
|
127
|
-
frame_src:
|
128
|
-
img_src:
|
129
|
-
manifest_src:
|
130
|
-
media_src:
|
131
|
-
object_src:
|
132
|
-
prefetch_src:
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
143
|
+
base_uri: "base-uri",
|
144
|
+
child_src: "child-src",
|
145
|
+
connect_src: "connect-src",
|
146
|
+
default_src: "default-src",
|
147
|
+
font_src: "font-src",
|
148
|
+
form_action: "form-action",
|
149
|
+
frame_ancestors: "frame-ancestors",
|
150
|
+
frame_src: "frame-src",
|
151
|
+
img_src: "img-src",
|
152
|
+
manifest_src: "manifest-src",
|
153
|
+
media_src: "media-src",
|
154
|
+
object_src: "object-src",
|
155
|
+
prefetch_src: "prefetch-src",
|
156
|
+
require_trusted_types_for: "require-trusted-types-for",
|
157
|
+
script_src: "script-src",
|
158
|
+
script_src_attr: "script-src-attr",
|
159
|
+
script_src_elem: "script-src-elem",
|
160
|
+
style_src: "style-src",
|
161
|
+
style_src_attr: "style-src-attr",
|
162
|
+
style_src_elem: "style-src-elem",
|
163
|
+
trusted_types: "trusted-types",
|
164
|
+
worker_src: "worker-src"
|
140
165
|
}.freeze
|
141
166
|
|
142
167
|
DEFAULT_NONCE_DIRECTIVES = %w[script-src style-src].freeze
|
@@ -164,6 +189,15 @@ module ActionDispatch #:nodoc:
|
|
164
189
|
end
|
165
190
|
end
|
166
191
|
|
192
|
+
# Specify whether to prevent the user agent from loading any assets over
|
193
|
+
# HTTP when the page uses HTTPS:
|
194
|
+
#
|
195
|
+
# policy.block_all_mixed_content
|
196
|
+
#
|
197
|
+
# Pass +false+ to allow it again:
|
198
|
+
#
|
199
|
+
# policy.block_all_mixed_content false
|
200
|
+
#
|
167
201
|
def block_all_mixed_content(enabled = true)
|
168
202
|
if enabled
|
169
203
|
@directives["block-all-mixed-content"] = true
|
@@ -172,6 +206,14 @@ module ActionDispatch #:nodoc:
|
|
172
206
|
end
|
173
207
|
end
|
174
208
|
|
209
|
+
# Restricts the set of plugins that can be embedded:
|
210
|
+
#
|
211
|
+
# policy.plugin_types "application/x-shockwave-flash"
|
212
|
+
#
|
213
|
+
# Leave empty to allow all plugins:
|
214
|
+
#
|
215
|
+
# policy.plugin_types
|
216
|
+
#
|
175
217
|
def plugin_types(*types)
|
176
218
|
if types.first
|
177
219
|
@directives["plugin-types"] = types
|
@@ -180,10 +222,24 @@ module ActionDispatch #:nodoc:
|
|
180
222
|
end
|
181
223
|
end
|
182
224
|
|
225
|
+
# Enable the {report-uri}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-uri]
|
226
|
+
# directive. Violation reports will be sent to the specified URI:
|
227
|
+
#
|
228
|
+
# policy.report_uri "/csp-violation-report-endpoint"
|
229
|
+
#
|
183
230
|
def report_uri(uri)
|
184
231
|
@directives["report-uri"] = [uri]
|
185
232
|
end
|
186
233
|
|
234
|
+
# Specify asset types for which {Subresource Integrity}[https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity]
|
235
|
+
# is required:
|
236
|
+
#
|
237
|
+
# policy.require_sri_for :script, :style
|
238
|
+
#
|
239
|
+
# Leave empty to not require Subresource Integrity:
|
240
|
+
#
|
241
|
+
# policy.require_sri_for
|
242
|
+
#
|
187
243
|
def require_sri_for(*types)
|
188
244
|
if types.first
|
189
245
|
@directives["require-sri-for"] = types
|
@@ -192,6 +248,19 @@ module ActionDispatch #:nodoc:
|
|
192
248
|
end
|
193
249
|
end
|
194
250
|
|
251
|
+
# Specify whether a {sandbox}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox]
|
252
|
+
# should be enabled for the requested resource:
|
253
|
+
#
|
254
|
+
# policy.sandbox
|
255
|
+
#
|
256
|
+
# Values can be passed as arguments:
|
257
|
+
#
|
258
|
+
# policy.sandbox "allow-scripts", "allow-modals"
|
259
|
+
#
|
260
|
+
# Pass +false+ to disable the sandbox:
|
261
|
+
#
|
262
|
+
# policy.sandbox false
|
263
|
+
#
|
195
264
|
def sandbox(*values)
|
196
265
|
if values.empty?
|
197
266
|
@directives["sandbox"] = true
|
@@ -202,6 +271,14 @@ module ActionDispatch #:nodoc:
|
|
202
271
|
end
|
203
272
|
end
|
204
273
|
|
274
|
+
# Specify whether user agents should treat any assets over HTTP as HTTPS:
|
275
|
+
#
|
276
|
+
# policy.upgrade_insecure_requests
|
277
|
+
#
|
278
|
+
# Pass +false+ to disable it:
|
279
|
+
#
|
280
|
+
# policy.upgrade_insecure_requests false
|
281
|
+
#
|
205
282
|
def upgrade_insecure_requests(enabled = true)
|
206
283
|
if enabled
|
207
284
|
@directives["upgrade-insecure-requests"] = true
|
@@ -4,28 +4,13 @@ require "active_support/parameter_filter"
|
|
4
4
|
|
5
5
|
module ActionDispatch
|
6
6
|
module Http
|
7
|
-
# Allows you to specify sensitive
|
8
|
-
# the request log
|
9
|
-
# sub-hashes of the params hash to filter. Filtering only certain sub-keys
|
10
|
-
# from a hash is possible by using the dot notation: 'credit_card.number'.
|
11
|
-
# If a block is given, each key and value of the params hash and all
|
12
|
-
# sub-hashes are passed to it, where the value or the key can be replaced using
|
13
|
-
# String#replace or similar methods.
|
14
|
-
#
|
15
|
-
# env["action_dispatch.parameter_filter"] = [:password]
|
16
|
-
# => replaces the value to all keys matching /password/i with "[FILTERED]"
|
7
|
+
# Allows you to specify sensitive query string and POST parameters to filter
|
8
|
+
# from the request log.
|
17
9
|
#
|
10
|
+
# # Replaces values with "[FILTERED]" for keys that match /foo|bar/i.
|
18
11
|
# env["action_dispatch.parameter_filter"] = [:foo, "bar"]
|
19
|
-
# => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
|
20
|
-
#
|
21
|
-
# env["action_dispatch.parameter_filter"] = [ "credit_card.code" ]
|
22
|
-
# => replaces { credit_card: {code: "xxxx"} } with "[FILTERED]", does not
|
23
|
-
# change { file: { code: "xxxx"} }
|
24
12
|
#
|
25
|
-
#
|
26
|
-
# v.reverse! if k.match?(/secret/i)
|
27
|
-
# end
|
28
|
-
# => reverses the value to all keys matching /secret/i
|
13
|
+
# For more information about filter behavior, see ActiveSupport::ParameterFilter.
|
29
14
|
module FilterParameters
|
30
15
|
ENV_MATCH = [/RAW_POST_DATA/, "rack.request.form_vars"] # :nodoc:
|
31
16
|
NULL_PARAM_FILTER = ActiveSupport::ParameterFilter.new # :nodoc:
|
@@ -65,7 +65,7 @@ module ActionDispatch
|
|
65
65
|
@req.set_header env_name(key), value
|
66
66
|
end
|
67
67
|
|
68
|
-
# Add a value to a multivalued header like Vary or Accept-Encoding
|
68
|
+
# Add a value to a multivalued header like +Vary+ or +Accept-Encoding+.
|
69
69
|
def add(key, value)
|
70
70
|
@req.add_header env_name(key), value
|
71
71
|
end
|