actionpack 7.0.2.3 → 7.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +86 -0
- data/lib/abstract_controller/base.rb +6 -5
- data/lib/abstract_controller/callbacks.rb +1 -1
- data/lib/abstract_controller/helpers.rb +1 -1
- data/lib/action_controller/api.rb +5 -5
- data/lib/action_controller/base.rb +5 -4
- data/lib/action_controller/form_builder.rb +2 -2
- data/lib/action_controller/metal/conditional_get.rb +1 -1
- data/lib/action_controller/metal/content_security_policy.rb +35 -1
- data/lib/action_controller/metal/helpers.rb +1 -1
- data/lib/action_controller/metal/http_authentication.rb +56 -29
- data/lib/action_controller/metal/live.rb +1 -0
- data/lib/action_controller/metal/permissions_policy.rb +18 -27
- data/lib/action_controller/metal/redirecting.rb +4 -3
- data/lib/action_controller/metal/renderers.rb +10 -11
- data/lib/action_controller/metal/rendering.rb +3 -3
- data/lib/action_controller/metal/request_forgery_protection.rb +4 -4
- data/lib/action_controller/metal/streaming.rb +5 -5
- data/lib/action_controller/metal/strong_parameters.rb +13 -4
- data/lib/action_controller/metal/url_for.rb +3 -3
- data/lib/action_controller/metal.rb +3 -3
- data/lib/action_controller/renderer.rb +1 -1
- data/lib/action_controller/test_case.rb +3 -3
- data/lib/action_controller.rb +1 -0
- data/lib/action_dispatch/http/content_security_policy.rb +71 -8
- data/lib/action_dispatch/http/mime_negotiation.rb +2 -2
- data/lib/action_dispatch/http/permissions_policy.rb +16 -0
- data/lib/action_dispatch/http/request.rb +2 -2
- data/lib/action_dispatch/http/response.rb +2 -3
- data/lib/action_dispatch/middleware/cookies.rb +6 -3
- data/lib/action_dispatch/middleware/flash.rb +8 -7
- data/lib/action_dispatch/middleware/request_id.rb +1 -1
- data/lib/action_dispatch/middleware/server_timing.rb +53 -10
- data/lib/action_dispatch/middleware/session/cookie_store.rb +9 -9
- data/lib/action_dispatch/routing/mapper.rb +5 -5
- data/lib/action_dispatch/routing/redirection.rb +5 -0
- data/lib/action_dispatch/routing/route_set.rb +3 -1
- data/lib/action_dispatch/routing/url_for.rb +3 -3
- data/lib/action_dispatch/routing.rb +3 -4
- data/lib/action_dispatch/testing/assertions/routing.rb +3 -2
- data/lib/action_dispatch/testing/test_response.rb +20 -2
- data/lib/action_pack/gem_version.rb +3 -3
- data/lib/action_pack/version.rb +1 -1
- metadata +12 -12
@@ -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
|
@@ -30,7 +30,7 @@ module ActionController
|
|
30
30
|
super
|
31
31
|
end
|
32
32
|
|
33
|
-
#
|
33
|
+
# Override render_to_string because body can now be set to a Rack body.
|
34
34
|
def render_to_string(*)
|
35
35
|
result = super
|
36
36
|
if result.respond_to?(:each)
|
@@ -78,8 +78,8 @@ module ActionController
|
|
78
78
|
end
|
79
79
|
|
80
80
|
def _set_vary_header
|
81
|
-
if
|
82
|
-
|
81
|
+
if response.headers["Vary"].blank? && request.should_apply_vary_header?
|
82
|
+
response.headers["Vary"] = "Accept"
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
@@ -32,7 +32,7 @@ module ActionController # :nodoc:
|
|
32
32
|
# response may be extracted. To prevent this, only XmlHttpRequest (known as XHR or
|
33
33
|
# Ajax) requests are allowed to make requests for JavaScript responses.
|
34
34
|
#
|
35
|
-
# Subclasses of
|
35
|
+
# Subclasses of ActionController::Base are protected by default with the
|
36
36
|
# <tt>:exception</tt> strategy, which raises an
|
37
37
|
# <tt>ActionController::InvalidAuthenticityToken</tt> error on unverified requests.
|
38
38
|
#
|
@@ -124,8 +124,8 @@ module ActionController # :nodoc:
|
|
124
124
|
#
|
125
125
|
# Valid Options:
|
126
126
|
#
|
127
|
-
# * <tt>:only
|
128
|
-
# * <tt>:if
|
127
|
+
# * <tt>:only</tt> / <tt>:except</tt> - Only apply forgery protection to a subset of actions. For example <tt>only: [ :create, :create_all ]</tt>.
|
128
|
+
# * <tt>:if</tt> / <tt>:unless</tt> - Turn off the forgery protection entirely depending on the passed Proc or method reference.
|
129
129
|
# * <tt>:prepend</tt> - By default, the verification of the authentication token will be added at the position of the
|
130
130
|
# protect_from_forgery call in your application. This means any callbacks added before are run first. This is useful
|
131
131
|
# when you want your forgery protection to depend on other callbacks, like authentication methods (Oauth vs Cookie auth).
|
@@ -168,7 +168,7 @@ module ActionController # :nodoc:
|
|
168
168
|
#
|
169
169
|
# See +skip_before_action+ for allowed options.
|
170
170
|
def skip_forgery_protection(options = {})
|
171
|
-
skip_before_action :verify_authenticity_token, options
|
171
|
+
skip_before_action :verify_authenticity_token, options.reverse_merge(raise: false)
|
172
172
|
end
|
173
173
|
|
174
174
|
private
|
@@ -24,7 +24,7 @@ module ActionController # :nodoc:
|
|
24
24
|
# Ruby implementation).
|
25
25
|
#
|
26
26
|
# Streaming can be added to a given template easily, all you need to do is
|
27
|
-
# to pass the
|
27
|
+
# to pass the +:stream+ option.
|
28
28
|
#
|
29
29
|
# class PostsController
|
30
30
|
# def index
|
@@ -59,8 +59,8 @@ module ActionController # :nodoc:
|
|
59
59
|
# render stream: true
|
60
60
|
# end
|
61
61
|
#
|
62
|
-
# Notice that
|
63
|
-
# or
|
62
|
+
# Notice that +:stream+ only works with templates. Rendering +:json+
|
63
|
+
# or +:xml+ with +:stream+ won't work.
|
64
64
|
#
|
65
65
|
# == Communication between layout and template
|
66
66
|
#
|
@@ -72,7 +72,7 @@ module ActionController # :nodoc:
|
|
72
72
|
# variables set in the template to be used in the layout, they won't
|
73
73
|
# work once you move to streaming. The proper way to communicate
|
74
74
|
# between layout and template, regardless of whether you use streaming
|
75
|
-
# or not, is by using +content_for+, +provide
|
75
|
+
# or not, is by using +content_for+, +provide+, and +yield+.
|
76
76
|
#
|
77
77
|
# Take a simple example where the layout expects the template to tell
|
78
78
|
# which title to use:
|
@@ -132,7 +132,7 @@ module ActionController # :nodoc:
|
|
132
132
|
# That said, when streaming, you need to properly check your templates
|
133
133
|
# and choose when to use +provide+ and +content_for+.
|
134
134
|
#
|
135
|
-
# == Headers, cookies, session and flash
|
135
|
+
# == Headers, cookies, session, and flash
|
136
136
|
#
|
137
137
|
# When streaming, the HTTP headers are sent to the client right before
|
138
138
|
# it renders the first line. This means that, modifying headers, cookies,
|
@@ -236,7 +236,7 @@ module ActionController
|
|
236
236
|
# By default, never raise an UnpermittedParameters exception if these
|
237
237
|
# params are present. The default includes both 'controller' and 'action'
|
238
238
|
# because they are added by Rails and should be of no concern. One way
|
239
|
-
# to change these is to specify
|
239
|
+
# to change these is to specify +always_permitted_parameters+ in your
|
240
240
|
# config. For instance:
|
241
241
|
#
|
242
242
|
# config.action_controller.always_permitted_parameters = %w( controller action format )
|
@@ -279,10 +279,15 @@ module ActionController
|
|
279
279
|
@parameters == other
|
280
280
|
end
|
281
281
|
end
|
282
|
-
|
282
|
+
|
283
|
+
def eql?(other)
|
284
|
+
self.class == other.class &&
|
285
|
+
permitted? == other.permitted? &&
|
286
|
+
parameters.eql?(other.parameters)
|
287
|
+
end
|
283
288
|
|
284
289
|
def hash
|
285
|
-
[@parameters
|
290
|
+
[self.class, @parameters, @permitted].hash
|
286
291
|
end
|
287
292
|
|
288
293
|
# Returns a safe <tt>ActiveSupport::HashWithIndifferentAccess</tt>
|
@@ -778,7 +783,7 @@ module ActionController
|
|
778
783
|
|
779
784
|
# Deletes a key-value pair from +Parameters+ and returns the value. If
|
780
785
|
# +key+ is not found, returns +nil+ (or, with optional code block, yields
|
781
|
-
# +key+ and returns the result). Cf.
|
786
|
+
# +key+ and returns the result). Cf. #extract!, which returns the
|
782
787
|
# corresponding +ActionController::Parameters+ object.
|
783
788
|
def delete(key, &block)
|
784
789
|
convert_value_to_parameters(@parameters.delete(key, &block))
|
@@ -908,6 +913,10 @@ module ActionController
|
|
908
913
|
end
|
909
914
|
end
|
910
915
|
|
916
|
+
def encode_with(coder) # :nodoc:
|
917
|
+
coder.map = { "parameters" => @parameters, "permitted" => @permitted }
|
918
|
+
end
|
919
|
+
|
911
920
|
# Returns duplicate of object including all parameters.
|
912
921
|
def deep_dup
|
913
922
|
self.class.new(@parameters.deep_dup, @logging_context).tap do |duplicate|
|
@@ -4,11 +4,11 @@ module ActionController
|
|
4
4
|
# Includes +url_for+ into the host class. The class has to provide a +RouteSet+ by implementing
|
5
5
|
# the <tt>_routes</tt> method. Otherwise, an exception will be raised.
|
6
6
|
#
|
7
|
-
# In addition to
|
7
|
+
# In addition to AbstractController::UrlFor, this module accesses the HTTP layer to define
|
8
8
|
# URL options like the +host+. In order to do so, this module requires the host class
|
9
9
|
# to implement +env+ which needs to be Rack-compatible and +request+
|
10
|
-
# which is either an instance of
|
11
|
-
# that responds to the +host+, +optional_port+, +protocol
|
10
|
+
# which is either an instance of ActionDispatch::Request or an object
|
11
|
+
# that responds to the +host+, +optional_port+, +protocol+, and
|
12
12
|
# +symbolized_path_parameter+ methods.
|
13
13
|
#
|
14
14
|
# class RootUrl
|
@@ -60,7 +60,7 @@ module ActionController
|
|
60
60
|
|
61
61
|
# <tt>ActionController::Metal</tt> is the simplest possible controller, providing a
|
62
62
|
# valid Rack interface without the additional niceties provided by
|
63
|
-
#
|
63
|
+
# ActionController::Base.
|
64
64
|
#
|
65
65
|
# A sample metal controller might look like this:
|
66
66
|
#
|
@@ -111,7 +111,7 @@ module ActionController
|
|
111
111
|
#
|
112
112
|
# == Other Helpers
|
113
113
|
#
|
114
|
-
# You can refer to the modules included in
|
114
|
+
# You can refer to the modules included in ActionController::Base to see
|
115
115
|
# other features you can bring into your metal controller.
|
116
116
|
#
|
117
117
|
class Metal < AbstractController::Base
|
@@ -137,7 +137,7 @@ module ActionController
|
|
137
137
|
false
|
138
138
|
end
|
139
139
|
|
140
|
-
# Delegates to the class'
|
140
|
+
# Delegates to the class's ::controller_name.
|
141
141
|
def controller_name
|
142
142
|
self.class.controller_name
|
143
143
|
end
|
@@ -71,7 +71,7 @@ module ActionController
|
|
71
71
|
# Render templates with any options from ActionController::Base#render_to_string.
|
72
72
|
#
|
73
73
|
# The primary options are:
|
74
|
-
# * <tt>:partial</tt> - See
|
74
|
+
# * <tt>:partial</tt> - See ActionView::PartialRenderer for details.
|
75
75
|
# * <tt>:file</tt> - Renders an explicit template file. Add <tt>:locals</tt> to pass in, if so desired.
|
76
76
|
# It shouldn’t be used directly with unsanitized user input due to lack of validation.
|
77
77
|
# * <tt>:inline</tt> - Renders an ERB template string.
|
@@ -241,7 +241,7 @@ module ActionController
|
|
241
241
|
# == Basic example
|
242
242
|
#
|
243
243
|
# Functional tests are written as follows:
|
244
|
-
# 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
|
245
245
|
# an HTTP request.
|
246
246
|
# 2. Then, one asserts whether the current state is as expected. "State" can be anything:
|
247
247
|
# the controller's HTTP response, the database contents, etc.
|
@@ -391,7 +391,7 @@ module ActionController
|
|
391
391
|
#
|
392
392
|
# You can also simulate POST, PATCH, PUT, DELETE, and HEAD requests with
|
393
393
|
# +post+, +patch+, +put+, +delete+, and +head+.
|
394
|
-
# Example sending parameters, session and setting a flash message:
|
394
|
+
# Example sending parameters, session, and setting a flash message:
|
395
395
|
#
|
396
396
|
# get :show,
|
397
397
|
# params: { id: 7 },
|
@@ -461,7 +461,7 @@ module ActionController
|
|
461
461
|
# session: { user_id: 1 },
|
462
462
|
# flash: { notice: 'This is flash message' }
|
463
463
|
#
|
464
|
-
# To simulate +GET+, +POST+, +PATCH+, +PUT+, +DELETE
|
464
|
+
# To simulate +GET+, +POST+, +PATCH+, +PUT+, +DELETE+, and +HEAD+ requests
|
465
465
|
# prefer using #get, #post, #patch, #put, #delete and #head methods
|
466
466
|
# respectively which will make tests more expressive.
|
467
467
|
#
|
data/lib/action_controller.rb
CHANGED
@@ -1,8 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/object/deep_dup"
|
4
|
+
require "active_support/core_ext/array/wrap"
|
4
5
|
|
5
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
|
6
24
|
class ContentSecurityPolicy
|
7
25
|
class Middleware
|
8
26
|
CONTENT_TYPE = "Content-Type"
|
@@ -17,7 +35,6 @@ module ActionDispatch # :nodoc:
|
|
17
35
|
request = ActionDispatch::Request.new env
|
18
36
|
_, headers, _ = response = @app.call(env)
|
19
37
|
|
20
|
-
return response unless html_response?(headers)
|
21
38
|
return response if policy_present?(headers)
|
22
39
|
|
23
40
|
if policy = request.content_security_policy
|
@@ -31,12 +48,6 @@ module ActionDispatch # :nodoc:
|
|
31
48
|
end
|
32
49
|
|
33
50
|
private
|
34
|
-
def html_response?(headers)
|
35
|
-
if content_type = headers[CONTENT_TYPE]
|
36
|
-
/html/.match?(content_type)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
51
|
def header_name(request)
|
41
52
|
if request.content_security_policy_report_only
|
42
53
|
POLICY_REPORT_ONLY
|
@@ -174,6 +185,15 @@ module ActionDispatch # :nodoc:
|
|
174
185
|
end
|
175
186
|
end
|
176
187
|
|
188
|
+
# Specify whether to prevent the user agent from loading any assets over
|
189
|
+
# HTTP when the page uses HTTPS:
|
190
|
+
#
|
191
|
+
# policy.block_all_mixed_content
|
192
|
+
#
|
193
|
+
# Pass +false+ to allow it again:
|
194
|
+
#
|
195
|
+
# policy.block_all_mixed_content false
|
196
|
+
#
|
177
197
|
def block_all_mixed_content(enabled = true)
|
178
198
|
if enabled
|
179
199
|
@directives["block-all-mixed-content"] = true
|
@@ -182,6 +202,14 @@ module ActionDispatch # :nodoc:
|
|
182
202
|
end
|
183
203
|
end
|
184
204
|
|
205
|
+
# Restricts the set of plugins that can be embedded:
|
206
|
+
#
|
207
|
+
# policy.plugin_types "application/x-shockwave-flash"
|
208
|
+
#
|
209
|
+
# Leave empty to allow all plugins:
|
210
|
+
#
|
211
|
+
# policy.plugin_types
|
212
|
+
#
|
185
213
|
def plugin_types(*types)
|
186
214
|
if types.first
|
187
215
|
@directives["plugin-types"] = types
|
@@ -190,10 +218,24 @@ module ActionDispatch # :nodoc:
|
|
190
218
|
end
|
191
219
|
end
|
192
220
|
|
221
|
+
# Enable the {report-uri}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-uri]
|
222
|
+
# directive. Violation reports will be sent to the specified URI:
|
223
|
+
#
|
224
|
+
# policy.report_uri "/csp-violation-report-endpoint"
|
225
|
+
#
|
193
226
|
def report_uri(uri)
|
194
227
|
@directives["report-uri"] = [uri]
|
195
228
|
end
|
196
229
|
|
230
|
+
# Specify asset types for which {Subresource Integrity}[https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity]
|
231
|
+
# is required:
|
232
|
+
#
|
233
|
+
# policy.require_sri_for :script, :style
|
234
|
+
#
|
235
|
+
# Leave empty to not require Subresource Integrity:
|
236
|
+
#
|
237
|
+
# policy.require_sri_for
|
238
|
+
#
|
197
239
|
def require_sri_for(*types)
|
198
240
|
if types.first
|
199
241
|
@directives["require-sri-for"] = types
|
@@ -202,6 +244,19 @@ module ActionDispatch # :nodoc:
|
|
202
244
|
end
|
203
245
|
end
|
204
246
|
|
247
|
+
# Specify whether a {sandbox}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox]
|
248
|
+
# should be enabled for the requested resource:
|
249
|
+
#
|
250
|
+
# policy.sandbox
|
251
|
+
#
|
252
|
+
# Values can be passed as arguments:
|
253
|
+
#
|
254
|
+
# policy.sandbox "allow-scripts", "allow-modals"
|
255
|
+
#
|
256
|
+
# Pass +false+ to disable the sandbox:
|
257
|
+
#
|
258
|
+
# policy.sandbox false
|
259
|
+
#
|
205
260
|
def sandbox(*values)
|
206
261
|
if values.empty?
|
207
262
|
@directives["sandbox"] = true
|
@@ -212,6 +267,14 @@ module ActionDispatch # :nodoc:
|
|
212
267
|
end
|
213
268
|
end
|
214
269
|
|
270
|
+
# Specify whether user agents should treat any assets over HTTP as HTTPS:
|
271
|
+
#
|
272
|
+
# policy.upgrade_insecure_requests
|
273
|
+
#
|
274
|
+
# Pass +false+ to disable it:
|
275
|
+
#
|
276
|
+
# policy.upgrade_insecure_requests false
|
277
|
+
#
|
215
278
|
def upgrade_insecure_requests(enabled = true)
|
216
279
|
if enabled
|
217
280
|
@directives["upgrade-insecure-requests"] = true
|
@@ -276,7 +339,7 @@ module ActionDispatch # :nodoc:
|
|
276
339
|
raise RuntimeError, "Missing context for the dynamic content security policy source: #{source.inspect}"
|
277
340
|
else
|
278
341
|
resolved = context.instance_exec(&source)
|
279
|
-
|
342
|
+
apply_mappings(Array.wrap(resolved))
|
280
343
|
end
|
281
344
|
else
|
282
345
|
raise RuntimeError, "Unexpected content security policy source: #{source.inspect}"
|
@@ -132,8 +132,8 @@ module ActionDispatch
|
|
132
132
|
# Sets the \formats by string extensions. This differs from #format= by allowing you
|
133
133
|
# to set multiple, ordered formats, which is useful when you want to have a fallback.
|
134
134
|
#
|
135
|
-
# In this example, the
|
136
|
-
# to the
|
135
|
+
# In this example, the +:iphone+ format will be used if it's available, otherwise it'll fallback
|
136
|
+
# to the +:html+ format.
|
137
137
|
#
|
138
138
|
# class ApplicationController < ActionController::Base
|
139
139
|
# before_action :adjust_format_for_iphone_with_html_fallback
|
@@ -3,6 +3,22 @@
|
|
3
3
|
require "active_support/core_ext/object/deep_dup"
|
4
4
|
|
5
5
|
module ActionDispatch # :nodoc:
|
6
|
+
# Configures the HTTP
|
7
|
+
# {Feature-Policy}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy]
|
8
|
+
# response header to specify which browser features the current document and
|
9
|
+
# its iframes can use.
|
10
|
+
#
|
11
|
+
# Example global policy:
|
12
|
+
#
|
13
|
+
# Rails.application.config.permissions_policy do |policy|
|
14
|
+
# policy.camera :none
|
15
|
+
# policy.gyroscope :none
|
16
|
+
# policy.microphone :none
|
17
|
+
# policy.usb :none
|
18
|
+
# policy.fullscreen :self
|
19
|
+
# policy.payment :self, "https://secure.example.com"
|
20
|
+
# end
|
21
|
+
#
|
6
22
|
class PermissionsPolicy
|
7
23
|
class Middleware
|
8
24
|
CONTENT_TYPE = "Content-Type"
|
@@ -298,8 +298,8 @@ module ActionDispatch
|
|
298
298
|
ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id" # :nodoc:
|
299
299
|
|
300
300
|
# Returns the unique request id, which is based on either the X-Request-Id header that can
|
301
|
-
# be generated by a firewall, load balancer, or web server or by the RequestId middleware
|
302
|
-
# (which sets the action_dispatch.request_id environment variable).
|
301
|
+
# be generated by a firewall, load balancer, or web server, or by the RequestId middleware
|
302
|
+
# (which sets the +action_dispatch.request_id+ environment variable).
|
303
303
|
#
|
304
304
|
# This unique ID is useful for tracing a request from end-to-end as part of logging or debugging.
|
305
305
|
# This relies on the Rack variable set by the ActionDispatch::RequestId middleware.
|
@@ -21,9 +21,8 @@ module ActionDispatch # :nodoc:
|
|
21
21
|
# Nevertheless, integration tests may want to inspect controller responses in
|
22
22
|
# more detail, and that's when \Response can be useful for application
|
23
23
|
# developers. Integration test methods such as
|
24
|
-
#
|
25
|
-
#
|
26
|
-
# TestResponse (which are of course also of type \Response).
|
24
|
+
# Integration::RequestHelpers#get and Integration::RequestHelpers#post return
|
25
|
+
# objects of type TestResponse (which are of course also of type \Response).
|
27
26
|
#
|
28
27
|
# For example, the following demo integration test prints the body of the
|
29
28
|
# controller response to the console:
|
@@ -92,7 +92,7 @@ module ActionDispatch
|
|
92
92
|
include RequestCookieMethods
|
93
93
|
end
|
94
94
|
|
95
|
-
# Read and write data to cookies through ActionController#cookies.
|
95
|
+
# Read and write data to cookies through ActionController::Base#cookies.
|
96
96
|
#
|
97
97
|
# When reading cookie data, the data is read from the HTTP request header, Cookie.
|
98
98
|
# When writing cookie data, the data is sent out in the HTTP response header, Set-Cookie.
|
@@ -139,7 +139,7 @@ module ActionDispatch
|
|
139
139
|
#
|
140
140
|
# cookies.delete :user_name
|
141
141
|
#
|
142
|
-
# Please note that if you specify a
|
142
|
+
# Please note that if you specify a +:domain+ when setting a cookie, you must also specify the domain when deleting the cookie:
|
143
143
|
#
|
144
144
|
# cookies[:name] = {
|
145
145
|
# value: 'a yummy cookie',
|
@@ -176,6 +176,9 @@ module ActionDispatch
|
|
176
176
|
# Default is +false+.
|
177
177
|
# * <tt>:httponly</tt> - Whether this cookie is accessible via scripting or
|
178
178
|
# only HTTP. Defaults to +false+.
|
179
|
+
# * <tt>:same_site</tt> - The value of the +SameSite+ cookie attribute, which
|
180
|
+
# determines how this cookie should be restricted in cross-site contexts.
|
181
|
+
# Possible values are +:none+, +:lax+, and +:strict+. Defaults to +:lax+.
|
179
182
|
class Cookies
|
180
183
|
HTTP_HEADER = "Set-Cookie"
|
181
184
|
GENERATOR_KEY = "action_dispatch.key_generator"
|
@@ -199,7 +202,7 @@ module ActionDispatch
|
|
199
202
|
# Raised when storing more than 4K of session data.
|
200
203
|
CookieOverflow = Class.new StandardError
|
201
204
|
|
202
|
-
# Include in a cookie jar to allow chaining, e.g. cookies.permanent.signed
|
205
|
+
# Include in a cookie jar to allow chaining, e.g. +cookies.permanent.signed+.
|
203
206
|
module ChainedCookieJars
|
204
207
|
# Returns a jar that'll automatically set the assigned cookies to have an expiration date 20 years from now. Example:
|
205
208
|
#
|
@@ -20,10 +20,11 @@ module ActionDispatch
|
|
20
20
|
# end
|
21
21
|
# end
|
22
22
|
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
23
|
+
# Then in +show.html.erb+:
|
24
|
+
#
|
25
|
+
# <% if flash[:notice] %>
|
26
|
+
# <div class="notice"><%= flash[:notice] %></div>
|
27
|
+
# <% end %>
|
27
28
|
#
|
28
29
|
# Since the +notice+ and +alert+ keys are a common idiom, convenience accessors are available:
|
29
30
|
#
|
@@ -41,9 +42,9 @@ module ActionDispatch
|
|
41
42
|
KEY = "action_dispatch.request.flash_hash"
|
42
43
|
|
43
44
|
module RequestMethods
|
44
|
-
# Access the contents of the flash.
|
45
|
-
#
|
46
|
-
#
|
45
|
+
# Access the contents of the flash. Returns a ActionDispatch::Flash::FlashHash.
|
46
|
+
#
|
47
|
+
# See ActionDispatch::Flash for example usage.
|
47
48
|
def flash
|
48
49
|
flash = flash_hash
|
49
50
|
return flash if flash
|
@@ -5,7 +5,7 @@ require "active_support/core_ext/string/access"
|
|
5
5
|
|
6
6
|
module ActionDispatch
|
7
7
|
# Makes a unique request id available to the +action_dispatch.request_id+ env variable (which is then accessible
|
8
|
-
# through
|
8
|
+
# through ActionDispatch::Request#request_id or the alias ActionDispatch::Request#uuid) and sends
|
9
9
|
# the same id to the client via the X-Request-Id header.
|
10
10
|
#
|
11
11
|
# The unique request id is either based on the X-Request-Id header in the request, which would typically be generated
|
@@ -6,28 +6,71 @@ module ActionDispatch
|
|
6
6
|
class ServerTiming
|
7
7
|
SERVER_TIMING_HEADER = "Server-Timing"
|
8
8
|
|
9
|
+
class Subscriber # :nodoc:
|
10
|
+
include Singleton
|
11
|
+
KEY = :action_dispatch_server_timing_events
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@mutex = Mutex.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(event)
|
18
|
+
if events = ActiveSupport::IsolatedExecutionState[KEY]
|
19
|
+
events << event
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def collect_events
|
24
|
+
events = []
|
25
|
+
ActiveSupport::IsolatedExecutionState[KEY] = events
|
26
|
+
yield
|
27
|
+
events
|
28
|
+
ensure
|
29
|
+
ActiveSupport::IsolatedExecutionState.delete(KEY)
|
30
|
+
end
|
31
|
+
|
32
|
+
def ensure_subscribed
|
33
|
+
@mutex.synchronize do
|
34
|
+
# Subscribe to all events, except those beginning with "!"
|
35
|
+
# Ideally we would be more selective of what is being measured
|
36
|
+
@subscriber ||= ActiveSupport::Notifications.subscribe(/\A[^!]/, self)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def unsubscribe
|
41
|
+
@mutex.synchronize do
|
42
|
+
ActiveSupport::Notifications.unsubscribe @subscriber
|
43
|
+
@subscriber = nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.unsubscribe # :nodoc:
|
49
|
+
Subscriber.instance.unsubscribe
|
50
|
+
end
|
51
|
+
|
9
52
|
def initialize(app)
|
10
53
|
@app = app
|
54
|
+
@subscriber = Subscriber.instance
|
55
|
+
@subscriber.ensure_subscribed
|
11
56
|
end
|
12
57
|
|
13
58
|
def call(env)
|
14
|
-
|
15
|
-
|
16
|
-
|
59
|
+
response = nil
|
60
|
+
events = @subscriber.collect_events do
|
61
|
+
response = @app.call(env)
|
17
62
|
end
|
18
63
|
|
19
|
-
|
20
|
-
@app.call(env)
|
21
|
-
ensure
|
22
|
-
ActiveSupport::Notifications.unsubscribe(subscriber)
|
23
|
-
end
|
64
|
+
headers = response[1]
|
24
65
|
|
25
66
|
header_info = events.group_by(&:name).map do |event_name, events_collection|
|
26
|
-
"
|
67
|
+
"%s;dur=%.2f" % [event_name, events_collection.sum(&:duration)]
|
27
68
|
end
|
69
|
+
|
70
|
+
header_info.prepend(headers[SERVER_TIMING_HEADER]) if headers[SERVER_TIMING_HEADER].present?
|
28
71
|
headers[SERVER_TIMING_HEADER] = header_info.join(", ")
|
29
72
|
|
30
|
-
|
73
|
+
response
|
31
74
|
end
|
32
75
|
end
|
33
76
|
end
|