actionpack 7.0.8 → 7.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 (135) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +327 -371
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/lib/abstract_controller/base.rb +20 -11
  6. data/lib/abstract_controller/caching/fragments.rb +2 -0
  7. data/lib/abstract_controller/callbacks.rb +31 -6
  8. data/lib/abstract_controller/deprecator.rb +7 -0
  9. data/lib/abstract_controller/helpers.rb +61 -18
  10. data/lib/abstract_controller/railties/routes_helpers.rb +1 -16
  11. data/lib/abstract_controller/rendering.rb +3 -3
  12. data/lib/abstract_controller/translation.rb +1 -5
  13. data/lib/abstract_controller/url_for.rb +2 -0
  14. data/lib/abstract_controller.rb +6 -0
  15. data/lib/action_controller/api.rb +5 -3
  16. data/lib/action_controller/base.rb +3 -17
  17. data/lib/action_controller/caching.rb +2 -0
  18. data/lib/action_controller/deprecator.rb +7 -0
  19. data/lib/action_controller/form_builder.rb +2 -0
  20. data/lib/action_controller/log_subscriber.rb +16 -4
  21. data/lib/action_controller/metal/content_security_policy.rb +1 -1
  22. data/lib/action_controller/metal/data_streaming.rb +2 -0
  23. data/lib/action_controller/metal/default_headers.rb +2 -0
  24. data/lib/action_controller/metal/etag_with_flash.rb +2 -0
  25. data/lib/action_controller/metal/etag_with_template_digest.rb +2 -0
  26. data/lib/action_controller/metal/exceptions.rb +8 -0
  27. data/lib/action_controller/metal/head.rb +8 -6
  28. data/lib/action_controller/metal/helpers.rb +3 -14
  29. data/lib/action_controller/metal/http_authentication.rb +16 -7
  30. data/lib/action_controller/metal/implicit_render.rb +5 -3
  31. data/lib/action_controller/metal/instrumentation.rb +8 -1
  32. data/lib/action_controller/metal/live.rb +24 -0
  33. data/lib/action_controller/metal/mime_responds.rb +2 -2
  34. data/lib/action_controller/metal/params_wrapper.rb +3 -1
  35. data/lib/action_controller/metal/permissions_policy.rb +1 -1
  36. data/lib/action_controller/metal/redirecting.rb +6 -6
  37. data/lib/action_controller/metal/renderers.rb +2 -2
  38. data/lib/action_controller/metal/rendering.rb +0 -7
  39. data/lib/action_controller/metal/request_forgery_protection.rb +139 -50
  40. data/lib/action_controller/metal/rescue.rb +2 -0
  41. data/lib/action_controller/metal/streaming.rb +70 -30
  42. data/lib/action_controller/metal/strong_parameters.rb +126 -52
  43. data/lib/action_controller/metal/url_for.rb +7 -0
  44. data/lib/action_controller/metal.rb +79 -21
  45. data/lib/action_controller/railtie.rb +22 -9
  46. data/lib/action_controller/renderer.rb +98 -65
  47. data/lib/action_controller/test_case.rb +15 -5
  48. data/lib/action_controller.rb +8 -1
  49. data/lib/action_dispatch/constants.rb +32 -0
  50. data/lib/action_dispatch/deprecator.rb +7 -0
  51. data/lib/action_dispatch/http/cache.rb +1 -3
  52. data/lib/action_dispatch/http/content_security_policy.rb +9 -8
  53. data/lib/action_dispatch/http/filter_parameters.rb +11 -5
  54. data/lib/action_dispatch/http/headers.rb +2 -0
  55. data/lib/action_dispatch/http/mime_negotiation.rb +21 -21
  56. data/lib/action_dispatch/http/mime_type.rb +35 -12
  57. data/lib/action_dispatch/http/mime_types.rb +3 -1
  58. data/lib/action_dispatch/http/parameters.rb +1 -1
  59. data/lib/action_dispatch/http/permissions_policy.rb +39 -17
  60. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  61. data/lib/action_dispatch/http/request.rb +48 -14
  62. data/lib/action_dispatch/http/response.rb +78 -59
  63. data/lib/action_dispatch/http/upload.rb +2 -0
  64. data/lib/action_dispatch/journey/formatter.rb +8 -2
  65. data/lib/action_dispatch/journey/path/pattern.rb +14 -14
  66. data/lib/action_dispatch/journey/route.rb +3 -2
  67. data/lib/action_dispatch/journey/router.rb +9 -8
  68. data/lib/action_dispatch/journey/routes.rb +2 -2
  69. data/lib/action_dispatch/log_subscriber.rb +23 -0
  70. data/lib/action_dispatch/middleware/actionable_exceptions.rb +5 -6
  71. data/lib/action_dispatch/middleware/assume_ssl.rb +24 -0
  72. data/lib/action_dispatch/middleware/callbacks.rb +2 -0
  73. data/lib/action_dispatch/middleware/cookies.rb +81 -98
  74. data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -25
  75. data/lib/action_dispatch/middleware/debug_locks.rb +4 -1
  76. data/lib/action_dispatch/middleware/debug_view.rb +7 -2
  77. data/lib/action_dispatch/middleware/exception_wrapper.rb +181 -27
  78. data/lib/action_dispatch/middleware/executor.rb +1 -1
  79. data/lib/action_dispatch/middleware/flash.rb +7 -0
  80. data/lib/action_dispatch/middleware/host_authorization.rb +6 -3
  81. data/lib/action_dispatch/middleware/public_exceptions.rb +5 -3
  82. data/lib/action_dispatch/middleware/reloader.rb +7 -5
  83. data/lib/action_dispatch/middleware/remote_ip.rb +17 -16
  84. data/lib/action_dispatch/middleware/request_id.rb +2 -0
  85. data/lib/action_dispatch/middleware/server_timing.rb +4 -4
  86. data/lib/action_dispatch/middleware/session/abstract_store.rb +5 -0
  87. data/lib/action_dispatch/middleware/session/cache_store.rb +2 -0
  88. data/lib/action_dispatch/middleware/session/cookie_store.rb +11 -5
  89. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +3 -1
  90. data/lib/action_dispatch/middleware/show_exceptions.rb +19 -15
  91. data/lib/action_dispatch/middleware/ssl.rb +18 -6
  92. data/lib/action_dispatch/middleware/stack.rb +7 -2
  93. data/lib/action_dispatch/middleware/static.rb +12 -8
  94. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
  95. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +4 -4
  96. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
  97. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +7 -7
  98. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
  99. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +17 -0
  100. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +16 -12
  101. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -1
  102. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
  103. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +4 -4
  104. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
  105. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
  106. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
  107. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +46 -37
  108. data/lib/action_dispatch/railtie.rb +14 -4
  109. data/lib/action_dispatch/request/session.rb +16 -6
  110. data/lib/action_dispatch/request/utils.rb +8 -3
  111. data/lib/action_dispatch/routing/inspector.rb +54 -6
  112. data/lib/action_dispatch/routing/mapper.rb +26 -14
  113. data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -0
  114. data/lib/action_dispatch/routing/redirection.rb +15 -6
  115. data/lib/action_dispatch/routing/route_set.rb +52 -22
  116. data/lib/action_dispatch/routing/routes_proxy.rb +1 -1
  117. data/lib/action_dispatch/routing/url_for.rb +5 -1
  118. data/lib/action_dispatch/routing.rb +4 -4
  119. data/lib/action_dispatch/system_test_case.rb +3 -3
  120. data/lib/action_dispatch/system_testing/browser.rb +5 -6
  121. data/lib/action_dispatch/system_testing/driver.rb +13 -21
  122. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +27 -16
  123. data/lib/action_dispatch/testing/assertions/response.rb +13 -6
  124. data/lib/action_dispatch/testing/assertions/routing.rb +67 -28
  125. data/lib/action_dispatch/testing/assertions.rb +3 -1
  126. data/lib/action_dispatch/testing/integration.rb +27 -17
  127. data/lib/action_dispatch/testing/request_encoder.rb +4 -1
  128. data/lib/action_dispatch/testing/test_process.rb +4 -3
  129. data/lib/action_dispatch/testing/test_request.rb +1 -1
  130. data/lib/action_dispatch/testing/test_response.rb +23 -9
  131. data/lib/action_dispatch.rb +37 -4
  132. data/lib/action_pack/gem_version.rb +3 -3
  133. data/lib/action_pack/version.rb +1 -1
  134. data/lib/action_pack.rb +1 -1
  135. metadata +49 -27
