actionpack 5.2.4.4 → 6.1.1

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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +264 -322
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/abstract_controller.rb +1 -0
  6. data/lib/abstract_controller/base.rb +38 -4
  7. data/lib/abstract_controller/caching.rb +1 -1
  8. data/lib/abstract_controller/caching/fragments.rb +6 -22
  9. data/lib/abstract_controller/callbacks.rb +14 -2
  10. data/lib/abstract_controller/collector.rb +1 -2
  11. data/lib/abstract_controller/helpers.rb +106 -90
  12. data/lib/abstract_controller/railties/routes_helpers.rb +1 -1
  13. data/lib/abstract_controller/rendering.rb +9 -9
  14. data/lib/abstract_controller/translation.rb +11 -5
  15. data/lib/action_controller.rb +7 -4
  16. data/lib/action_controller/api.rb +4 -3
  17. data/lib/action_controller/base.rb +6 -9
  18. data/lib/action_controller/caching.rb +1 -3
  19. data/lib/action_controller/log_subscriber.rb +10 -7
  20. data/lib/action_controller/metal.rb +10 -8
  21. data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
  22. data/lib/action_controller/metal/conditional_get.rb +19 -5
  23. data/lib/action_controller/metal/content_security_policy.rb +1 -2
  24. data/lib/action_controller/metal/cookies.rb +3 -1
  25. data/lib/action_controller/metal/data_streaming.rb +6 -7
  26. data/lib/action_controller/metal/default_headers.rb +17 -0
  27. data/lib/action_controller/metal/etag_with_template_digest.rb +3 -5
  28. data/lib/action_controller/metal/exceptions.rb +56 -2
  29. data/lib/action_controller/metal/flash.rb +5 -5
  30. data/lib/action_controller/metal/head.rb +7 -4
  31. data/lib/action_controller/metal/helpers.rb +14 -5
  32. data/lib/action_controller/metal/http_authentication.rb +24 -23
  33. data/lib/action_controller/metal/implicit_render.rb +5 -15
  34. data/lib/action_controller/metal/instrumentation.rb +13 -14
  35. data/lib/action_controller/metal/live.rb +30 -32
  36. data/lib/action_controller/metal/logging.rb +20 -0
  37. data/lib/action_controller/metal/mime_responds.rb +19 -4
  38. data/lib/action_controller/metal/parameter_encoding.rb +35 -4
  39. data/lib/action_controller/metal/params_wrapper.rb +31 -22
  40. data/lib/action_controller/metal/permissions_policy.rb +46 -0
  41. data/lib/action_controller/metal/redirecting.rb +6 -6
  42. data/lib/action_controller/metal/renderers.rb +4 -4
  43. data/lib/action_controller/metal/rendering.rb +8 -3
  44. data/lib/action_controller/metal/request_forgery_protection.rb +62 -34
  45. data/lib/action_controller/metal/rescue.rb +1 -1
  46. data/lib/action_controller/metal/streaming.rb +0 -1
  47. data/lib/action_controller/metal/strong_parameters.rb +167 -58
  48. data/lib/action_controller/metal/url_for.rb +1 -1
  49. data/lib/action_controller/railties/helpers.rb +1 -1
  50. data/lib/action_controller/renderer.rb +37 -13
  51. data/lib/action_controller/template_assertions.rb +1 -1
  52. data/lib/action_controller/test_case.rb +70 -65
  53. data/lib/action_dispatch.rb +9 -3
  54. data/lib/action_dispatch/http/cache.rb +26 -21
  55. data/lib/action_dispatch/http/content_disposition.rb +45 -0
  56. data/lib/action_dispatch/http/content_security_policy.rb +33 -19
  57. data/lib/action_dispatch/http/filter_parameters.rb +9 -8
  58. data/lib/action_dispatch/http/filter_redirect.rb +2 -3
  59. data/lib/action_dispatch/http/headers.rb +4 -4
  60. data/lib/action_dispatch/http/mime_negotiation.rb +26 -13
  61. data/lib/action_dispatch/http/mime_type.rb +42 -23
  62. data/lib/action_dispatch/http/parameters.rb +14 -23
  63. data/lib/action_dispatch/http/permissions_policy.rb +173 -0
  64. data/lib/action_dispatch/http/request.rb +45 -22
  65. data/lib/action_dispatch/http/response.rb +45 -25
  66. data/lib/action_dispatch/http/upload.rb +9 -1
  67. data/lib/action_dispatch/http/url.rb +82 -82
  68. data/lib/action_dispatch/journey.rb +0 -2
  69. data/lib/action_dispatch/journey/formatter.rb +54 -30
  70. data/lib/action_dispatch/journey/gtg/builder.rb +22 -37
  71. data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
  72. data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -5
  73. data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
  74. data/lib/action_dispatch/journey/nodes/node.rb +13 -11
  75. data/lib/action_dispatch/journey/parser.rb +13 -13
  76. data/lib/action_dispatch/journey/parser.y +1 -1
  77. data/lib/action_dispatch/journey/path/pattern.rb +19 -21
  78. data/lib/action_dispatch/journey/route.rb +10 -20
  79. data/lib/action_dispatch/journey/router.rb +26 -34
  80. data/lib/action_dispatch/journey/router/utils.rb +14 -12
  81. data/lib/action_dispatch/journey/routes.rb +0 -2
  82. data/lib/action_dispatch/journey/scanner.rb +10 -4
  83. data/lib/action_dispatch/journey/visitors.rb +1 -4
  84. data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
  85. data/lib/action_dispatch/middleware/callbacks.rb +2 -4
  86. data/lib/action_dispatch/middleware/cookies.rb +128 -109
  87. data/lib/action_dispatch/middleware/debug_exceptions.rb +43 -66
  88. data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
  89. data/lib/action_dispatch/middleware/debug_view.rb +66 -0
  90. data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -30
  91. data/lib/action_dispatch/middleware/flash.rb +1 -1
  92. data/lib/action_dispatch/middleware/host_authorization.rb +121 -0
  93. data/lib/action_dispatch/middleware/public_exceptions.rb +6 -3
  94. data/lib/action_dispatch/middleware/remote_ip.rb +14 -16
  95. data/lib/action_dispatch/middleware/request_id.rb +5 -6
  96. data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -3
  97. data/lib/action_dispatch/middleware/session/cookie_store.rb +3 -9
  98. data/lib/action_dispatch/middleware/show_exceptions.rb +3 -2
  99. data/lib/action_dispatch/middleware/ssl.rb +20 -15
  100. data/lib/action_dispatch/middleware/stack.rb +56 -2
  101. data/lib/action_dispatch/middleware/static.rb +153 -93
  102. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  103. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  104. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  105. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
  106. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  107. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
  108. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
  109. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
  110. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
  111. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +23 -4
  112. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
  113. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +6 -3
  114. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -1
  115. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +104 -8
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
  119. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
  122. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +24 -1
  123. data/lib/action_dispatch/railtie.rb +8 -2
  124. data/lib/action_dispatch/request/session.rb +10 -9
  125. data/lib/action_dispatch/request/utils.rb +26 -2
  126. data/lib/action_dispatch/routing.rb +21 -20
  127. data/lib/action_dispatch/routing/inspector.rb +100 -52
  128. data/lib/action_dispatch/routing/mapper.rb +155 -103
  129. data/lib/action_dispatch/routing/polymorphic_routes.rb +13 -15
  130. data/lib/action_dispatch/routing/redirection.rb +3 -3
  131. data/lib/action_dispatch/routing/route_set.rb +71 -69
  132. data/lib/action_dispatch/routing/url_for.rb +2 -2
  133. data/lib/action_dispatch/system_test_case.rb +54 -11
  134. data/lib/action_dispatch/system_testing/browser.rb +53 -16
  135. data/lib/action_dispatch/system_testing/driver.rb +11 -3
  136. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +49 -7
  137. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +8 -10
  138. data/lib/action_dispatch/testing/assertion_response.rb +0 -1
  139. data/lib/action_dispatch/testing/assertions.rb +1 -1
  140. data/lib/action_dispatch/testing/assertions/response.rb +4 -7
  141. data/lib/action_dispatch/testing/assertions/routing.rb +20 -8
  142. data/lib/action_dispatch/testing/integration.rb +61 -28
  143. data/lib/action_dispatch/testing/request_encoder.rb +2 -2
  144. data/lib/action_dispatch/testing/test_process.rb +29 -4
  145. data/lib/action_dispatch/testing/test_request.rb +3 -3
  146. data/lib/action_dispatch/testing/test_response.rb +4 -32
  147. data/lib/action_pack.rb +1 -1
  148. data/lib/action_pack/gem_version.rb +4 -4
  149. metadata +38 -26
  150. data/lib/action_controller/metal/force_ssl.rb +0 -99
  151. data/lib/action_dispatch/http/parameter_filter.rb +0 -86
  152. data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
  153. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -49
  154. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -120
  155. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -7,7 +7,7 @@ module AbstractController
