actionpack 6.1.7.3 → 7.0.8
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +320 -390
- 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 +5 -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 +111 -19
- 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
|