@@ -14,8 +14,13 @@ module ActionController
14
14
  config.action_controller.log_query_tags_around_actions = true
15
15
  config.action_controller.wrap_parameters_by_default = false
16
16
 
17
+ config.eager_load_namespaces << AbstractController
17
18
  config.eager_load_namespaces << ActionController
18
19
 
20
+ initializer "action_controller.deprecator", before: :load_environment_config do |app|
21
+ app.deprecators[:action_controller] = ActionController.deprecator
22
+ end
23
+
19
24
  initializer "action_controller.assets_config", group: :all do |app|
20
25
  app.config.action_controller.assets_dir ||= app.config.paths["public"].first
21
26
  end
@@ -37,10 +42,15 @@ module ActionController
37
42
  action_on_unpermitted_parameters = options.action_on_unpermitted_parameters
38
43
 
39
44
  if action_on_unpermitted_parameters.nil?
40
- action_on_unpermitted_parameters = (Rails.env.test? || Rails.env.development?) ? :log : false
45
+ action_on_unpermitted_parameters = Rails.env.local? ? :log : false
41
46
  end
42
47
 
43
48
  ActionController::Parameters.action_on_unpermitted_parameters = action_on_unpermitted_parameters
49
+
50
+ unless options.allow_deprecated_parameters_hash_equality.nil?
51
+ ActionController::Parameters.allow_deprecated_parameters_hash_equality =
52
+ options.allow_deprecated_parameters_hash_equality
53
+ end
44
54
  end