7
7
  Module.new do
8
8
  define_method(:inherited) do |klass|
9
9
  super(klass)
10
- if namespace = klass.parents.detect { |m| m.respond_to?(:railtie_routes_url_helpers) }
10
+ if namespace = klass.module_parents.detect { |m| m.respond_to?(:railtie_routes_url_helpers) }
11
11
  klass.include(namespace.railtie_routes_url_helpers(include_path_helpers))
12
12
  else
13
13
  klass.include(routes.url_helpers(include_path_helpers))
@@ -28,6 +28,7 @@ module AbstractController
28
28
  else
29
29
  _set_rendered_content_type rendered_format
30
30
  end
31
+ _set_vary_header
31
32
  self.response_body = rendered_body
32
33
  end
33
34
 
@@ -55,20 +56,16 @@ module AbstractController
55
56
  Mime[:text]
56
57
  end
57
58
 
58
- DEFAULT_PROTECTED_INSTANCE_VARIABLES = Set.new %i(
59
- @_action_name @_response_body @_formats @_prefixes
60
- )
59
+ DEFAULT_PROTECTED_INSTANCE_VARIABLES = %i(@_action_name @_response_body @_formats @_prefixes)
61
60
 
62
61
  # This method should return a hash with assigns.
63
62
  # You can overwrite this configuration per controller.
