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
@@ -33,77 +33,100 @@ module ActionController
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
# Sets the +etag+, +last_modified+, or both on the response and renders a
|
36
|
+
# Sets the +etag+, +last_modified+, or both on the response, and renders a
|
37
37
|
# <tt>304 Not Modified</tt> response if the request is already fresh.
|
38
38
|
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
# +:weak_etag+ option.
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
39
|
+
# ==== Options
|
40
|
+
#
|
41
|
+
# [+:etag+]
|
42
|
+
# Sets a "weak" ETag validator on the response. See the +:weak_etag+ option.
|
43
|
+
# [+:weak_etag+]
|
44
|
+
# Sets a "weak" ETag validator on the response. Requests that specify an
|
45
|
+
# +If-None-Match+ header may receive a <tt>304 Not Modified</tt> response
|
46
|
+
# if the ETag matches exactly.
|
47
|
+
#
|
48
|
+
# A weak ETag indicates semantic equivalence, not byte-for-byte equality,
|
49
|
+
# so they're good for caching HTML pages in browser caches. They can't be
|
50
|
+
# used for responses that must be byte-identical, like serving +Range+
|
51
|
+
# requests within a PDF file.
|
52
|
+
# [+:strong_etag+]
|
53
|
+
# Sets a "strong" ETag validator on the response. Requests that specify an
|
54
|
+
# +If-None-Match+ header may receive a <tt>304 Not Modified</tt> response
|
55
|
+
# if the ETag matches exactly.
|
56
|
+
#
|
57
|
+
# A strong ETag implies exact equality -- the response must match byte for
|
58
|
+
# byte. This is necessary for serving +Range+ requests within a large
|
59
|
+
# video or PDF file, for example, or for compatibility with some CDNs that
|
60
|
+
# don't support weak ETags.
|
61
|
+
# [+:last_modified+]
|
62
|
+
# Sets a "weak" last-update validator on the response. Subsequent requests
|
63
|
+
# that specify an +If-Modified-Since+ header may receive a <tt>304 Not Modified</tt>
|
64
|
+
# response if +last_modified+ <= +If-Modified-Since+.
|
65
|
+
# [+:public+]
|
66
|
+
# By default the +Cache-Control+ header is private. Set this option to
|
67
|
+
# +true+ if you want your application to be cacheable by other devices,
|
68
|
+
# such as proxy caches.
|
69
|
+
# [+:cache_control+]
|
70
|
+
# When given, will overwrite an existing +Cache-Control+ header. For a
|
71
|
+
# list of +Cache-Control+ directives, see the {article on
|
72
|
+
# MDN}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control].
|
73
|
+
# [+:template+]
|
74
|
+
# By default, the template digest for the current controller/action is
|
75
|
+
# included in ETags. If the action renders a different template, you can
|
76
|
+
# include its digest instead. If the action doesn't render a template at
|
77
|
+
# all, you can pass <tt>template: false</tt> to skip any attempt to check
|
78
|
+
# for a template digest.
|
79
|
+
#
|
80
|
+
# ==== Examples
|
67
81
|
#
|
68
82
|
# def show
|
69
83
|
# @article = Article.find(params[:id])
|
70
84
|
# fresh_when(etag: @article, last_modified: @article.updated_at, public: true)
|
71
85
|
# end
|
72
86
|
#
|
73
|
-
# This will
|
74
|
-
# If-Modified-Since header
|
87
|
+
# This will send a <tt>304 Not Modified</tt> response if the request
|
88
|
+
# specifies a matching ETag and +If-Modified-Since+ header. Otherwise, it
|
89
|
+
# will render the +show+ template.
|
75
90
|
#
|
76
|
-
# You can also just pass a record
|
77
|
-
# by calling +updated_at+ and +etag+ by passing the object itself.
|
91
|
+
# You can also just pass a record:
|
78
92
|
#
|
79
93
|
# def show
|
80
94
|
# @article = Article.find(params[:id])
|
81
95
|
# fresh_when(@article)
|
82
96
|
# end
|
83
97
|
#
|
98
|
+
# +etag+ will be set to the record, and +last_modified+ will be set to the
|
99
|
+
# record's +updated_at+.
|
100
|
+
#
|
84
101
|
# You can also pass an object that responds to +maximum+, such as a
|
85
|
-
# collection of
|
86
|
-
# calling <tt>maximum(:updated_at)</tt> on the collection (the timestamp of the
|
87
|
-
# most recently updated record) and the +etag+ by passing the object itself.
|
102
|
+
# collection of records:
|
88
103
|
#
|
89
104
|
# def index
|
90
105
|
# @articles = Article.all
|
91
106
|
# fresh_when(@articles)
|
92
107
|
# end
|
93
108
|
#
|
94
|
-
#
|
109
|
+
# In this case, +etag+ will be set to the collection, and +last_modified+
|
110
|
+
# will be set to <tt>maximum(:updated_at)</tt> (the timestamp of the most
|
111
|
+
# recently updated record).
|
112
|
+
#
|
113
|
+
# When passing a record or a collection, you can still specify other
|
114
|
+
# options, such as +:public+ and +:cache_control+:
|
95
115
|
#
|
96
116
|
# def show
|
97
117
|
# @article = Article.find(params[:id])
|
98
|
-
# fresh_when(@article, public: true)
|
118
|
+
# fresh_when(@article, public: true, cache_control: { no_cache: true })
|
99
119
|
# end
|
100
120
|
#
|
101
|
-
#
|
102
|
-
#
|
121
|
+
# The above will set <tt>Cache-Control: public, no-cache</tt> in the response.
|
122
|
+
#
|
123
|
+
# When rendering a different template than the controller/action's default
|
124
|
+
# template, you can indicate which digest to include in the ETag:
|
103
125
|
#
|
104
|
-
# before_action { fresh_when @article, template:
|
126
|
+
# before_action { fresh_when @article, template: "widgets/show" }
|
105
127
|
#
|
106
|
-
def fresh_when(object = nil, etag: nil, weak_etag: nil, strong_etag: nil, last_modified: nil, public: false, template: nil)
|
128
|
+
def fresh_when(object = nil, etag: nil, weak_etag: nil, strong_etag: nil, last_modified: nil, public: false, cache_control: {}, template: nil)
|
129
|
+
response.cache_control.delete(:no_store)
|
107
130
|
weak_etag ||= etag || object unless strong_etag
|
108
131
|
last_modified ||= object.try(:updated_at) || object.try(:maximum, :updated_at)
|
109
132
|
|
@@ -117,43 +140,21 @@ module ActionController
|
|
117
140
|
|
118
141
|
response.last_modified = last_modified if last_modified
|
119
142
|
response.cache_control[:public] = true if public
|
143
|
+
response.cache_control.merge!(cache_control)
|
120
144
|
|
121
145
|
head :not_modified if request.fresh?(response)
|
122
146
|
end
|
123
147
|
|
124
|
-
# Sets the +etag+ and/or +last_modified+ on the response and checks
|
125
|
-
# the
|
126
|
-
#
|
127
|
-
# it
|
128
|
-
#
|
129
|
-
#
|
130
|
-
#
|
131
|
-
#
|
132
|
-
#
|
133
|
-
#
|
134
|
-
# Requests that set If-None-Match header may return a 304 Not Modified
|
135
|
-
# response if it matches the ETag exactly. A weak ETag indicates semantic
|
136
|
-
# equivalence, not byte-for-byte equality, so they're good for caching
|
137
|
-
# HTML pages in browser caches. They can't be used for responses that
|
138
|
-
# must be byte-identical, like serving Range requests within a PDF file.
|
139
|
-
# * <tt>:strong_etag</tt> Sets a "strong" ETag validator on the response.
|
140
|
-
# Requests that set If-None-Match header may return a 304 Not Modified
|
141
|
-
# response if it matches the ETag exactly. A strong ETag implies exact
|
142
|
-
# equality: the response must match byte for byte. This is necessary for
|
143
|
-
# doing Range requests within a large video or PDF file, for example, or
|
144
|
-
# for compatibility with some CDNs that don't support weak ETags.
|
145
|
-
# * <tt>:last_modified</tt> Sets a "weak" last-update validator on the
|
146
|
-
# response. Subsequent requests that set If-Modified-Since may return a
|
147
|
-
# 304 Not Modified response if last_modified <= If-Modified-Since.
|
148
|
-
# * <tt>:public</tt> By default the Cache-Control header is private, set this to
|
149
|
-
# +true+ if you want your application to be cacheable by other devices (proxy caches).
|
150
|
-
# * <tt>:template</tt> By default, the template digest for the current
|
151
|
-
# controller/action is included in ETags. If the action renders a
|
152
|
-
# different template, you can include its digest instead. If the action
|
153
|
-
# doesn't render a template at all, you can pass <tt>template: false</tt>
|
154
|
-
# to skip any attempt to check for a template digest.
|
155
|
-
#
|
156
|
-
# === Example:
|
148
|
+
# Sets the +etag+ and/or +last_modified+ on the response and checks them
|
149
|
+
# against the request. If the request doesn't match the provided options, it
|
150
|
+
# is considered stale, and the response should be rendered from scratch.
|
151
|
+
# Otherwise, it is fresh, and a <tt>304 Not Modified</tt> is sent.
|
152
|
+
#
|
153
|
+
# ==== Options
|
154
|
+
#
|
155
|
+
# See #fresh_when for supported options.
|
156
|
+
#
|
157
|
+
# ==== Examples
|
157
158
|
#
|
158
159
|
# def show
|
159
160
|
# @article = Article.find(params[:id])
|
@@ -166,8 +167,7 @@ module ActionController
|
|
166
167
|
# end
|
167
168
|
# end
|
168
169
|
#
|
169
|
-
# You can also just pass a record
|
170
|
-
# by calling +updated_at+ and +etag+ by passing the object itself.
|
170
|
+
# You can also just pass a record:
|
171
171
|
#
|
172
172
|
# def show
|
173
173
|
# @article = Article.find(params[:id])
|
@@ -180,10 +180,11 @@ module ActionController
|
|
180
180
|
# end
|
181
181
|
# end
|
182
182
|
#
|
183
|
+
# +etag+ will be set to the record, and +last_modified+ will be set to the
|
184
|
+
# record's +updated_at+.
|
185
|
+
#
|
183
186
|
# You can also pass an object that responds to +maximum+, such as a
|
184
|
-
# collection of
|
185
|
-
# calling <tt>maximum(:updated_at)</tt> on the collection (the timestamp of the
|
186
|
-
# most recently updated record) and the +etag+ by passing the object itself.
|
187
|
+
# collection of records:
|
187
188
|
#
|
188
189
|
# def index
|
189
190
|
# @articles = Article.all
|
@@ -196,24 +197,31 @@ module ActionController
|
|
196
197
|
# end
|
197
198
|
# end
|
198
199
|
#
|
199
|
-
#
|
200
|
+
# In this case, +etag+ will be set to the collection, and +last_modified+
|
201
|
+
# will be set to <tt>maximum(:updated_at)</tt> (the timestamp of the most
|
202
|
+
# recently updated record).
|
203
|
+
#
|
204
|
+
# When passing a record or a collection, you can still specify other
|
205
|
+
# options, such as +:public+ and +:cache_control+:
|
200
206
|
#
|
201
207
|
# def show
|
202
208
|
# @article = Article.find(params[:id])
|
203
209
|
#
|
204
|
-
# if stale?(@article, public: true)
|
205
|
-
# @statistics = @
|
210
|
+
# if stale?(@article, public: true, cache_control: { no_cache: true })
|
211
|
+
# @statistics = @articles.really_expensive_call
|
206
212
|
# respond_to do |format|
|
207
213
|
# # all the supported formats
|
208
214
|
# end
|
209
215
|
# end
|
210
216
|
# end
|
211
217
|
#
|
212
|
-
#
|
213
|
-
#
|
218
|
+
# The above will set <tt>Cache-Control: public, no-cache</tt> in the response.
|
219
|
+
#
|
220
|
+
# When rendering a different template than the controller/action's default
|
221
|
+
# template, you can indicate which digest to include in the ETag:
|
214
222
|
#
|
215
223
|
# def show
|
216
|
-
# super if stale?
|
224
|
+
# super if stale?(@article, template: "widgets/show")
|
217
225
|
# end
|
218
226
|
#
|
219
227
|
def stale?(object = nil, **freshness_kwargs)
|
@@ -221,29 +229,50 @@ module ActionController
|
|
221
229
|
!request.fresh?(response)
|
222
230
|
end
|
223
231
|
|
224
|
-
# Sets
|
225
|
-
#
|
232
|
+
# Sets the +Cache-Control+ header, overwriting existing directives. This
|
233
|
+
# method will also ensure an HTTP +Date+ header for client compatibility.
|
234
|
+
#
|
235
|
+
# Defaults to issuing the +private+ directive, so that intermediate caches
|
236
|
+
# must not cache the response.
|
237
|
+
#
|
238
|
+
# ==== Options
|
239
|
+
#
|
240
|
+
# [+:public+]
|
241
|
+
# If true, replaces the default +private+ directive with the +public+
|
242
|
+
# directive.
|
243
|
+
# [+:must_revalidate+]
|
244
|
+
# If true, adds the +must-revalidate+ directive.
|
245
|
+
# [+:stale_while_revalidate+]
|
246
|
+
# Sets the value of the +stale-while-revalidate+ directive.
|
247
|
+
# [+:stale_if_error+]
|
248
|
+
# Sets the value of the +stale-if-error+ directive.
|
226
249
|
#
|
227
|
-
#
|
228
|
-
#
|
229
|
-
#
|
250
|
+
# Any additional key-value pairs are concatenated as directives. For a list
|
251
|
+
# of supported +Cache-Control+ directives, see the {article on
|
252
|
+
# MDN}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control].
|
230
253
|
#
|
231
|
-
#
|
232
|
-
# See https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.
|
254
|
+
# ==== Examples
|
233
255
|
#
|
234
|
-
#
|
235
|
-
#
|
256
|
+
# expires_in 10.minutes
|
257
|
+
# # => Cache-Control: max-age=600, private
|
236
258
|
#
|
237
|
-
# expires_in
|
238
|
-
#
|
259
|
+
# expires_in 10.minutes, public: true
|
260
|
+
# # => Cache-Control: max-age=600, public
|
239
261
|
#
|
240
|
-
#
|
241
|
-
#
|
262
|
+
# expires_in 10.minutes, public: true, must_revalidate: true
|
263
|
+
# # => Cache-Control: max-age=600, public, must-revalidate
|
242
264
|
#
|
243
|
-
# expires_in
|
265
|
+
# expires_in 1.hour, stale_while_revalidate: 60.seconds
|
266
|
+
# # => Cache-Control: max-age=3600, private, stale-while-revalidate=60
|
267
|
+
#
|
268
|
+
# expires_in 1.hour, stale_if_error: 5.minutes
|
269
|
+
# # => Cache-Control: max-age=3600, private, stale-if-error=300
|
270
|
+
#
|
271
|
+
# expires_in 1.hour, public: true, "s-maxage": 3.hours, "no-transform": true
|
272
|
+
# # => Cache-Control: max-age=3600, public, s-maxage=10800, no-transform=true
|
244
273
|
#
|
245
|
-
# The method will also ensure an HTTP Date header for client compatibility.
|
246
274
|
def expires_in(seconds, options = {})
|
275
|
+
response.cache_control.delete(:no_store)
|
247
276
|
response.cache_control.merge!(
|
248
277
|
max_age: seconds,
|
249
278
|
public: options.delete(:public),
|
@@ -257,7 +286,7 @@ module ActionController
|
|
257
286
|
response.date = Time.now unless response.date?
|
258
287
|
end
|
259
288
|
|
260
|
-
# Sets an HTTP 1.1 Cache-Control header of <tt>no-cache</tt>. This means the
|
289
|
+
# Sets an HTTP 1.1 +Cache-Control+ header of <tt>no-cache</tt>. This means the
|
261
290
|
# resource will be marked as stale, so clients must always revalidate.
|
262
291
|
# Intermediate/browser caches may still store the asset.
|
263
292
|
def expires_now
|
@@ -280,6 +309,12 @@ module ActionController
|
|
280
309
|
public: public)
|
281
310
|
end
|
282
311
|
|
312
|
+
# Sets an HTTP 1.1 +Cache-Control+ header of <tt>no-store</tt>. This means the
|
313
|
+
# resource may not be stored in any cache.
|
314
|
+
def no_store
|
315
|
+
response.cache_control.replace(no_store: true)
|
316
|
+
end
|
317
|
+
|
283
318
|
private
|
284
319
|
def combine_etags(validator, options)
|
285
320
|
[validator, *etaggers.map { |etagger| instance_exec(options, &etagger) }].compact
|
@@ -1,8 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module ActionController
|
3
|
+
module ActionController # :nodoc:
|
4
4
|
module ContentSecurityPolicy
|
5
|
-
# TODO: Documentation
|
6
5
|
extend ActiveSupport::Concern
|
7
6
|
|
8
7
|
include AbstractController::Helpers
|
@@ -14,6 +13,29 @@ module ActionController #:nodoc:
|
|
14
13
|
end
|
15
14
|
|
16
15
|
module ClassMethods
|
16
|
+
# Overrides parts of the globally configured +Content-Security-Policy+
|
17
|
+
# header:
|
18
|
+
#
|
19
|
+
# class PostsController < ApplicationController
|
20
|
+
# content_security_policy do |policy|
|
21
|
+
# policy.base_uri "https://www.example.com"
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# Options can be passed similar to +before_action+. For example, pass
|
26
|
+
# <tt>only: :index</tt> to override the header on the index action only:
|
27
|
+
#
|
28
|
+
# class PostsController < ApplicationController
|
29
|
+
# content_security_policy(only: :index) do |policy|
|
30
|
+
# policy.default_src :self, :https
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# Pass +false+ to remove the +Content-Security-Policy+ header:
|
35
|
+
#
|
36
|
+
# class PostsController < ApplicationController
|
37
|
+
# content_security_policy false, only: :index
|
38
|
+
# end
|
17
39
|
def content_security_policy(enabled = true, **options, &block)
|
18
40
|
before_action(options) do
|
19
41
|
if block_given?
|
@@ -28,6 +50,18 @@ module ActionController #:nodoc:
|
|
28
50
|
end
|
29
51
|
end
|
30
52
|
|
53
|
+
# Overrides the globally configured +Content-Security-Policy-Report-Only+
|
54
|
+
# header:
|
55
|
+
#
|
56
|
+
# class PostsController < ApplicationController
|
57
|
+
# content_security_policy_report_only only: :index
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# Pass +false+ to remove the +Content-Security-Policy-Report-Only+ header:
|
61
|
+
#
|
62
|
+
# class PostsController < ApplicationController
|
63
|
+
# content_security_policy_report_only false, only: :index
|
64
|
+
# end
|
31
65
|
def content_security_policy_report_only(report_only = true, **options)
|
32
66
|
before_action(options) do
|
33
67
|
request.content_security_policy_report_only = report_only
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require "action_controller/metal/exceptions"
|
4
4
|
require "action_dispatch/http/content_disposition"
|
5
5
|
|
6
|
-
module ActionController
|
6
|
+
module ActionController # :nodoc:
|
7
7
|
# Methods for sending arbitrary data and for streaming files to the browser,
|
8
8
|
# instead of rendering.
|
9
9
|
module DataStreaming
|
@@ -11,14 +11,14 @@ module ActionController #:nodoc:
|
|
11
11
|
|
12
12
|
include ActionController::Rendering
|
13
13
|
|
14
|
-
DEFAULT_SEND_FILE_TYPE = "application/octet-stream"
|
15
|
-
DEFAULT_SEND_FILE_DISPOSITION = "attachment"
|
14
|
+
DEFAULT_SEND_FILE_TYPE = "application/octet-stream" # :nodoc:
|
15
|
+
DEFAULT_SEND_FILE_DISPOSITION = "attachment" # :nodoc:
|
16
16
|
|
17
17
|
private
|
18
|
-
# Sends the file. This uses a server-appropriate method (such as X-Sendfile)
|
19
|
-
# via the Rack::Sendfile middleware. The header to use is set via
|
18
|
+
# Sends the file. This uses a server-appropriate method (such as +X-Sendfile+)
|
19
|
+
# via the +Rack::Sendfile+ middleware. The header to use is set via
|
20
20
|
# +config.action_dispatch.x_sendfile_header+.
|
21
|
-
# Your server can also configure this for you by setting the X-Sendfile-Type header.
|
21
|
+
# Your server can also configure this for you by setting the +X-Sendfile-Type+ header.
|
22
22
|
#
|
23
23
|
# Be careful to sanitize the path parameter if it is coming from a web
|
24
24
|
# page. <tt>send_file(params[:path])</tt> allows a malicious user to
|
@@ -28,17 +28,17 @@ module ActionController #:nodoc:
|
|
28
28
|
# * <tt>:filename</tt> - suggests a filename for the browser to use.
|
29
29
|
# Defaults to <tt>File.basename(path)</tt>.
|
30
30
|
# * <tt>:type</tt> - specifies an HTTP content type.
|
31
|
-
# You can specify either a string or a symbol for a registered type with <tt>Mime::Type.register</tt>, for example
|
31
|
+
# You can specify either a string or a symbol for a registered type with <tt>Mime::Type.register</tt>, for example +:json+.
|
32
32
|
# If omitted, the type will be inferred from the file extension specified in <tt>:filename</tt>.
|
33
|
-
# If no content type is registered for the extension, the default type
|
33
|
+
# If no content type is registered for the extension, the default type +application/octet-stream+ will be used.
|
34
34
|
# * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
|
35
|
-
# Valid values are
|
35
|
+
# Valid values are <tt>"inline"</tt> and <tt>"attachment"</tt> (default).
|
36
36
|
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to 200.
|
37
37
|
# * <tt>:url_based_filename</tt> - set to +true+ if you want the browser to guess the filename from
|
38
38
|
# the URL, which is necessary for i18n filenames on certain browsers
|
39
39
|
# (setting <tt>:filename</tt> overrides this option).
|
40
40
|
#
|
41
|
-
# The default Content-Type and Content-Disposition headers are
|
41
|
+
# The default +Content-Type+ and +Content-Disposition+ headers are
|
42
42
|
# set to download arbitrary binary files in as many browsers as
|
43
43
|
# possible. IE versions 4, 5, 5.5, and 6 are all known to have
|
44
44
|
# a variety of quirks (especially when downloading over SSL).
|
@@ -55,18 +55,18 @@ module ActionController #:nodoc:
|
|
55
55
|
#
|
56
56
|
# send_file '/path/to/404.html', type: 'text/html; charset=utf-8', disposition: 'inline', status: 404
|
57
57
|
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
# https://
|
58
|
+
# You can use other <tt>Content-*</tt> HTTP headers to provide additional
|
59
|
+
# information to the client. See MDN for a
|
60
|
+
# {list of HTTP headers}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers].
|
61
61
|
#
|
62
62
|
# Also be aware that the document may be cached by proxies and browsers.
|
63
|
-
# The Pragma and Cache-Control headers declare how the file may be cached
|
63
|
+
# The +Pragma+ and +Cache-Control+ headers declare how the file may be cached
|
64
64
|
# by intermediaries. They default to require clients to validate with
|
65
65
|
# the server before releasing cached responses. See
|
66
66
|
# https://www.mnot.net/cache_docs/ for an overview of web caching and
|
67
|
-
# https://www.
|
68
|
-
# for the Cache-Control header spec.
|
69
|
-
def send_file(path, options = {})
|
67
|
+
# {RFC 9111}[https://www.rfc-editor.org/rfc/rfc9111.html#name-cache-control]
|
68
|
+
# for the +Cache-Control+ header spec.
|
69
|
+
def send_file(path, options = {}) # :doc:
|
70
70
|
raise MissingFile, "Cannot read file #{path}" unless File.file?(path) && File.readable?(path)
|
71
71
|
|
72
72
|
options[:filename] ||= File.basename(path) unless options[:url_based_filename]
|
@@ -85,12 +85,12 @@ module ActionController #:nodoc:
|
|
85
85
|
#
|
86
86
|
# Options:
|
87
87
|
# * <tt>:filename</tt> - suggests a filename for the browser to use.
|
88
|
-
# * <tt>:type</tt> - specifies an HTTP content type. Defaults to
|
89
|
-
# You can specify either a string or a symbol for a registered type with <tt>Mime::Type.register</tt>, for example
|
88
|
+
# * <tt>:type</tt> - specifies an HTTP content type. Defaults to +application/octet-stream+.
|
89
|
+
# You can specify either a string or a symbol for a registered type with <tt>Mime::Type.register</tt>, for example +:json+.
|
90
90
|
# If omitted, type will be inferred from the file extension specified in <tt>:filename</tt>.
|
91
|
-
# If no content type is registered for the extension, the default type
|
91
|
+
# If no content type is registered for the extension, the default type +application/octet-stream+ will be used.
|
92
92
|
# * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
|
93
|
-
# Valid values are
|
93
|
+
# Valid values are <tt>"inline"</tt> and <tt>"attachment"</tt> (default).
|
94
94
|
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to 200.
|
95
95
|
#
|
96
96
|
# Generic data download:
|
@@ -105,8 +105,8 @@ module ActionController #:nodoc:
|
|
105
105
|
#
|
106
106
|
# send_data image.data, type: image.content_type, disposition: 'inline'
|
107
107
|
#
|
108
|
-
# See +send_file+ for more information on HTTP Content
|
109
|
-
def send_data(data, options = {})
|
108
|
+
# See +send_file+ for more information on HTTP <tt>Content-*</tt> headers and caching.
|
109
|
+
def send_data(data, options = {}) # :doc:
|
110
110
|
send_file_headers! options
|
111
111
|
render options.slice(:status, :content_type).merge(body: data)
|
112
112
|
end
|
@@ -138,14 +138,6 @@ module ActionController #:nodoc:
|
|
138
138
|
end
|
139
139
|
|
140
140
|
headers["Content-Transfer-Encoding"] = "binary"
|
141
|
-
|
142
|
-
# Fix a problem with IE 6.0 on opening downloaded files:
|
143
|
-
# If Cache-Control: no-cache is set (which Rails does by default),
|
144
|
-
# IE removes the file it just downloaded from its cache immediately
|
145
|
-
# after it displays the "open/save" dialog, which means that if you
|
146
|
-
# hit "open" the file isn't there anymore when the application that
|
147
|
-
# is called for handling the download is run, so let's workaround that
|
148
|
-
response.cache_control[:public] ||= false
|
149
141
|
end
|
150
142
|
end
|
151
143
|
end
|