45
55
  end
46
56
 
@@ -71,7 +81,8 @@ module ActionController
71
81
  :permit_all_parameters,
72
82
  :action_on_unpermitted_parameters,
73
83
  :always_permitted_parameters,
74
- :wrap_parameters_by_default
84
+ :wrap_parameters_by_default,
85
+ :allow_deprecated_parameters_hash_equality
75
86
  )
76
87
 
77
88
  filtered_options.each do |k, v|
@@ -99,12 +110,6 @@ module ActionController
99
110
  end
100
111
  end
101
112
 
102
- initializer "action_controller.eager_load_actions" do
103
- ActiveSupport.on_load(:after_initialize) do
104
- ActionController::Metal.descendants.each(&:action_methods) if config.eager_load
105
- end
106
- end
107
-
108
113
  initializer "action_controller.query_log_tags" do |app|
109
114
  query_logs_tags_enabled = app.config.respond_to?(:active_record) &&
110
115
  app.config.active_record.query_log_tags_enabled &&
@@ -118,7 +123,15 @@ module ActionController
118
123
  ActiveRecord::QueryLogs.taggings.merge!(
119
124
  controller: ->(context) { context[:controller]&.controller_name },
120
125
  action: ->(context) { context[:controller]&.action_name },
121
- namespaced_controller: ->(context) { context[:controller].class.name if context[:controller] }
126
+ namespaced_controller: ->(context) {
127
+ if context[:controller]
128
+ controller_class = context[:controller].class
129
+ # based on ActionController::Metal#controller_name, but does not demodulize
130
+ unless controller_class.anonymous?
131
+ controller_class.name.delete_suffix("Controller").underscore
132
+ end
133
+ end
134
+ }
122
135
  )
123
136
  end
124
137
  end
@@ -1,78 +1,127 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionController
4
- # ActionController::Renderer allows you to render arbitrary templates
5
- # without requirement of being in controller actions.
4
+ # = Action Controller \Renderer
6
5
  #
7
- # You get a concrete renderer class by invoking ActionController::Base#renderer.
8
- # For example:
6
+ # ActionController::Renderer allows you to render arbitrary templates without
7
+ # being inside a controller action.
9
8
  #
10
- # ApplicationController.renderer
11
- #
12
- # It allows you to call method #render directly.
13
- #
14
- # ApplicationController.renderer.render template: '...'
15
- #
16
- # You can use this shortcut in a controller, instead of the previous example:
17
- #
18
- # ApplicationController.render template: '...'
9
+ # You can get a renderer instance by calling +renderer+ on a controller class:
19
10
  #
20
- # #render allows you to use the same options that you can use when rendering in a controller.
21
- # For example:
22
- #
23
- # FooController.render :action, locals: { ... }, assigns: { ... }
24
- #
25
- # The template will be rendered in a Rack environment which is accessible through
26
- # ActionController::Renderer#env. You can set it up in two ways:
11
+ # ApplicationController.renderer
12
+ # PostsController.renderer
27
13
  #
28
- # * by changing renderer defaults, like
14
+ # and render a template by calling the #render method:
29
15
  #