64
63
  def view_assigns
65
- protected_vars = _protected_ivars
66
- variables = instance_variables
64
+ variables = instance_variables - _protected_ivars
67
65
 
68
- variables.reject! { |s| protected_vars.include? s }
69
- variables.each_with_object({}) { |name, hash|
66
+ variables.each_with_object({}) do |name, hash|
70
67
  hash[name.slice(1, name.length)] = instance_variable_get(name)
71
- }
68
+ end
72
69
  end
73
70
 
74
71
  private
@@ -109,6 +106,9 @@ module AbstractController
109
106
  def _set_html_content_type # :nodoc:
110
107
  end
111
108
 
109
+ def _set_vary_header # :nodoc:
110
+ end
111
+
112
112
  def _set_rendered_content_type(format) # :nodoc:
113
113
  end
114
114
 
@@ -120,7 +120,7 @@ module AbstractController
120
120
  options
121
121
  end
122
122
 
123
- def _protected_ivars # :nodoc:
123
+ def _protected_ivars
124
124
  DEFAULT_PROTECTED_INSTANCE_VARIABLES
125
125
  end
126
126
  end
@@ -1,7 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/symbol/starts_ends_with"
4
+
3
5
  module AbstractController
4
6
  module Translation
7
+ mattr_accessor :raise_on_missing_translations, default: false
8
+
5
9
  # Delegates to <tt>I18n.translate</tt>. Also aliased as <tt>t</tt>.
6
10
  #
7
11
  # When the given key starts with a period, it will be scoped by the current
@@ -10,21 +14,23 @@ module AbstractController
10
14
  # <tt>I18n.translate("people.index.foo")</tt>. This makes it less repetitive
