actionpack 6.1.7.5 → 7.1.3.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 +355 -435
- data/MIT-LICENSE +2 -1
- data/README.rdoc +6 -7
- data/lib/abstract_controller/asset_paths.rb +1 -1
- data/lib/abstract_controller/base.rb +33 -37
- data/lib/abstract_controller/caching/fragments.rb +4 -2
- data/lib/abstract_controller/caching.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +50 -11
- data/lib/abstract_controller/collector.rb +2 -2
- data/lib/abstract_controller/deprecator.rb +7 -0
- data/lib/abstract_controller/error.rb +1 -1
- data/lib/abstract_controller/helpers.rb +78 -30
- data/lib/abstract_controller/logger.rb +1 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +3 -16
- data/lib/abstract_controller/rendering.rb +12 -14
- data/lib/abstract_controller/translation.rb +26 -7
- data/lib/abstract_controller/url_for.rb +6 -6
- data/lib/abstract_controller.rb +6 -0
- data/lib/action_controller/api.rb +12 -10
- data/lib/action_controller/base.rb +8 -21
- data/lib/action_controller/caching.rb +2 -0
- data/lib/action_controller/deprecator.rb +7 -0
- data/lib/action_controller/form_builder.rb +4 -2
- data/lib/action_controller/log_subscriber.rb +20 -7
- 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 +37 -3
- data/lib/action_controller/metal/cookies.rb +1 -1
- data/lib/action_controller/metal/data_streaming.rb +25 -31
- data/lib/action_controller/metal/default_headers.rb +2 -0
- data/lib/action_controller/metal/etag_with_flash.rb +3 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +2 -0
- data/lib/action_controller/metal/exceptions.rb +27 -30
- data/lib/action_controller/metal/flash.rb +6 -2
- data/lib/action_controller/metal/head.rb +9 -7
- data/lib/action_controller/metal/helpers.rb +5 -16
- data/lib/action_controller/metal/http_authentication.rb +78 -42
- data/lib/action_controller/metal/implicit_render.rb +5 -3
- data/lib/action_controller/metal/instrumentation.rb +62 -50
- data/lib/action_controller/metal/live.rb +67 -2
- data/lib/action_controller/metal/mime_responds.rb +5 -5
- data/lib/action_controller/metal/params_wrapper.rb +24 -13
- data/lib/action_controller/metal/permissions_policy.rb +20 -29
- data/lib/action_controller/metal/redirecting.rb +96 -23
- data/lib/action_controller/metal/renderers.rb +14 -15
- data/lib/action_controller/metal/rendering.rb +121 -16
- data/lib/action_controller/metal/request_forgery_protection.rb +208 -68
- data/lib/action_controller/metal/rescue.rb +7 -4
- data/lib/action_controller/metal/streaming.rb +74 -36
- data/lib/action_controller/metal/strong_parameters.rb +254 -151
- data/lib/action_controller/metal/testing.rb +9 -2
- data/lib/action_controller/metal/url_for.rb +10 -5
- data/lib/action_controller/metal.rb +89 -34
- data/lib/action_controller/railtie.rb +66 -9
- data/lib/action_controller/renderer.rb +99 -85
- data/lib/action_controller/test_case.rb +42 -11
- data/lib/action_controller.rb +10 -6
- data/lib/action_dispatch/constants.rb +32 -0
- data/lib/action_dispatch/deprecator.rb +7 -0
- data/lib/action_dispatch/http/cache.rb +21 -16
- data/lib/action_dispatch/http/content_security_policy.rb +122 -44
- data/lib/action_dispatch/http/filter_parameters.rb +14 -23
- data/lib/action_dispatch/http/headers.rb +3 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +25 -15
- data/lib/action_dispatch/http/mime_type.rb +43 -22
- data/lib/action_dispatch/http/mime_types.rb +3 -1
- data/lib/action_dispatch/http/parameters.rb +6 -6
- data/lib/action_dispatch/http/permissions_policy.rb +57 -19
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +75 -51
- data/lib/action_dispatch/http/response.rb +81 -77
- data/lib/action_dispatch/http/upload.rb +15 -2
- data/lib/action_dispatch/http/url.rb +11 -19
- data/lib/action_dispatch/journey/formatter.rb +8 -2
- 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 +36 -27
- data/lib/action_dispatch/journey/route.rb +8 -14
- data/lib/action_dispatch/journey/router/utils.rb +2 -2
- data/lib/action_dispatch/journey/router.rb +10 -9
- data/lib/action_dispatch/journey/routes.rb +5 -5
- 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/log_subscriber.rb +23 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +5 -7
- data/lib/action_dispatch/middleware/assume_ssl.rb +24 -0
- data/lib/action_dispatch/middleware/callbacks.rb +2 -0
- data/lib/action_dispatch/middleware/cookies.rb +97 -107
- data/lib/action_dispatch/middleware/debug_exceptions.rb +31 -28
- data/lib/action_dispatch/middleware/debug_locks.rb +7 -4
- data/lib/action_dispatch/middleware/debug_view.rb +7 -2
- data/lib/action_dispatch/middleware/exception_wrapper.rb +190 -27
- data/lib/action_dispatch/middleware/executor.rb +3 -0
- data/lib/action_dispatch/middleware/flash.rb +24 -18
- data/lib/action_dispatch/middleware/host_authorization.rb +19 -20
- data/lib/action_dispatch/middleware/public_exceptions.rb +5 -3
- data/lib/action_dispatch/middleware/reloader.rb +7 -5
- data/lib/action_dispatch/middleware/remote_ip.rb +32 -19
- data/lib/action_dispatch/middleware/request_id.rb +5 -3
- data/lib/action_dispatch/middleware/server_timing.rb +76 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +6 -1
- data/lib/action_dispatch/middleware/session/cache_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +19 -13
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +3 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +30 -25
- data/lib/action_dispatch/middleware/ssl.rb +18 -6
- data/lib/action_dispatch/middleware/stack.rb +34 -11
- data/lib/action_dispatch/middleware/static.rb +16 -16
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +5 -5
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +4 -11
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
- 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 +9 -9
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +45 -18
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -15
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +6 -6
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +7 -7
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +64 -55
- data/lib/action_dispatch/railtie.rb +20 -4
- data/lib/action_dispatch/request/session.rb +59 -19
- data/lib/action_dispatch/request/utils.rb +8 -3
- data/lib/action_dispatch/routing/inspector.rb +55 -7
- data/lib/action_dispatch/routing/mapper.rb +117 -107
- data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -0
- data/lib/action_dispatch/routing/redirection.rb +20 -8
- data/lib/action_dispatch/routing/route_set.rb +67 -27
- data/lib/action_dispatch/routing/routes_proxy.rb +11 -16
- data/lib/action_dispatch/routing/url_for.rb +29 -26
- data/lib/action_dispatch/routing.rb +12 -13
- data/lib/action_dispatch/system_test_case.rb +8 -8
- data/lib/action_dispatch/system_testing/browser.rb +20 -29
- data/lib/action_dispatch/system_testing/driver.rb +34 -18
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +35 -20
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +0 -8
- data/lib/action_dispatch/testing/assertion_response.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +14 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +70 -30
- data/lib/action_dispatch/testing/assertions.rb +3 -4
- data/lib/action_dispatch/testing/integration.rb +33 -25
- data/lib/action_dispatch/testing/request_encoder.rb +4 -1
- data/lib/action_dispatch/testing/test_process.rb +5 -30
- data/lib/action_dispatch/testing/test_request.rb +1 -1
- data/lib/action_dispatch/testing/test_response.rb +34 -2
- data/lib/action_dispatch.rb +38 -4
- data/lib/action_pack/gem_version.rb +4 -4
- data/lib/action_pack/version.rb +1 -1
- data/lib/action_pack.rb +1 -1
- metadata +67 -30
@@ -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,11 +13,34 @@ 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?
|
20
42
|
policy = current_content_security_policy
|
21
|
-
|
43
|
+
instance_exec(policy, &block)
|
22
44
|
request.content_security_policy = policy
|
23
45
|
end
|
24
46
|
|
@@ -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,9 @@
|
|
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
|
+
# = Action Controller Data \Streaming
|
8
|
+
#
|
7
9
|
# Methods for sending arbitrary data and for streaming files to the browser,
|
8
10
|
# instead of rendering.
|
9
11
|
module DataStreaming
|
@@ -11,14 +13,14 @@ module ActionController #:nodoc:
|
|
11
13
|
|
12
14
|
include ActionController::Rendering
|
13
15
|
|
14
|
-
DEFAULT_SEND_FILE_TYPE = "application/octet-stream"
|
15
|
-
DEFAULT_SEND_FILE_DISPOSITION = "attachment"
|
16
|
+
DEFAULT_SEND_FILE_TYPE = "application/octet-stream" # :nodoc:
|
17
|
+
DEFAULT_SEND_FILE_DISPOSITION = "attachment" # :nodoc:
|
16
18
|
|
17
19
|
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
|
20
|
+
# Sends the file. This uses a server-appropriate method (such as +X-Sendfile+)
|
21
|
+
# via the +Rack::Sendfile+ middleware. The header to use is set via
|
20
22
|
# +config.action_dispatch.x_sendfile_header+.
|
21
|
-
# Your server can also configure this for you by setting the X-Sendfile-Type header.
|
23
|
+
# Your server can also configure this for you by setting the +X-Sendfile-Type+ header.
|
22
24
|
#
|
23
25
|
# Be careful to sanitize the path parameter if it is coming from a web
|
24
26
|
# page. <tt>send_file(params[:path])</tt> allows a malicious user to
|
@@ -28,17 +30,17 @@ module ActionController #:nodoc:
|
|
28
30
|
# * <tt>:filename</tt> - suggests a filename for the browser to use.
|
29
31
|
# Defaults to <tt>File.basename(path)</tt>.
|
30
32
|
# * <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
|
33
|
+
# You can specify either a string or a symbol for a registered type with <tt>Mime::Type.register</tt>, for example +:json+.
|
32
34
|
# 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
|
35
|
+
# If no content type is registered for the extension, the default type +application/octet-stream+ will be used.
|
34
36
|
# * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
|
35
|
-
# Valid values are
|
37
|
+
# Valid values are <tt>"inline"</tt> and <tt>"attachment"</tt> (default).
|
36
38
|
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to 200.
|
37
39
|
# * <tt>:url_based_filename</tt> - set to +true+ if you want the browser to guess the filename from
|
38
40
|
# the URL, which is necessary for i18n filenames on certain browsers
|
39
41
|
# (setting <tt>:filename</tt> overrides this option).
|
40
42
|
#
|
41
|
-
# The default Content-Type and Content-Disposition headers are
|
43
|
+
# The default +Content-Type+ and +Content-Disposition+ headers are
|
42
44
|
# set to download arbitrary binary files in as many browsers as
|
43
45
|
# possible. IE versions 4, 5, 5.5, and 6 are all known to have
|
44
46
|
# a variety of quirks (especially when downloading over SSL).
|
@@ -55,18 +57,18 @@ module ActionController #:nodoc:
|
|
55
57
|
#
|
56
58
|
# send_file '/path/to/404.html', type: 'text/html; charset=utf-8', disposition: 'inline', status: 404
|
57
59
|
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
# https://
|
60
|
+
# You can use other <tt>Content-*</tt> HTTP headers to provide additional
|
61
|
+
# information to the client. See MDN for a
|
62
|
+
# {list of HTTP headers}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers].
|
61
63
|
#
|
62
64
|
# 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
|
65
|
+
# The +Pragma+ and +Cache-Control+ headers declare how the file may be cached
|
64
66
|
# by intermediaries. They default to require clients to validate with
|
65
67
|
# the server before releasing cached responses. See
|
66
68
|
# 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 = {})
|
69
|
+
# {RFC 9111}[https://www.rfc-editor.org/rfc/rfc9111.html#name-cache-control]
|
70
|
+
# for the +Cache-Control+ header spec.
|
71
|
+
def send_file(path, options = {}) # :doc:
|
70
72
|
raise MissingFile, "Cannot read file #{path}" unless File.file?(path) && File.readable?(path)
|
71
73
|
|
72
74
|
options[:filename] ||= File.basename(path) unless options[:url_based_filename]
|
@@ -85,12 +87,12 @@ module ActionController #:nodoc:
|
|
85
87
|
#
|
86
88
|
# Options:
|
87
89
|
# * <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
|
90
|
+
# * <tt>:type</tt> - specifies an HTTP content type. Defaults to +application/octet-stream+.
|
91
|
+
# You can specify either a string or a symbol for a registered type with <tt>Mime::Type.register</tt>, for example +:json+.
|
90
92
|
# 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
|
93
|
+
# If no content type is registered for the extension, the default type +application/octet-stream+ will be used.
|
92
94
|
# * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
|
93
|
-
# Valid values are
|
95
|
+
# Valid values are <tt>"inline"</tt> and <tt>"attachment"</tt> (default).
|
94
96
|
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to 200.
|
95
97
|
#
|
96
98
|
# Generic data download:
|
@@ -105,8 +107,8 @@ module ActionController #:nodoc:
|
|
105
107
|
#
|
106
108
|
# send_data image.data, type: image.content_type, disposition: 'inline'
|
107
109
|
#
|
108
|
-
# See +send_file+ for more information on HTTP Content
|
109
|
-
def send_data(data, options = {})
|
110
|
+
# See +send_file+ for more information on HTTP <tt>Content-*</tt> headers and caching.
|
111
|
+
def send_data(data, options = {}) # :doc:
|
110
112
|
send_file_headers! options
|
111
113
|
render options.slice(:status, :content_type).merge(body: data)
|
112
114
|
end
|
@@ -138,14 +140,6 @@ module ActionController #:nodoc:
|
|
138
140
|
end
|
139
141
|
|
140
142
|
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
143
|
end
|
150
144
|
end
|
151
145
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionController
|
4
|
+
# = Action Controller Etag With \Flash
|
5
|
+
#
|
4
6
|
# When you're using the flash, it's generally used as a conditional on the view.
|
5
7
|
# This means the content of the view depends on the flash. Which in turn means
|
6
8
|
# that the ETag for a response should be computed with the content of the flash
|
@@ -12,7 +14,7 @@ module ActionController
|
|
12
14
|
include ActionController::ConditionalGet
|
13
15
|
|
14
16
|
included do
|
15
|
-
etag { flash
|
17
|
+
etag { flash if request.respond_to?(:flash) && !flash.empty? }
|
16
18
|
end
|
17
19
|
end
|
18
20
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionController
|
4
|
+
# = Action Controller Etag With Template \Digest
|
5
|
+
#
|
4
6
|
# When our views change, they should bubble up into HTTP cache freshness
|
5
7
|
# and bust browser caches. So the template digest for the current action
|
6
8
|
# is automatically included in the ETag.
|