30
- # ApplicationController.renderer.defaults # => hash with default Rack environment
16
+ # ApplicationController.renderer.render template: "posts/show", assigns: { post: Post.first }
17
+ # PostsController.renderer.render :show, assigns: { post: Post.first }
31
18
  #
32
- # * by initializing an instance of renderer by passing it a custom environment.
19
+ # As a shortcut, you can also call +render+ directly on the controller class itself:
33
20
  #
34
- # ApplicationController.renderer.new(method: 'post', https: true)
21
+ # ApplicationController.render template: "posts/show", assigns: { post: Post.first }
22
+ # PostsController.render :show, assigns: { post: Post.first }
35
23
  #
36
24
  class Renderer
37
- attr_reader :defaults, :controller
25
+ attr_reader :controller
38
26
 
39
27
  DEFAULTS = {
40
- http_host: "example.org",
41
- https: false,
42
28
  method: "get",
43
- script_name: "",
44
29
  input: ""
45
30
  }.freeze
46
31
 
47
- # Create a new renderer instance for a specific controller class.
48
- def self.for(controller, env = {}, defaults = DEFAULTS.dup)
32
+ def self.normalize_env(env) # :nodoc:
33
+ new_env = {}
34
+
35
+ env.each_pair do |key, value|
36
+ case key
37
+ when :https
38
+ value = value ? "on" : "off"
39
+ when :method
40
+ value = -value.upcase
41
+ end
42
+
43
+ key = RACK_KEY_TRANSLATION[key] || key.to_s
44
+
45
+ new_env[key] = value
46
+ end
47
+
48
+ if new_env["HTTP_HOST"]
49
+ new_env["HTTPS"] ||= "off"
50
+ new_env["SCRIPT_NAME"] ||= ""
51
+ end
52
+
53
+ if new_env["HTTPS"]
54
+ new_env["rack.url_scheme"] = new_env["HTTPS"] == "on" ? "https" : "http"
55
+ end
56
+
57
+ new_env
58
+ end
59
+
60
+ # Creates a new renderer using the given controller class. See ::new.
61
+ def self.for(controller, env = nil, defaults = DEFAULTS)
49
62
  new(controller, env, defaults)
50
63
  end
51
64
 
52
- # Create a new renderer for the same controller but with a new env.
53
- def new(env = {})
54
- self.class.new controller, env, defaults
65
+ # Creates a new renderer using the same controller, but with a new Rack env.
66
+ #
67
+ # ApplicationController.renderer.new(method: "post")
68
+ #
69
+ def new(env = nil)
70
+ self.class.new controller, env, @defaults
55
71
  end
56
72
 
57
- # Create a new renderer for the same controller but with new defaults.
73
+ # Creates a new renderer using the same controller, but with the given
74
+ # defaults merged on top of the previous defaults.
58
75
  def with_defaults(defaults)
59
- self.class.new controller, @env, self.defaults.merge(defaults)
76
+ self.class.new controller, @env, @defaults.merge(defaults)
60
77
  end
61
78
 
62
- # Accepts a custom Rack environment to render templates in.
63
- # It will be merged with the default Rack environment defined by
64
- # +ActionController::Renderer::DEFAULTS+.
79
+ # Initializes a new Renderer.
80
+ #
81
+ # ==== Parameters
82
+ #
83
+ # * +controller+ - The controller class to instantiate for rendering.
84
+ # * +env+ - The Rack env to use for mocking a request when rendering.
85
+ # Entries can be typical Rack env keys and values, or they can be any of
86
+ # the following, which will be converted appropriately:
87
+ # * +:http_host+ - The HTTP host for the incoming request. Converts to
88
+ # Rack's +HTTP_HOST+.
89
+ # * +:https+ - Boolean indicating whether the incoming request uses HTTPS.
90
+ # Converts to Rack's +HTTPS+.
91
+ # * +:method+ - The HTTP method for the incoming request, case-insensitive.
92
+ # Converts to Rack's +REQUEST_METHOD+.
93
+ # * +:script_name+ - The portion of the incoming request's URL path that
94
+ # corresponds to the application. Converts to Rack's +SCRIPT_NAME+.
95
+ # * +:input+ - The input stream. Converts to Rack's +rack.input+.
96
+ # * +defaults+ - Default values for the Rack env. Entries are specified in
97
+ # the same format as +env+. +env+ will be merged on top of these values.
98
+ # +defaults+ will be retained when calling #new on a renderer instance.
99
+ #
100
+ # If no +http_host+ is specified, the env HTTP host will be derived from the
101
+ # routes' +default_url_options+. In this case, the +https+ boolean and the
102
+ # +script_name+ will also be derived from +default_url_options+ if they were
103
+ # not specified. Additionally, the +https+ boolean will fall back to
104
+ # +Rails.application.config.force_ssl+ if +default_url_options+ does not
105
+ # specify a +protocol+.
65
106
  def initialize(controller, env, defaults)