11
15
  # to translate many keys within the same controller / action and gives you a
12
16
  # simple framework for scoping them consistently.
13
- def translate(key, options = {})
14
- if key.to_s.first == "."
17
+ def translate(key, **options)
18
+ if key&.start_with?(".")
15
19
  path = controller_path.tr("/", ".")
16
20
  defaults = [:"#{path}#{key}"]
17
21
  defaults << options[:default] if options[:default]
18
22
  options[:default] = defaults.flatten
19
23
  key = "#{path}.#{action_name}#{key}"
20
24
  end
21
- I18n.translate(key, options)
25
+
26
+ i18n_raise = options.fetch(:raise, self.raise_on_missing_translations)
27
+ I18n.translate(key, **options, raise: i18n_raise)
22
28
  end
23
29
  alias :t :translate
24
30
 
25
31
  # Delegates to <tt>I18n.localize</tt>. Also aliased as <tt>l</tt>.
26
- def localize(*args)
27
- I18n.localize(*args)
32
+ def localize(object, **options)
33
+ I18n.localize(object, **options)
28
34
  end
29
35
  alias :l :localize
30
36
  end
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/rails"
4
3
  require "abstract_controller"
5
4
  require "action_dispatch"
6
- require "action_controller/metal/live"
7
5
  require "action_controller/metal/strong_parameters"
8
6
 
9
7
  module ActionController
@@ -12,7 +10,6 @@ module ActionController
12
10
  autoload :API
13
11
  autoload :Base
14
12
  autoload :Metal
15
- autoload :Middleware
16
13
  autoload :Renderer
17
14
  autoload :FormBuilder
18
15
 
@@ -21,20 +18,26 @@ module ActionController
21
18
  end
22
19
 
23
20
  autoload_under "metal" do
21
+ eager_autoload do
22
+ autoload :Live
23
+ end
24
+
24
25
  autoload :ConditionalGet
25
26
  autoload :ContentSecurityPolicy
26
27
  autoload :Cookies
27
28
  autoload :DataStreaming
29
+ autoload :DefaultHeaders
28
30
  autoload :EtagWithTemplateDigest
29
31
  autoload :EtagWithFlash
32
+ autoload :PermissionsPolicy
30
33
  autoload :Flash
31
- autoload :ForceSSL
32
34
  autoload :Head
33
35
  autoload :Helpers
34
36
  autoload :HttpAuthentication
35
37
  autoload :BasicImplicitRender
36
38
  autoload :ImplicitRender
37
39
  autoload :Instrumentation
40
+ autoload :Logging
38
41
  autoload :MimeResponds
39
42
  autoload :ParamsWrapper
40
43
  autoload :Redirecting
@@ -12,7 +12,7 @@ module ActionController
12
12
  #
13
13
  # An API Controller is different from a normal controller in the sense that
14
14
  # by default it doesn't include a number of features that are usually required
15
- # by browser access only: layouts and templates rendering, cookies, sessions,
15
+ # by browser access only: layouts and templates rendering,
16
16
  # flash, assets, and so on. This makes the entire controller stack thinner,
17
17
  # suitable for API applications. It doesn't mean you won't have such
18
18
  # features if you need them: they're all available for you to include in
@@ -93,7 +93,7 @@ module ActionController
93
93
  # the ones passed as arguments:
94
94
  #
95
95
  # class MyAPIBaseController < ActionController::Metal
96
- # ActionController::API.without_modules(:ForceSSL, :UrlFor).each do |left|
96
+ # ActionController::API.without_modules(:UrlFor).each do |left|
97
97
  # include left
98
98
  # end
99
99
  # end
@@ -120,8 +120,9 @@ module ActionController
120
120
  BasicImplicitRender,
121
121
  StrongParameters,
122
122
 
123
- ForceSSL,
124
123
  DataStreaming,
124
+ DefaultHeaders,
125
+ Logging,
125
126
 
126
127
  # Before callbacks should also be executed as early as possible, so
127
128
  # also include them at the bottom.
@@ -78,7 +78,7 @@ module ActionController
78
78
  #
