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.

Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +320 -390
  3. data/MIT-LICENSE +1 -0
  4. data/README.rdoc +4 -5
  5. data/lib/abstract_controller/asset_paths.rb +1 -1
  6. data/lib/abstract_controller/base.rb +13 -26
  7. data/lib/abstract_controller/caching/fragments.rb +2 -2
  8. data/lib/abstract_controller/caching.rb +1 -1
  9. data/lib/abstract_controller/callbacks.rb +21 -7
  10. data/lib/abstract_controller/collector.rb +2 -2
  11. data/lib/abstract_controller/error.rb +1 -1
  12. data/lib/abstract_controller/helpers.rb +17 -12
  13. data/lib/abstract_controller/logger.rb +1 -1
  14. data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
  15. data/lib/abstract_controller/rendering.rb +9 -11
  16. data/lib/abstract_controller/translation.rb +5 -4
  17. data/lib/abstract_controller/url_for.rb +4 -6
  18. data/lib/action_controller/api.rb +7 -7
  19. data/lib/action_controller/base.rb +5 -4
  20. data/lib/action_controller/form_builder.rb +2 -2
  21. data/lib/action_controller/log_subscriber.rb +4 -3
  22. data/lib/action_controller/metal/basic_implicit_render.rb +3 -1
  23. data/lib/action_controller/metal/conditional_get.rb +137 -102
  24. data/lib/action_controller/metal/content_security_policy.rb +36 -2
  25. data/lib/action_controller/metal/cookies.rb +1 -1
  26. data/lib/action_controller/metal/data_streaming.rb +23 -31
  27. data/lib/action_controller/metal/etag_with_flash.rb +1 -1
  28. data/lib/action_controller/metal/exceptions.rb +19 -30
  29. data/lib/action_controller/metal/flash.rb +6 -2
  30. data/lib/action_controller/metal/head.rb +1 -1
  31. data/lib/action_controller/metal/helpers.rb +2 -2
  32. data/lib/action_controller/metal/http_authentication.rb +66 -39
  33. data/lib/action_controller/metal/instrumentation.rb +57 -52
  34. data/lib/action_controller/metal/live.rb +43 -2
  35. data/lib/action_controller/metal/mime_responds.rb +3 -3
  36. data/lib/action_controller/metal/params_wrapper.rb +20 -11
  37. data/lib/action_controller/metal/permissions_policy.rb +19 -28
  38. data/lib/action_controller/metal/redirecting.rb +111 -19
  39. data/lib/action_controller/metal/renderers.rb +12 -13
  40. data/lib/action_controller/metal/rendering.rb +121 -9
  41. data/lib/action_controller/metal/request_forgery_protection.rb +83 -32
  42. data/lib/action_controller/metal/rescue.rb +5 -4
  43. data/lib/action_controller/metal/streaming.rb +7 -9
  44. data/lib/action_controller/metal/strong_parameters.rb +138 -115
  45. data/lib/action_controller/metal/testing.rb +9 -2
  46. data/lib/action_controller/metal/url_for.rb +3 -5
  47. data/lib/action_controller/metal.rb +10 -13
  48. data/lib/action_controller/railtie.rb +50 -6
  49. data/lib/action_controller/renderer.rb +1 -20
  50. data/lib/action_controller/test_case.rb +28 -7
  51. data/lib/action_controller.rb +2 -5
  52. data/lib/action_dispatch/http/cache.rb +20 -13
  53. data/lib/action_dispatch/http/content_security_policy.rb +113 -36
  54. data/lib/action_dispatch/http/filter_parameters.rb +4 -19
  55. data/lib/action_dispatch/http/headers.rb +1 -1
  56. data/lib/action_dispatch/http/mime_negotiation.rb +15 -5
  57. data/lib/action_dispatch/http/mime_type.rb +9 -11
  58. data/lib/action_dispatch/http/parameters.rb +5 -5
  59. data/lib/action_dispatch/http/permissions_policy.rb +17 -1
  60. data/lib/action_dispatch/http/request.rb +27 -37
  61. data/lib/action_dispatch/http/response.rb +3 -20
  62. data/lib/action_dispatch/http/upload.rb +13 -2
  63. data/lib/action_dispatch/http/url.rb +11 -19
  64. data/lib/action_dispatch/journey/gtg/builder.rb +11 -12
  65. data/lib/action_dispatch/journey/gtg/simulator.rb +10 -4
  66. data/lib/action_dispatch/journey/gtg/transition_table.rb +77 -21
  67. data/lib/action_dispatch/journey/nodes/node.rb +70 -5
  68. data/lib/action_dispatch/journey/path/pattern.rb +22 -13
  69. data/lib/action_dispatch/journey/route.rb +6 -13
  70. data/lib/action_dispatch/journey/router/utils.rb +2 -2
  71. data/lib/action_dispatch/journey/router.rb +1 -1
  72. data/lib/action_dispatch/journey/routes.rb +3 -3
  73. data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
  74. data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
  75. data/lib/action_dispatch/middleware/actionable_exceptions.rb +0 -1
  76. data/lib/action_dispatch/middleware/cookies.rb +20 -13
  77. data/lib/action_dispatch/middleware/debug_exceptions.rb +6 -4
  78. data/lib/action_dispatch/middleware/debug_locks.rb +3 -3
  79. data/lib/action_dispatch/middleware/exception_wrapper.rb +4 -0
  80. data/lib/action_dispatch/middleware/executor.rb +3 -0
  81. data/lib/action_dispatch/middleware/flash.rb +17 -18
  82. data/lib/action_dispatch/middleware/host_authorization.rb +13 -17
  83. data/lib/action_dispatch/middleware/remote_ip.rb +20 -8
  84. data/lib/action_dispatch/middleware/request_id.rb +3 -3
  85. data/lib/action_dispatch/middleware/server_timing.rb +76 -0
  86. data/lib/action_dispatch/middleware/session/abstract_store.rb +1 -1
  87. data/lib/action_dispatch/middleware/session/cookie_store.rb +9 -9
  88. data/lib/action_dispatch/middleware/show_exceptions.rb +17 -16
  89. data/lib/action_dispatch/middleware/stack.rb +27 -9
  90. data/lib/action_dispatch/middleware/static.rb +5 -9
  91. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +1 -1
  92. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +4 -11
  93. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +2 -2
  94. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +10 -5
  95. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +7 -3
  96. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +4 -4
  97. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +3 -3
  98. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +28 -18
  99. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +3 -3
  100. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +3 -3
  101. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
  102. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +3 -3
  103. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +3 -3
  104. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +22 -22
  105. data/lib/action_dispatch/railtie.rb +8 -2
  106. data/lib/action_dispatch/request/session.rb +43 -13
  107. data/lib/action_dispatch/routing/inspector.rb +1 -1
  108. data/lib/action_dispatch/routing/mapper.rb +82 -83
  109. data/lib/action_dispatch/routing/redirection.rb +5 -2
  110. data/lib/action_dispatch/routing/route_set.rb +17 -7
  111. data/lib/action_dispatch/routing/routes_proxy.rb +1 -1
  112. data/lib/action_dispatch/routing/url_for.rb +24 -25
  113. data/lib/action_dispatch/routing.rb +5 -6
  114. data/lib/action_dispatch/system_test_case.rb +5 -5
  115. data/lib/action_dispatch/system_testing/browser.rb +3 -13
  116. data/lib/action_dispatch/system_testing/driver.rb +34 -10
  117. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +11 -7
  118. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +0 -8
  119. data/lib/action_dispatch/testing/assertions/response.rb +1 -1
  120. data/lib/action_dispatch/testing/assertions/routing.rb +3 -2
  121. data/lib/action_dispatch/testing/assertions.rb +2 -5
  122. data/lib/action_dispatch/testing/integration.rb +6 -8
  123. data/lib/action_dispatch/testing/test_process.rb +3 -29
  124. data/lib/action_dispatch/testing/test_response.rb +20 -2
  125. data/lib/action_dispatch.rb +1 -0
  126. data/lib/action_pack/gem_version.rb +5 -5
  127. data/lib/action_pack/version.rb +1 -1
  128. 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