66
107
  @controller = controller
67
108
  @defaults = defaults
68
- @env = normalize_keys defaults, env
109
+ if env.blank? && @defaults == DEFAULTS
110
+ @env = DEFAULT_ENV
111
+ else
112
+ @env = normalize_env(@defaults)
113
+ @env.merge!(normalize_env(env)) unless env.blank?
114
+ end
115
+ end
116
+
117
+ def defaults
118
+ @defaults = @defaults.dup if @defaults.frozen?
119
+ @defaults
69
120
  end
70
121
 
71
122
  # Renders a template to a string, just like ActionController::Rendering#render_to_string.
72
123
  def render(*args)
73
- raise "missing controller" unless controller
74
-
75
- request = ActionDispatch::Request.new @env
124
+ request = ActionDispatch::Request.new(env_for_request)
76
125
  request.routes = controller._routes
77
126
 
78
127
  instance = controller.new
@@ -83,19 +132,6 @@ module ActionController
83
132
  alias_method :render_to_string, :render # :nodoc:
84
133
 
85
134
  private
86
- def normalize_keys(defaults, env)
87
- new_env = {}
88
- env.each_pair { |k, v| new_env[rack_key_for(k)] = rack_value_for(k, v) }
89
-
90
- defaults.each_pair do |k, v|
91
- key = rack_key_for(k)
92
- new_env[key] = rack_value_for(k, v) unless new_env.key?(key)
93
- end
94
-
95
- new_env["rack.url_scheme"] = new_env["HTTPS"] == "on" ? "https" : "http"
96
- new_env
97
- end
98
-
99
135
  RACK_KEY_TRANSLATION = {
100
136
  http_host: "HTTP_HOST",
101
137
  https: "HTTPS",
@@ -104,18 +140,15 @@ module ActionController
104
140
  input: "rack.input"
105
141
  }
106
142
 
107
- def rack_key_for(key)
108
- RACK_KEY_TRANSLATION[key] || key.to_s
109
- end
143
+ DEFAULT_ENV = normalize_env(DEFAULTS).freeze # :nodoc:
110
144
 
111
- def rack_value_for(key, value)
112
- case key
113
- when :https
114
- value ? "on" : "off"
115
- when :method
116
- -value.upcase
145
+ delegate :normalize_env, to: :class
146
+
147
+ def env_for_request
148
+ if @env.key?("HTTP_HOST") || controller._routes.nil?
149
+ @env.dup
117
150
  else
118
- value
151
+ controller._routes.default_env.merge(@env)
119
152
  end
120
153
  end
121
154
  end
@@ -127,6 +127,9 @@ module ActionController
127
127
  fetch_header("PATH_INFO") do |k|
128
128
  set_header k, generated_path
129
129
  end
130
+ fetch_header("ORIGINAL_FULLPATH") do |k|
131
+ set_header k, fullpath
132
+ end
130
133
  path_parameters[:controller] = controller_path
131
134
  path_parameters[:action] = action
132
135
 
@@ -182,11 +185,12 @@ module ActionController
182
185
  class TestSession < Rack::Session::Abstract::PersistedSecure::SecureSessionHash # :nodoc:
183
186
  DEFAULT_OPTIONS = Rack::Session::Abstract::Persisted::DEFAULT_OPTIONS
184
187
 
185
- def initialize(session = {})
188
+ def initialize(session = {}, id = Rack::Session::SessionId.new(SecureRandom.hex(16)))
186
189
  super(nil, nil)
187
- @id = Rack::Session::SessionId.new(SecureRandom.hex(16))
190
+ @id = id
188
191
  @data = stringify_keys(session)
189
192
  @loaded = true
193
+ @initially_empty = @data.empty?
190
194
  end
191
195
 
192
196
  def exists?
@@ -218,21 +222,27 @@ module ActionController
218
222
  true
219
223
  end
220
224
 
225
+ def id_was
226
+ @id
227
+ end
228
+
221
229
  private
222
230
  def load!
223
231
  @id
224
232
  end
225
233
  end
226
234
 