79
79
  # You can retrieve it again through the same hash:
80
80
  #
81
- # Hello #{session[:person]}
81
+ # "Hello #{session[:person]}"
82
82
  #
83
83
  # For removing objects from the session, you can either assign a single key to +nil+:
84
84
  #
@@ -226,12 +226,14 @@ module ActionController
226
226
  FormBuilder,
227
227
  RequestForgeryProtection,
228
228
  ContentSecurityPolicy,
229
- ForceSSL,
229
+ PermissionsPolicy,
230
230
  Streaming,
231
231
  DataStreaming,
232
232
  HttpAuthentication::Basic::ControllerMethods,
233
233
  HttpAuthentication::Digest::ControllerMethods,
234
234
  HttpAuthentication::Token::ControllerMethods,
235
+ DefaultHeaders,
236
+ Logging,
235
237
 
236
238
  # Before callbacks should also be executed as early as possible, so
237
239
  # also include them at the bottom.
@@ -260,15 +262,10 @@ module ActionController
260
262
  @_view_renderer @_lookup_context @_routes @_view_runtime @_db_runtime @_helper_proxy
261
263
  )
262
264
 
263
- def _protected_ivars # :nodoc:
265
+ def _protected_ivars
264
266
  PROTECTED_IVARS
265
267
  end
266
-
267
- def self.make_response!(request)
268
- ActionDispatch::Response.create.tap do |res|
269
- res.request = request
270
- end
271
- end
268
+ private :_protected_ivars
272
269
 
273
270
  ActiveSupport.run_load_hooks(:action_controller_base, self)
274
271
  ActiveSupport.run_load_hooks(:action_controller, self)
@@ -22,7 +22,6 @@ module ActionController
22
22
  # config.action_controller.cache_store = :mem_cache_store, Memcached::Rails.new('localhost:11211')
23
23
  # config.action_controller.cache_store = MyOwnStore.new('parameter')
24
24
  module Caching
25
- extend ActiveSupport::Autoload
26
25
  extend ActiveSupport::Concern
27
26
 
28
27
  included do
@@ -30,7 +29,6 @@ module ActionController
30
29
  end
31
30
 
32
31
  private
33
-
34
32
  def instrument_payload(key)
35
33
  {
36
34
  controller: controller_name,
@@ -40,7 +38,7 @@ module ActionController
40
38
  end
41
39
 
42
40
  def instrument_name
43
- "action_controller".freeze
41
+ "action_controller"
44
42
  end
45
43
  end
46
44
  end
@@ -11,6 +11,7 @@ module ActionController
11
11
  params = payload[:params].except(*INTERNAL_PARAMS)
12
12
  format = payload[:format]
13
13
  format = format.to_s.upcase if format.is_a?(Symbol)
14
+ format = "*/*" if format.nil?
14
15
 
15
16
  info "Processing by #{payload[:controller]}##{payload[:action]} as #{format}"
16
17
  info " Parameters: #{params.inspect}" unless params.empty?
@@ -18,16 +19,18 @@ module ActionController
18
19
 
19
20
  def process_action(event)
20
21
  info do
21
- payload = event.payload
22
+ payload = event.payload
22
23
  additions = ActionController::Base.log_process_action(payload)
23
-
24
24
  status = payload[:status]
25
- if status.nil? && payload[:exception].present?
26
- exception_class_name = payload[:exception].first
25
+
26
+ if status.nil? && (exception_class_name = payload[:exception].first)
27
27
  status = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name)
28
28
  end
29
- message = "Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in #{event.duration.round}ms".dup
30
- message << " (#{additions.join(" | ".freeze)})" unless additions.empty?
29
+
30
+ additions << "Allocations: #{event.allocations}"
31
+
32
+ message = +"Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in #{event.duration.round}ms"
33
+ message << " (#{additions.join(" | ")})"
31
34
  message << "\n\n" if defined?(Rails.env) && Rails.env.development?
32
35
 
33
36
  message
@@ -53,7 +56,7 @@ module ActionController
53
56
  def unpermitted_parameters(event)