- # === Parameters:
40
- #
41
- # * <tt>:etag</tt> Sets a "weak" ETag validator on the response. See the
42
- # +:weak_etag+ option.
43
- # * <tt>:weak_etag</tt> Sets a "weak" ETag validator on the response.
44
- # Requests that set If-None-Match header may return a 304 Not Modified
45
- # response if it matches the ETag exactly. A weak ETag indicates semantic
46
- # equivalence, not byte-for-byte equality, so they're good for caching
47
- # HTML pages in browser caches. They can't be used for responses that
48
- # must be byte-identical, like serving Range requests within a PDF file.
49
- # * <tt>:strong_etag</tt> Sets a "strong" ETag validator on the response.
50
- # Requests that set If-None-Match header may return a 304 Not Modified
51
- # response if it matches the ETag exactly. A strong ETag implies exact
52
- # equality: the response must match byte for byte. This is necessary for
53
- # doing Range requests within a large video or PDF file, for example, or
54
- # for compatibility with some CDNs that don't support weak ETags.
55
- # * <tt>:last_modified</tt> Sets a "weak" last-update validator on the
56
- # response. Subsequent requests that set If-Modified-Since may return a
57
- # 304 Not Modified response if last_modified <= If-Modified-Since.
58
- # * <tt>:public</tt> By default the Cache-Control header is private, set this to
59
- # +true+ if you want your application to be cacheable by other devices (proxy caches).
60
- # * <tt>:template</tt> By default, the template digest for the current
61
- # controller/action is included in ETags. If the action renders a
62
- # different template, you can include its digest instead. If the action
63
- # doesn't render a template at all, you can pass <tt>template: false</tt>
64
- # to skip any attempt to check for a template digest.
65
- #
66
- # === Example:
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 render the show template if the request isn't sending a matching ETag or
74
- # If-Modified-Since header and just a <tt>304 Not Modified</tt> response if there's a match.
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. In this case +last_modified+ will be set
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 active records. In this case +last_modified+ will be set by
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
- # When passing a record or a collection, you can still set the public header:
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
- # When rendering a different template than the default controller/action
102
- # style, you can indicate which digest to include in the ETag:
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: 'widgets/show' }
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 it against
125
- # the client request. If the request doesn't match the options provided, the
126
- # request is considered stale and should be generated from scratch. Otherwise,
127
- # it's fresh and we don't need to generate anything and a reply of <tt>304 Not Modified</tt> is sent.
128
- #
129
- # === Parameters:
130
- #
131
- # * <tt>:etag</tt> Sets a "weak" ETag validator on the response. See the
132
- # +:weak_etag+ option.
133
- # * <tt>:weak_etag</tt> Sets a "weak" ETag validator on the response.
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. In this case +last_modified+ will be set
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 active records. In this case +last_modified+ will be set by
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
- # When passing a record or a collection, you can still set the public header:
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 = @article.really_expensive_call
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
- # When rendering a different template than the default controller/action
213
- # style, you can indicate which digest to include in the ETag:
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? @article, template: 'widgets/show'
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 an HTTP 1.1 Cache-Control header. Defaults to issuing a +private+
225
- # instruction, so that intermediate caches must not cache the response.
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
- # expires_in 20.minutes
228
- # expires_in 3.hours, public: true
229
- # expires_in 3.hours, public: true, must_revalidate: true
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
- # This method will overwrite an existing Cache-Control header.
232
- # See https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.
254
+ # ==== Examples
233
255
  #