235
+ # = Action Controller Test Case
236
+ #
227
237
  # Superclass for ActionController functional tests. Functional tests allow you to
228
238
  # test a single controller action per test method.
229
239
  #
230
240
  # == Use integration style controller tests over functional style controller tests.
231
241
  #
232
- # Rails discourages the use of functional tests in favor of integration tests
242
+ # \Rails discourages the use of functional tests in favor of integration tests
233
243
  # (use ActionDispatch::IntegrationTest).
234
244
  #
235
- # New Rails applications no longer generate functional style controller tests and they should
245
+ # New \Rails applications no longer generate functional style controller tests and they should
236
246
  # only be used for backward compatibility. Integration style controller tests perform actual
237
247
  # requests, whereas functional style controller tests merely simulate a request. Besides,
238
248
  # integration tests are as fast as functional tests and provide lot of helpers such as +as+,
@@ -467,7 +477,7 @@ module ActionController
467
477
  #
468
478
  # It's not recommended to make more than one request in the same test. Instance
469
479
  # variables that are set in one request will not persist to the next request,
470
- # but it's not guaranteed that all Rails internal state will be reset. Prefer
480
+ # but it's not guaranteed that all \Rails internal state will be reset. Prefer
471
481
  # ActionDispatch::IntegrationTest for making multiple requests in the same test.
472
482
  #
473
483
  # Note that the request method is not verified.
@@ -2,9 +2,17 @@
2
2
 
3
3
  require "abstract_controller"
4
4
  require "action_dispatch"
5
+ require "action_controller/deprecator"
5
6
  require "action_controller/metal/strong_parameters"
6
7
  require "action_controller/metal/exceptions"
7
8
 
9
+ # = Action Controller
10
+ #
11
+ # Action Controller is a module of Action Pack.
12
+ #
13
+ # Action Controller provides a base controller class that can be subclassed to
14
+ # implement filters and actions to handle requests. The result of an action is
15
+ # typically content generated from views.
8
16
  module ActionController
9
17
  extend ActiveSupport::Autoload
10
18
 
@@ -60,7 +68,6 @@ end
60
68
 
61
69
  # Common Active Support usage in Action Controller
62
70
  require "active_support/core_ext/module/attribute_accessors"
63
- require "active_support/core_ext/load_error"
64
71
  require "active_support/core_ext/module/attr_internal"
65
72
  require "active_support/core_ext/name_error"
66
73
  require "active_support/inflector"
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rack/version"
4
+
5
+ module ActionDispatch
6
+ module Constants
7
+ # Response Header keys for Rack 2.x and 3.x
8
+ if Gem::Version.new(Rack::RELEASE) < Gem::Version.new("3")
9
+ VARY = "Vary"
10
+ CONTENT_ENCODING = "Content-Encoding"
11
+ CONTENT_SECURITY_POLICY = "Content-Security-Policy"
12
+ CONTENT_SECURITY_POLICY_REPORT_ONLY = "Content-Security-Policy-Report-Only"
13
+ LOCATION = "Location"
14
+ FEATURE_POLICY = "Feature-Policy"
15
+ X_REQUEST_ID = "X-Request-Id"
16
+ X_CASCADE = "X-Cascade"
17
+ SERVER_TIMING = "Server-Timing"
18
+ STRICT_TRANSPORT_SECURITY = "Strict-Transport-Security"
19
+ else
20
+ VARY = "vary"
21
+ CONTENT_ENCODING = "content-encoding"
22
+ CONTENT_SECURITY_POLICY = "content-security-policy"
23
+ CONTENT_SECURITY_POLICY_REPORT_ONLY = "content-security-policy-report-only"
24
+ LOCATION = "location"
25
+ FEATURE_POLICY = "feature-policy"
26
+ X_REQUEST_ID = "x-request-id"
27
+ X_CASCADE = "x-cascade"
28
+ SERVER_TIMING = "server-timing"
29
+ STRICT_TRANSPORT_SECURITY = "strict-transport-security"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ def self.deprecator # :nodoc:
5
+ @deprecator ||= ActiveSupport::Deprecation.new
6
+ end
7
+ end
@@ -138,15 +138,13 @@ module ActionDispatch
138
138
  def cache_control_segments
139
139
  if cache_control = _cache_control
140
140
  cache_control.delete(" ").split(",")
141
- else
142
- []
143
141
  end
144
142
  end
145
143
 
146
144
  def cache_control_headers
