actionpack 6.1.7.5 → 7.0.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +323 -399
  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 +27 -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 +95 -22
  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