234
- # HTTP Cache-Control Extensions for Stale Content. See https://tools.ietf.org/html/rfc5861
235
- # It helps to cache an asset and serve it while is being revalidated and/or returning with an error.
256
+ # expires_in 10.minutes
257
+ # # => Cache-Control: max-age=600, private
236
258
  #
237
- # expires_in 3.hours, public: true, stale_while_revalidate: 60.seconds
238
- # expires_in 3.hours, public: true, stale_while_revalidate: 60.seconds, stale_if_error: 5.minutes
259
+ # expires_in 10.minutes, public: true
260
+ # # => Cache-Control: max-age=600, public
239
261
  #
240
- # HTTP Cache-Control Extensions other values: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
241
- # Any additional key-value pairs are concatenated onto the `Cache-Control` header in the response:
262
+ # expires_in 10.minutes, public: true, must_revalidate: true
263
+ # # => Cache-Control: max-age=600, public, must-revalidate
242
264
  #
243
- # expires_in 3.hours, public: true, "s-maxage": 3.hours, "no-transform": true
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 #:nodoc:
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
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module ActionController #:nodoc:
3
+ module ActionController # :nodoc:
4
4
  module Cookies
5
5
  extend ActiveSupport::Concern
6
6
 
@@ -3,7 +3,7 @@
3
3
  require "action_controller/metal/exceptions"
4
4
  require "action_dispatch/http/content_disposition"
5
5
 
6
- module ActionController #:nodoc:
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" #:nodoc:
15
- DEFAULT_SEND_FILE_DISPOSITION = "attachment" #:nodoc:
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 :json.
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 'application/octet-stream' will be used.
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 'inline' and 'attachment' (default).
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
- # Read about the other Content-* HTTP headers if you'd like to
59
- # provide the user with more information (such as Content-Description) in
60
- # https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11.
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.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
68
- # for the Cache-Control header spec.
69
- def send_file(path, options = {}) #:doc:
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 '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.
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 'application/octet-stream' will be used.
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 'inline' and 'attachment' (default).
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-* headers and caching.
109
- def send_data(data, options = {}) #:doc:
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
@@ -12,7 +12,7 @@ module ActionController
12
12
  include ActionController::ConditionalGet
13
13
 
14
14
  included do
15
- etag { flash unless flash.empty? }
15
+ etag { flash if request.respond_to?(:flash) && !flash.empty? }
16
16
  end
17
17
  end
18
18
  end