147
145
  cache_control = {}
148
146
 
149
- cache_control_segments.each do |segment|
147
+ cache_control_segments&.each do |segment|
150
148
  directive, argument = segment.split("=", 2)
151
149
 
152
150
  if SPECIAL_KEYS.include? directive
@@ -4,6 +4,8 @@ require "active_support/core_ext/object/deep_dup"
4
4
  require "active_support/core_ext/array/wrap"
5
5
 
6
6
  module ActionDispatch # :nodoc:
7
+ # = Action Dispatch Content Security Policy
8
+ #
7
9
  # Configures the HTTP
8
10
  # {Content-Security-Policy}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy]
9
11
  # response header to help protect against XSS and injection attacks.
@@ -23,16 +25,11 @@ module ActionDispatch # :nodoc:
23
25
  # end
24
26
  class ContentSecurityPolicy
25
27
  class Middleware
26
- CONTENT_TYPE = "Content-Type"
27
- POLICY = "Content-Security-Policy"
28
- POLICY_REPORT_ONLY = "Content-Security-Policy-Report-Only"
29
-
30
28
  def initialize(app)
31
29
  @app = app
32
30
  end
33
31
 
34
32
  def call(env)
35
- request = ActionDispatch::Request.new env
36
33
  status, headers, _ = response = @app.call(env)
37
34
 
38
35
  # Returning CSP headers with a 304 Not Modified is harmful, since nonces in the new
@@ -41,6 +38,8 @@ module ActionDispatch # :nodoc:
41
38
 
42
39
  return response if policy_present?(headers)
43
40
 
41
+ request = ActionDispatch::Request.new env
42
+
44
43
  if policy = request.content_security_policy
45
44
  nonce = request.content_security_policy_nonce
46
45
  nonce_directives = request.content_security_policy_nonce_directives
@@ -54,14 +53,15 @@ module ActionDispatch # :nodoc:
54
53
  private
55
54
  def header_name(request)
56
55
  if request.content_security_policy_report_only
57
- POLICY_REPORT_ONLY
56
+ ActionDispatch::Constants::CONTENT_SECURITY_POLICY_REPORT_ONLY
58
57
  else
59
- POLICY
58
+ ActionDispatch::Constants::CONTENT_SECURITY_POLICY
60
59
  end
61
60
  end
62
61
 
63
62
  def policy_present?(headers)
64
- headers[POLICY] || headers[POLICY_REPORT_ONLY]
63
+ headers[ActionDispatch::Constants::CONTENT_SECURITY_POLICY] ||
64
+ headers[ActionDispatch::Constants::CONTENT_SECURITY_POLICY_REPORT_ONLY]
65
65
  end
66
66
  end
67
67
 