54
57
  debug do
55
58
  unpermitted_keys = event.payload[:keys]
56
- "Unpermitted parameter#{'s' if unpermitted_keys.size > 1}: #{unpermitted_keys.map { |e| ":#{e}" }.join(", ")}"
59
+ color("Unpermitted parameter#{'s' if unpermitted_keys.size > 1}: #{unpermitted_keys.map { |e| ":#{e}" }.join(", ")}", RED)
57
60
  end
58
61
  end
59
62
 
@@ -35,7 +35,6 @@ module ActionController
35
35
  end
36
36
 
37
37
  private
38
-
39
38
  INCLUDE = ->(list, action) { list.include? action }
40
39
  EXCLUDE = ->(list, action) { !list.include? action }
41
40
  NULL = ->(list, action) { true }
@@ -127,7 +126,7 @@ module ActionController
127
126
  # ==== Returns
128
127
  # * <tt>string</tt>
129
128
  def self.controller_name
130
- @controller_name ||= name.demodulize.sub(/Controller$/, "").underscore
129
+ @controller_name ||= (name.demodulize.delete_suffix("Controller").underscore unless anonymous?)
131
130
  end
132
131
 
133
132
  def self.make_response!(request)
@@ -136,7 +135,7 @@ module ActionController
136
135
  end
137
136
  end
138
137
 
139
- def self.binary_params_for?(action) # :nodoc:
138
+ def self.action_encoding_template(action) # :nodoc:
140
139
  false
141
140
  end
142
141
 
@@ -148,7 +147,7 @@ module ActionController
148
147
  attr_internal :response, :request
149
148
  delegate :session, to: "@_request"
150
149
  delegate :headers, :status=, :location=, :content_type=,
151
- :status, :location, :content_type, to: "@_response"
150
+ :status, :location, :content_type, :media_type, to: "@_response"
152
151
 
153
152
  def initialize
154
153
  @_request = nil
@@ -217,10 +216,13 @@ module ActionController
217
216
  super
218
217
  end
219
218
 
220
- # Pushes the given Rack middleware and its arguments to the bottom of the
221
- # middleware stack.
222
- def self.use(*args, &block)
223
- middleware_stack.use(*args, &block)
219
+ class << self
220
+ # Pushes the given Rack middleware and its arguments to the bottom of the
221
+ # middleware stack.
222
+ def use(*args, &block)
223
+ middleware_stack.use(*args, &block)
224
+ end
225
+ ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true)
224
226
  end
225
227
 
226
228
  # Alias for +middleware_stack+.
@@ -6,7 +6,7 @@ module ActionController
6
6
  super.tap { default_render unless performed? }
7
7
  end
8
8
 
9
- def default_render(*args)
9
+ def default_render
10
10
  head :no_content
11
11
  end
12
12
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/hash/keys"
3
+ require "active_support/core_ext/object/try"
4
+ require "active_support/core_ext/integer/time"
4
5
 
5
6
  module ActionController
6
7
  module ConditionalGet
@@ -19,12 +20,12 @@ module ActionController
19
20
  # of cached pages.
20
21
  #
21
22
  # class InvoicesController < ApplicationController
22
- # etag { current_user.try :id }
23
+ # etag { current_user&.id }
23
24
  #
24
25
  # def show
25
26
  # # Etag will differ even for the same invoice when it's viewed by a different current_user
26
27
  # @invoice = Invoice.find(params[:id])
27
- # fresh_when(@invoice)
28
+ # fresh_when etag: @invoice
28
29
  # end
29
30
  # end
30
31
  def etag(&etagger)
@@ -181,7 +182,7 @@ module ActionController
181
182
  #
182
183
  # You can also pass an object that responds to +maximum+, such as a
183
184
  # collection of active records. In this case +last_modified+ will be set by
184
- # calling +maximum(:updated_at)+ on the collection (the timestamp of the
185
+ # calling <tt>maximum(:updated_at)</tt> on the collection (the timestamp of the
185
186
  # most recently updated record) and the +etag+ by passing the object itself.
186
187
  #