@@ -123,6 +123,7 @@ module ActionDispatch # :nodoc:
123
123
  MAPPINGS = {
124
124
  self: "'self'",
125
125
  unsafe_eval: "'unsafe-eval'",
126
+ unsafe_hashes: "'unsafe-hashes'",
126
127
  unsafe_inline: "'unsafe-inline'",
127
128
  none: "'none'",
128
129
  http: "http:",
@@ -4,6 +4,8 @@ require "active_support/parameter_filter"
4
4
 
5
5
  module ActionDispatch
6
6
  module Http
7
+ # = Action Dispatch HTTP Filter Parameters
8
+ #
7
9
  # Allows you to specify sensitive query string and POST parameters to filter
8
10
  # from the request log.
9
11
  #
@@ -21,6 +23,7 @@ module ActionDispatch
21
23
  @filtered_parameters = nil
22
24
  @filtered_env = nil
23
25
  @filtered_path = nil
26
+ @parameter_filter = nil
24
27
  end
25
28
 
26
29
  # Returns a hash of parameters with all sensitive data replaced.
@@ -40,13 +43,16 @@ module ActionDispatch
40
43
  @filtered_path ||= query_string.empty? ? path : "#{path}?#{filtered_query_string}"
41
44
  end
42
45
 
43
- private
44
- def parameter_filter # :doc:
45
- parameter_filter_for fetch_header("action_dispatch.parameter_filter") {
46
- return NULL_PARAM_FILTER
47
- }
46
+ # Returns the +ActiveSupport::ParameterFilter+ object used to filter in this request.
47
+ def parameter_filter
48
+ @parameter_filter ||= if has_header?("action_dispatch.parameter_filter")
49
+ parameter_filter_for get_header("action_dispatch.parameter_filter")
50
+ else
51
+ NULL_PARAM_FILTER
52
+ end
48
53
  end
49
54
 
55
+ private
50
56
  def env_filter # :doc:
51
57
  user_key = fetch_header("action_dispatch.parameter_filter") {
52
58
  return NULL_ENV_FILTER
@@ -2,6 +2,8 @@
2
2
 
3
3
  module ActionDispatch
4
4
  module Http
5
+ # = Action Dispatch HTTP \Headers
6
+ #
5
7
  # Provides access to the request's HTTP headers from the environment.
6
8
  #
7
9
  # env = { "CONTENT_TYPE" => "text/plain", "HTTP_USER_AGENT" => "curl/7.43.0" }
@@ -16,7 +16,20 @@ module ActionDispatch
16
16
 
17
17
  included do
18
18
  mattr_accessor :ignore_accept_header, default: false
19
- cattr_accessor :return_only_media_type_on_content_type, default: false
19
+
20
+ def return_only_media_type_on_content_type=(value)
21
+ ActionDispatch.deprecator.warn(
22
+ "`config.action_dispatch.return_only_request_media_type_on_content_type` is deprecated and will" \
23
+ " be removed in Rails 7.2."
24
+ )
25
+ end
26
+
27
+ def return_only_media_type_on_content_type
28
+ ActionDispatch.deprecator.warn(
29
+ "`config.action_dispatch.return_only_request_media_type_on_content_type` is deprecated and will" \
30
+ " be removed in Rails 7.2."
31
+ )
32
+ end
20
33
  end
21
34
 
22
35
  # The MIME type of the HTTP request, such as Mime[:xml].
@@ -33,19 +46,6 @@ module ActionDispatch
33
46
  end
34
47
  end
35
48
 
36
- def content_type
37
- if self.class.return_only_media_type_on_content_type
38
- ActiveSupport::Deprecation.warn(
39
- "Rails 7.1 will return Content-Type header without modification." \
40
- " If you want just the MIME type, please use `#media_type` instead."
41
- )
42
-
43
- content_mime_type&.to_s
44
- else
45
- super
46
- end
47
- end
48
-
49
49
  def has_content_type? # :nodoc:
50
50
  get_header "CONTENT_TYPE"
51
51
  end
@@ -72,7 +72,7 @@ module ActionDispatch
72
72
  # GET /posts/5.xhtml | request.format => Mime[:html]
73
73
  # GET /posts/5 | request.format => Mime[:html] or Mime[:js], or request.accepts.first
74
74
  #
75
- def format(view_path = [])
75
+ def format(_view_path = nil)
76
76
  formats.first || Mime::NullType.instance
77
77
  end
78
78
 
@@ -81,7 +81,7 @@ module ActionDispatch
81
81
  v = if params_readable?
82
82
  Array(Mime[parameters[:format]])
83
83
  elsif use_accept_header && valid_accept_header
84
- accepts
84
+ accepts.dup
85
85
  elsif extension_format = format_from_path_extension
86
86
  [extension_format]
87
87
  elsif xhr?
@@ -90,7 +90,7 @@ module ActionDispatch
90
90
  [Mime[:html]]
91
91
  end
92
92
 
93
- v = v.select do |format|
93
+ v.select! do |format|
94
94
  format.symbol || format.ref == "*/*"
95
95
  end
96
96
 
@@ -172,22 +172,22 @@ module ActionDispatch
172
172
  # in which case we assume you're a browser and send HTML.
173
173
  BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/
174
174
 
175
- def params_readable? # :doc:
175
+ def params_readable?
176
176
  parameters[:format]
177
177
  rescue *RESCUABLE_MIME_FORMAT_ERRORS
178
178
  false
179
179
  end
180
180
 
181
- def valid_accept_header # :doc:
181
+ def valid_accept_header
182
182
  (xhr? && (accept.present? || content_mime_type)) ||
183
183
  (accept.present? && !accept.match?(BROWSER_LIKE_ACCEPTS))
184
184
  end
185
185
 
186
- def use_accept_header # :doc:
186
+ def use_accept_header
187
187
  !self.class.ignore_accept_header
188
188
  end
189
189
 
190
- def format_from_path_extension # :doc:
190
+ def format_from_path_extension
191
191
  path = get_header("action_dispatch.original_path") || get_header("PATH_INFO")
192
192
  if match = path && path.match(/\.(\w+)\z/)
193
193
  Mime[match.captures.first]