187
188
  # def index
@@ -230,12 +231,25 @@ module ActionController
230
231
  # This method will overwrite an existing Cache-Control header.
231
232
  # See https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html for more possibilities.
232
233
  #
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.
236
+ #
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
239
+ #
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:
242
+ #
243
+ # expires_in 3.hours, public: true, "s-maxage": 3.hours, "no-transform": true
244
+ #
233
245
  # The method will also ensure an HTTP Date header for client compatibility.
234
246
  def expires_in(seconds, options = {})
235
247
  response.cache_control.merge!(
236
248
  max_age: seconds,
237
249
  public: options.delete(:public),
238
- must_revalidate: options.delete(:must_revalidate)
250
+ must_revalidate: options.delete(:must_revalidate),
251
+ stale_while_revalidate: options.delete(:stale_while_revalidate),
252
+ stale_if_error: options.delete(:stale_if_error),
239
253
  )
240
254
  options.delete(:private)
241
255
 
@@ -36,7 +36,6 @@ module ActionController #:nodoc:
36
36
  end
37
37
 
38
38
  private
39
-
40
39
  def content_security_policy?
41
40
  request.content_security_policy
42
41
  end
@@ -46,7 +45,7 @@ module ActionController #:nodoc:
46
45
  end
47
46
 
48
47
  def current_content_security_policy
49
- request.content_security_policy.try(:clone) || ActionDispatch::ContentSecurityPolicy.new
48
+ request.content_security_policy&.clone || ActionDispatch::ContentSecurityPolicy.new
50
49
  end
51
50
  end
52
51
  end
@@ -9,7 +9,9 @@ module ActionController #:nodoc:
9
9
  end
10
10
 
11
11
  private
12
- def cookies
12
+ # The cookies for the current request. See ActionDispatch::Cookies for
13
+ # more information.
14
+ def cookies # :doc:
13
15
  request.cookie_jar
14
16
  end
15
17
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "action_controller/metal/exceptions"
4
+ require "action_dispatch/http/content_disposition"
4
5
 
5
6
  module ActionController #:nodoc:
6
7
  # Methods for sending arbitrary data and for streaming files to the browser,
@@ -10,8 +11,8 @@ module ActionController #:nodoc:
10
11
 
11
12
  include ActionController::Rendering
12
13
 
13
- DEFAULT_SEND_FILE_TYPE = "application/octet-stream".freeze #:nodoc:
14
- DEFAULT_SEND_FILE_DISPOSITION = "attachment".freeze #:nodoc:
14
+ DEFAULT_SEND_FILE_TYPE = "application/octet-stream" #:nodoc:
15
+ DEFAULT_SEND_FILE_DISPOSITION = "attachment" #:nodoc:
15
16
 
16
17
  private
17
18
  # Sends the file. This uses a server-appropriate method (such as X-Sendfile)
@@ -52,7 +53,7 @@ module ActionController #:nodoc:
52
53
  #
53
54
  # Show a 404 page in the browser:
54
55
  #
55
- # send_file '/path/to/404.html', type: 'text/html; charset=utf-8', status: 404
56
+ # send_file '/path/to/404.html', type: 'text/html; charset=utf-8', disposition: 'inline', status: 404
56
57
  #
57
58
  # Read about the other Content-* HTTP headers if you'd like to
58
59
  # provide the user with more information (such as Content-Description) in
@@ -132,10 +133,8 @@ module ActionController #:nodoc:
132
133
  end
133
134
 
134
135
  disposition = options.fetch(:disposition, DEFAULT_SEND_FILE_DISPOSITION)
135
- unless disposition.nil?
136
- disposition = disposition.to_s
137
- disposition += %(; filename="#{options[:filename]}") if options[:filename]
138
- headers["Content-Disposition"] = disposition
136
+ if disposition
137
+ headers["Content-Disposition"] = ActionDispatch::Http::ContentDisposition.format(disposition: disposition, filename: options[:filename])
139
138
  end
140
139
 
141
140
  headers["Content-Transfer-Encoding"] = "binary"