actionpack 5.2.1 → 7.0.2.4

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 (167) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +264 -220
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -6
  5. data/lib/abstract_controller/asset_paths.rb +1 -1
  6. data/lib/abstract_controller/base.rb +24 -4
  7. data/lib/abstract_controller/caching/fragments.rb +8 -24
  8. data/lib/abstract_controller/caching.rb +2 -2
  9. data/lib/abstract_controller/callbacks.rb +34 -8
  10. data/lib/abstract_controller/collector.rb +5 -4
  11. data/lib/abstract_controller/error.rb +1 -1
  12. data/lib/abstract_controller/helpers.rb +107 -90
  13. data/lib/abstract_controller/logger.rb +1 -1
  14. data/lib/abstract_controller/railties/routes_helpers.rb +19 -1
  15. data/lib/abstract_controller/rendering.rb +9 -9
  16. data/lib/abstract_controller/translation.rb +12 -5
  17. data/lib/abstract_controller/url_for.rb +4 -6
  18. data/lib/abstract_controller.rb +2 -0
  19. data/lib/action_controller/api.rb +5 -4
  20. data/lib/action_controller/base.rb +6 -9
  21. data/lib/action_controller/caching.rb +1 -3
  22. data/lib/action_controller/log_subscriber.rb +13 -9
  23. data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
  24. data/lib/action_controller/metal/conditional_get.rb +57 -6
  25. data/lib/action_controller/metal/content_security_policy.rb +2 -3
  26. data/lib/action_controller/metal/cookies.rb +4 -2
  27. data/lib/action_controller/metal/data_streaming.rb +9 -18
  28. data/lib/action_controller/metal/default_headers.rb +17 -0
  29. data/lib/action_controller/metal/etag_with_template_digest.rb +4 -6
  30. data/lib/action_controller/metal/exceptions.rb +55 -12
  31. data/lib/action_controller/metal/flash.rb +10 -6
  32. data/lib/action_controller/metal/head.rb +7 -4
  33. data/lib/action_controller/metal/helpers.rb +15 -6
  34. data/lib/action_controller/metal/http_authentication.rb +41 -39
  35. data/lib/action_controller/metal/implicit_render.rb +5 -15
  36. data/lib/action_controller/metal/instrumentation.rb +59 -55
  37. data/lib/action_controller/metal/live.rb +80 -33
  38. data/lib/action_controller/metal/logging.rb +20 -0
  39. data/lib/action_controller/metal/mime_responds.rb +22 -7
  40. data/lib/action_controller/metal/parameter_encoding.rb +35 -4
  41. data/lib/action_controller/metal/params_wrapper.rb +50 -31
  42. data/lib/action_controller/metal/permissions_policy.rb +46 -0
  43. data/lib/action_controller/metal/redirecting.rb +93 -23
  44. data/lib/action_controller/metal/renderers.rb +4 -4
  45. data/lib/action_controller/metal/rendering.rb +14 -9
  46. data/lib/action_controller/metal/request_forgery_protection.rb +160 -58
  47. data/lib/action_controller/metal/rescue.rb +2 -2
  48. data/lib/action_controller/metal/streaming.rb +1 -4
  49. data/lib/action_controller/metal/strong_parameters.rb +236 -88
  50. data/lib/action_controller/metal/testing.rb +9 -2
  51. data/lib/action_controller/metal/url_for.rb +1 -1
  52. data/lib/action_controller/metal.rb +16 -17
  53. data/lib/action_controller/railtie.rb +49 -6
  54. data/lib/action_controller/railties/helpers.rb +1 -1
  55. data/lib/action_controller/renderer.rb +37 -13
  56. data/lib/action_controller/template_assertions.rb +1 -1
  57. data/lib/action_controller/test_case.rb +98 -68
  58. data/lib/action_controller.rb +4 -5
  59. data/lib/action_dispatch/http/cache.rb +45 -32
  60. data/lib/action_dispatch/http/content_disposition.rb +45 -0
  61. data/lib/action_dispatch/http/content_security_policy.rb +69 -56
  62. data/lib/action_dispatch/http/filter_parameters.rb +14 -8
  63. data/lib/action_dispatch/http/filter_redirect.rb +2 -3
  64. data/lib/action_dispatch/http/headers.rb +4 -4
  65. data/lib/action_dispatch/http/mime_negotiation.rb +44 -16
  66. data/lib/action_dispatch/http/mime_type.rb +47 -30
  67. data/lib/action_dispatch/http/parameters.rb +18 -27
  68. data/lib/action_dispatch/http/permissions_policy.rb +173 -0
  69. data/lib/action_dispatch/http/request.rb +49 -35
  70. data/lib/action_dispatch/http/response.rb +34 -26
  71. data/lib/action_dispatch/http/upload.rb +9 -1
  72. data/lib/action_dispatch/http/url.rb +86 -94
  73. data/lib/action_dispatch/journey/formatter.rb +55 -31
  74. data/lib/action_dispatch/journey/gtg/builder.rb +30 -46
  75. data/lib/action_dispatch/journey/gtg/simulator.rb +15 -8
  76. data/lib/action_dispatch/journey/gtg/transition_table.rb +78 -21
  77. data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
  78. data/lib/action_dispatch/journey/nodes/node.rb +83 -16
  79. data/lib/action_dispatch/journey/parser.rb +13 -13
  80. data/lib/action_dispatch/journey/parser.y +1 -1
  81. data/lib/action_dispatch/journey/path/pattern.rb +42 -34
  82. data/lib/action_dispatch/journey/route.rb +14 -31
  83. data/lib/action_dispatch/journey/router/utils.rb +16 -14
  84. data/lib/action_dispatch/journey/router.rb +27 -35
  85. data/lib/action_dispatch/journey/routes.rb +3 -5
  86. data/lib/action_dispatch/journey/scanner.rb +10 -4
  87. data/lib/action_dispatch/journey/visitors.rb +1 -4
  88. data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
  89. data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
  90. data/lib/action_dispatch/journey.rb +0 -2
  91. data/lib/action_dispatch/middleware/actionable_exceptions.rb +45 -0
  92. data/lib/action_dispatch/middleware/callbacks.rb +2 -4
  93. data/lib/action_dispatch/middleware/cookies.rb +136 -113
  94. data/lib/action_dispatch/middleware/debug_exceptions.rb +47 -68
  95. data/lib/action_dispatch/middleware/debug_locks.rb +8 -8
  96. data/lib/action_dispatch/middleware/debug_view.rb +66 -0
  97. data/lib/action_dispatch/middleware/exception_wrapper.rb +79 -30
  98. data/lib/action_dispatch/middleware/executor.rb +4 -1
  99. data/lib/action_dispatch/middleware/flash.rb +10 -12
  100. data/lib/action_dispatch/middleware/host_authorization.rb +159 -0
  101. data/lib/action_dispatch/middleware/public_exceptions.rb +6 -3
  102. data/lib/action_dispatch/middleware/remote_ip.rb +30 -20
  103. data/lib/action_dispatch/middleware/request_id.rb +5 -6
  104. data/lib/action_dispatch/middleware/server_timing.rb +33 -0
  105. data/lib/action_dispatch/middleware/session/abstract_store.rb +16 -3
  106. data/lib/action_dispatch/middleware/session/cache_store.rb +11 -6
  107. data/lib/action_dispatch/middleware/session/cookie_store.rb +24 -19
  108. data/lib/action_dispatch/middleware/show_exceptions.rb +20 -11
  109. data/lib/action_dispatch/middleware/ssl.rb +20 -15
  110. data/lib/action_dispatch/middleware/stack.rb +79 -7
  111. data/lib/action_dispatch/middleware/static.rb +150 -94
  112. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  113. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  114. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  115. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +6 -11
  116. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  117. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
  118. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +46 -36
  119. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +8 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +7 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +25 -6
  122. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
  123. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +9 -6
  124. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +4 -1
  125. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +121 -15
  126. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  128. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +5 -5
  129. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +4 -4
  130. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +5 -5
  131. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
  132. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +16 -2
  133. data/lib/action_dispatch/railtie.rb +16 -4
  134. data/lib/action_dispatch/request/session.rb +59 -22
  135. data/lib/action_dispatch/request/utils.rb +28 -2
  136. data/lib/action_dispatch/routing/inspector.rb +102 -54
  137. data/lib/action_dispatch/routing/mapper.rb +184 -156
  138. data/lib/action_dispatch/routing/polymorphic_routes.rb +21 -19
  139. data/lib/action_dispatch/routing/redirection.rb +4 -6
  140. data/lib/action_dispatch/routing/route_set.rb +83 -73
  141. data/lib/action_dispatch/routing/routes_proxy.rb +1 -1
  142. data/lib/action_dispatch/routing/url_for.rb +2 -3
  143. data/lib/action_dispatch/routing.rb +23 -22
  144. data/lib/action_dispatch/system_test_case.rb +65 -16
  145. data/lib/action_dispatch/system_testing/browser.rb +43 -16
  146. data/lib/action_dispatch/system_testing/driver.rb +42 -10
  147. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +58 -12
  148. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +3 -10
  149. data/lib/action_dispatch/testing/assertion_response.rb +0 -1
  150. data/lib/action_dispatch/testing/assertions/response.rb +4 -7
  151. data/lib/action_dispatch/testing/assertions/routing.rb +20 -8
  152. data/lib/action_dispatch/testing/assertions.rb +3 -6
  153. data/lib/action_dispatch/testing/integration.rb +61 -30
  154. data/lib/action_dispatch/testing/request_encoder.rb +2 -2
  155. data/lib/action_dispatch/testing/test_process.rb +8 -6
  156. data/lib/action_dispatch/testing/test_request.rb +3 -3
  157. data/lib/action_dispatch/testing/test_response.rb +4 -32
  158. data/lib/action_dispatch.rb +15 -7
  159. data/lib/action_pack/gem_version.rb +4 -4
  160. data/lib/action_pack.rb +1 -1
  161. metadata +44 -25
  162. data/lib/action_controller/metal/force_ssl.rb +0 -99
  163. data/lib/action_dispatch/http/parameter_filter.rb +0 -86
  164. data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
  165. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -49
  166. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -120
  167. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -2,10 +2,17 @@
2
2
 
3
3
  module ActionController
4
4
  module Testing
5
- extend ActiveSupport::Concern
6
-
7
5
  # Behavior specific to functional tests
8
6
  module Functional # :nodoc:
7
+ def clear_instance_variables_between_requests
8
+ if defined?(@_ivars)
9
+ new_ivars = instance_variables - @_ivars
10
+ new_ivars.each { |ivar| remove_instance_variable(ivar) }
11
+ end
12
+
13
+ @_ivars = instance_variables
14
+ end
15
+
9
16
  def recycle!
10
17
  @_url_options = nil
11
18
  self.formats = nil
@@ -44,7 +44,7 @@ module ActionController
44
44
  options[:original_script_name] = original_script_name
45
45
  else
46
46
  if same_origin
47
- options[:script_name] = request.script_name.empty? ? "".freeze : request.script_name.dup
47
+ options[:script_name] = request.script_name.empty? ? "" : request.script_name.dup
48
48
  else
49
49
  options[:script_name] = script_name
50
50
  end
@@ -2,8 +2,6 @@
2
2
 
3
3
  require "active_support/core_ext/array/extract_options"
4
4
  require "action_dispatch/middleware/stack"
5
- require "action_dispatch/http/request"
6
- require "action_dispatch/http/response"
7
5
 
8
6
  module ActionController
9
7
  # Extend ActionDispatch middleware stack to make it aware of options
@@ -13,8 +11,8 @@ module ActionController
13
11
  # use AuthenticationMiddleware, except: [:index, :show]
14
12
  # end
15
13
  #
16
- class MiddlewareStack < ActionDispatch::MiddlewareStack #:nodoc:
17
- class Middleware < ActionDispatch::MiddlewareStack::Middleware #:nodoc:
14
+ class MiddlewareStack < ActionDispatch::MiddlewareStack # :nodoc:
15
+ class Middleware < ActionDispatch::MiddlewareStack::Middleware # :nodoc:
18
16
  def initialize(klass, args, actions, strategy, block)
19
17
  @actions = actions
20
18
  @strategy = strategy
@@ -26,16 +24,15 @@ module ActionController
26
24
  end
27
25
  end
28
26
 
29
- def build(action, app = Proc.new)
27
+ def build(action, app = nil, &block)
30
28
  action = action.to_s
31
29
 
32
- middlewares.reverse.inject(app) do |a, middleware|
30
+ middlewares.reverse.inject(app || block) do |a, middleware|
33
31
  middleware.valid?(action) ? middleware.build(a) : a
34
32
  end
35
33
  end
36
34
 
37
35
  private
38
-
39
36
  INCLUDE = ->(list, action) { list.include? action }
40
37
  EXCLUDE = ->(list, action) { !list.include? action }
41
38
  NULL = ->(list, action) { true }
@@ -127,7 +124,7 @@ module ActionController
127
124
  # ==== Returns
128
125
  # * <tt>string</tt>
129
126
  def self.controller_name
130
- @controller_name ||= name.demodulize.sub(/Controller$/, "").underscore
127
+ @controller_name ||= (name.demodulize.delete_suffix("Controller").underscore unless anonymous?)
131
128
  end
132
129
 
133
130
  def self.make_response!(request)
@@ -136,7 +133,7 @@ module ActionController
136
133
  end
137
134
  end
138
135
 
139
- def self.binary_params_for?(action) # :nodoc:
136
+ def self.action_encoding_template(action) # :nodoc:
140
137
  false
141
138
  end
142
139
 
@@ -148,7 +145,7 @@ module ActionController
148
145
  attr_internal :response, :request
149
146
  delegate :session, to: "@_request"
150
147
  delegate :headers, :status=, :location=, :content_type=,
151
- :status, :location, :content_type, to: "@_response"
148
+ :status, :location, :content_type, :media_type, to: "@_response"
152
149
 
153
150
  def initialize
154
151
  @_request = nil
@@ -185,7 +182,7 @@ module ActionController
185
182
  response_body || response.committed?
186
183
  end
187
184
 
188
- def dispatch(name, request, response) #:nodoc:
185
+ def dispatch(name, request, response) # :nodoc:
189
186
  set_request!(request)
190
187
  set_response!(response)
191
188
  process(name)
@@ -197,12 +194,12 @@ module ActionController
197
194
  @_response = response
198
195
  end
199
196
 
200
- def set_request!(request) #:nodoc:
197
+ def set_request!(request) # :nodoc:
201
198
  @_request = request
202
199
  @_request.controller_instance = self
203
200
  end
204
201
 
205
- def to_a #:nodoc:
202
+ def to_a # :nodoc:
206
203
  response.to_a
207
204
  end
208
205
 
@@ -217,10 +214,12 @@ module ActionController
217
214
  super
218
215
  end
219
216
 
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)
217
+ class << self
218
+ # Pushes the given Rack middleware and its arguments to the bottom of the
219
+ # middleware stack.
220
+ def use(...)
221
+ middleware_stack.use(...)
222
+ end
224
223
  end
225
224
 
226
225
  # Alias for +middleware_stack+.
@@ -8,8 +8,11 @@ require "action_controller/railties/helpers"
8
8
  require "action_view/railtie"
9
9
 
10
10
  module ActionController
11
- class Railtie < Rails::Railtie #:nodoc:
11
+ class Railtie < Rails::Railtie # :nodoc:
12
12
  config.action_controller = ActiveSupport::OrderedOptions.new
13
+ config.action_controller.raise_on_open_redirects = false
14
+ config.action_controller.log_query_tags_around_actions = true
15
+ config.action_controller.wrap_parameters_by_default = false
13
16
 
14
17
  config.eager_load_namespaces << ActionController
15
18
 
@@ -25,14 +28,19 @@ module ActionController
25
28
  options = app.config.action_controller
26
29
 
27
30
  ActiveSupport.on_load(:action_controller, run_once: true) do
28
- ActionController::Parameters.permit_all_parameters = options.delete(:permit_all_parameters) { false }
31
+ ActionController::Parameters.permit_all_parameters = options.permit_all_parameters || false
29
32
  if app.config.action_controller[:always_permitted_parameters]
30
33
  ActionController::Parameters.always_permitted_parameters =
31
- app.config.action_controller.delete(:always_permitted_parameters)
34
+ app.config.action_controller.always_permitted_parameters
32
35
  end
33
- ActionController::Parameters.action_on_unpermitted_parameters = options.delete(:action_on_unpermitted_parameters) do
34
- (Rails.env.test? || Rails.env.development?) ? :log : false
36
+
37
+ action_on_unpermitted_parameters = options.action_on_unpermitted_parameters
38
+
39
+ if action_on_unpermitted_parameters.nil?
40
+ action_on_unpermitted_parameters = (Rails.env.test? || Rails.env.development?) ? :log : false
35
41
  end
42
+
43
+ ActionController::Parameters.action_on_unpermitted_parameters = action_on_unpermitted_parameters
36
44
  end
37
45
  end
38
46
 
@@ -55,7 +63,18 @@ module ActionController
55
63
  extend ::AbstractController::Railties::RoutesHelpers.with(app.routes)
56
64
  extend ::ActionController::Railties::Helpers
57
65
 
58
- options.each do |k, v|
66
+ wrap_parameters format: [:json] if options.wrap_parameters_by_default && respond_to?(:wrap_parameters)
67
+
68
+ # Configs used in other initializers
69
+ filtered_options = options.except(
70
+ :log_query_tags_around_actions,
71
+ :permit_all_parameters,
72
+ :action_on_unpermitted_parameters,
73
+ :always_permitted_parameters,
74
+ :wrap_parameters_by_default
75
+ )
76
+
77
+ filtered_options.each do |k, v|
59
78
  k = "#{k}="
60
79
  if respond_to?(k)
61
80
  send(k, v)
@@ -85,5 +104,29 @@ module ActionController
85
104
  ActionController::Metal.descendants.each(&:action_methods) if config.eager_load
86
105
  end
87
106
  end
107
+
108
+ initializer "action_controller.query_log_tags" do |app|
109
+ query_logs_tags_enabled = app.config.respond_to?(:active_record) &&
110
+ app.config.active_record.query_log_tags_enabled &&
111
+ app.config.action_controller.log_query_tags_around_actions
112
+
113
+ if query_logs_tags_enabled
114
+ app.config.active_record.query_log_tags += [:controller, :action]
115
+
116
+ ActiveSupport.on_load(:active_record) do
117
+ ActiveRecord::QueryLogs.taggings.merge!(
118
+ controller: ->(context) { context[:controller]&.controller_name },
119
+ action: ->(context) { context[:controller]&.action_name },
120
+ namespaced_controller: ->(context) { context[:controller].class.name if context[:controller] }
121
+ )
122
+ end
123
+ end
124
+ end
125
+
126
+ initializer "action_controller.test_case" do |app|
127
+ ActiveSupport.on_load(:action_controller_test_case) do
128
+ ActionController::TestCase.executor_around_each_request = app.config.active_support.executor_around_test_case
129
+ end
130
+ end
88
131
  end
89
132
  end
@@ -7,7 +7,7 @@ module ActionController
7
7
  super
8
8
  return unless klass.respond_to?(:helpers_path=)
9
9
 
10
- if namespace = klass.parents.detect { |m| m.respond_to?(:railtie_helpers_paths) }
10
+ if namespace = klass.module_parents.detect { |m| m.respond_to?(:railtie_helpers_paths) }
11
11
  paths = namespace.railtie_helpers_paths
12
12
  else
13
13
  paths = ActionController::Helpers.helpers_path
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/hash/keys"
4
-
5
3
  module ActionController
6
4
  # ActionController::Renderer allows you to render arbitrary templates
7
5
  # without requirement of being in controller actions.
@@ -67,10 +65,29 @@ module ActionController
67
65
  def initialize(controller, env, defaults)
68
66
  @controller = controller
69
67
  @defaults = defaults
70
- @env = normalize_keys defaults.merge(env)
68
+ @env = normalize_keys defaults, env
71
69
  end
72
70
 
73
71
  # Render templates with any options from ActionController::Base#render_to_string.
72
+ #
73
+ # The primary options are:
74
+ # * <tt>:partial</tt> - See <tt>ActionView::PartialRenderer</tt> for details.
75
+ # * <tt>:file</tt> - Renders an explicit template file. Add <tt>:locals</tt> to pass in, if so desired.
76
+ # It shouldn’t be used directly with unsanitized user input due to lack of validation.
77
+ # * <tt>:inline</tt> - Renders an ERB template string.
78
+ # * <tt>:plain</tt> - Renders provided text and sets the content type as <tt>text/plain</tt>.
79
+ # * <tt>:html</tt> - Renders the provided HTML safe string, otherwise
80
+ # performs HTML escape on the string first. Sets the content type as <tt>text/html</tt>.
81
+ # * <tt>:json</tt> - Renders the provided hash or object in JSON. You don't
82
+ # need to call <tt>.to_json</tt> on the object you want to render.
83
+ # * <tt>:body</tt> - Renders provided text and sets content type of <tt>text/plain</tt>.
84
+ #
85
+ # If no <tt>options</tt> hash is passed or if <tt>:update</tt> is specified, then:
86
+ #
87
+ # If an object responding to +render_in+ is passed, +render_in+ is called on the object,
88
+ # passing in the current view context.
89
+ #
90
+ # Otherwise, a partial is rendered using the second parameter as the locals hash.
74
91
  def render(*args)
75
92
  raise "missing controller" unless controller
76
93
 
@@ -82,11 +99,18 @@ module ActionController
82
99
  instance.set_response! controller.make_response!(request)
83
100
  instance.render_to_string(*args)
84
101
  end
102
+ alias_method :render_to_string, :render # :nodoc:
85
103
 
86
104
  private
87
- def normalize_keys(env)
105
+ def normalize_keys(defaults, env)
88
106
  new_env = {}
89
107
  env.each_pair { |k, v| new_env[rack_key_for(k)] = rack_value_for(k, v) }
108
+
109
+ defaults.each_pair do |k, v|
110
+ key = rack_key_for(k)
111
+ new_env[key] = rack_value_for(k, v) unless new_env.key?(key)
112
+ end
113
+
90
114
  new_env["rack.url_scheme"] = new_env["HTTPS"] == "on" ? "https" : "http"
91
115
  new_env
92
116
  end
@@ -99,19 +123,19 @@ module ActionController
99
123
  input: "rack.input"
100
124
  }
101
125
 
102
- IDENTITY = ->(_) { _ }
103
-
104
- RACK_VALUE_TRANSLATION = {
105
- https: ->(v) { v ? "on" : "off" },
106
- method: ->(v) { v.upcase },
107
- }
108
-
109
126
  def rack_key_for(key)
110
- RACK_KEY_TRANSLATION.fetch(key, key.to_s)
127
+ RACK_KEY_TRANSLATION[key] || key.to_s
111
128
  end
112
129
 
113
130
  def rack_value_for(key, value)
114
- RACK_VALUE_TRANSLATION.fetch(key, IDENTITY).call value
131
+ case key
132
+ when :https
133
+ value ? "on" : "off"
134
+ when :method
135
+ -value.upcase
136
+ else
137
+ value
138
+ end
115
139
  end
116
140
  end
117
141
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionController
4
- module TemplateAssertions
4
+ module TemplateAssertions # :nodoc:
5
5
  def assert_template(options = {}, message = nil)
6
6
  raise NoMethodError,
7
7
  "assert_template has been extracted to a gem. To continue using it,
@@ -24,11 +24,14 @@ module ActionController
24
24
  def new_controller_thread # :nodoc:
25
25
  yield
26
26
  end
27
+
28
+ # Avoid a deadlock from the queue filling up
29
+ Buffer.queue_size = nil
27
30
  end
28
31
 
29
- # ActionController::TestCase will be deprecated and moved to a gem in Rails 5.1.
32
+ # ActionController::TestCase will be deprecated and moved to a gem in the future.
30
33
  # Please use ActionDispatch::IntegrationTest going forward.
31
- class TestRequest < ActionDispatch::TestRequest #:nodoc:
34
+ class TestRequest < ActionDispatch::TestRequest # :nodoc:
32
35
  DEFAULT_ENV = ActionDispatch::TestRequest::DEFAULT_ENV.dup
33
36
  DEFAULT_ENV.delete "PATH_INFO"
34
37
 
@@ -84,7 +87,7 @@ module ActionController
84
87
  value = value.to_param
85
88
  end
86
89
 
87
- path_parameters[key] = value
90
+ path_parameters[key.to_sym] = value
88
91
  end
89
92
  end
90
93
 
@@ -158,7 +161,6 @@ module ActionController
158
161
  end.new
159
162
 
160
163
  private
161
-
162
164
  def params_parsers
163
165
  super.merge @custom_param_parsers
164
166
  end
@@ -177,12 +179,12 @@ module ActionController
177
179
 
178
180
  # Methods #destroy and #load! are overridden to avoid calling methods on the
179
181
  # @store object, which does not exist for the TestSession class.
180
- class TestSession < Rack::Session::Abstract::SessionHash #:nodoc:
182
+ class TestSession < Rack::Session::Abstract::PersistedSecure::SecureSessionHash # :nodoc:
181
183
  DEFAULT_OPTIONS = Rack::Session::Abstract::Persisted::DEFAULT_OPTIONS
182
184
 
183
185
  def initialize(session = {})
184
186
  super(nil, nil)
185
- @id = SecureRandom.hex(16)
187
+ @id = Rack::Session::SessionId.new(SecureRandom.hex(16))
186
188
  @data = stringify_keys(session)
187
189
  @loaded = true
188
190
  end
@@ -203,12 +205,20 @@ module ActionController
203
205
  clear
204
206
  end
205
207
 
208
+ def dig(*keys)
209
+ keys = keys.map.with_index { |key, i| i.zero? ? key.to_s : key }
210
+ @data.dig(*keys)
211
+ end
212
+
206
213
  def fetch(key, *args, &block)
207
214
  @data.fetch(key.to_s, *args, &block)
208
215
  end
209
216
 
210
- private
217
+ def enabled?
218
+ true
219
+ end
211
220
 
221
+ private
212
222
  def load!
213
223
  @id
214
224
  end
@@ -276,9 +286,6 @@ module ActionController
276
286
  # after calling +post+. If the various assert methods are not sufficient, then you
277
287
  # may use this object to inspect the HTTP response in detail.
278
288
  #
279
- # (Earlier versions of \Rails required each functional test to subclass
280
- # Test::Unit::TestCase and define @controller, @request, @response in +setup+.)
281
- #
282
289
  # == Controller is automatically inferred
283
290
  #
284
291
  # ActionController::TestCase will automatically infer the controller under test
@@ -326,6 +333,8 @@ module ActionController
326
333
  #
327
334
  # assert_redirected_to page_url(title: 'foo')
328
335
  class TestCase < ActiveSupport::TestCase
336
+ singleton_class.attr_accessor :executor_around_each_request
337
+
329
338
  module Behavior
330
339
  extend ActiveSupport::Concern
331
340
  include ActionDispatch::TestProcess
@@ -456,10 +465,17 @@ module ActionController
456
465
  # prefer using #get, #post, #patch, #put, #delete and #head methods
457
466
  # respectively which will make tests more expressive.
458
467
  #
468
+ # It's not recommended to make more than one request in the same test. Instance
469
+ # 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
471
+ # ActionDispatch::IntegrationTest for making multiple requests in the same test.
472
+ #
459
473
  # Note that the request method is not verified.
460
- def process(action, method: "GET", params: {}, session: nil, body: nil, flash: {}, format: nil, xhr: false, as: nil)
474
+ def process(action, method: "GET", params: nil, session: nil, body: nil, flash: {}, format: nil, xhr: false, as: nil)
461
475
  check_required_ivars
476
+ @controller.clear_instance_variables_between_requests
462
477
 
478
+ action = +action.to_s
463
479
  http_method = method.to_s.upcase
464
480
 
465
481
  @html_document = nil
@@ -485,63 +501,14 @@ module ActionController
485
501
  format ||= as
486
502
  end
487
503
 
488
- parameters = params.symbolize_keys
504
+ parameters = (params || {}).symbolize_keys
489
505
 
490
506
  if format
491
507
  parameters[:format] = format
492
508
  end
493
509
 
494
- generated_extras = @routes.generate_extras(parameters.merge(controller: controller_class_name, action: action.to_s))
495
- generated_path = generated_path(generated_extras)
496
- query_string_keys = query_parameter_names(generated_extras)
497
-
498
- @request.assign_parameters(@routes, controller_class_name, action.to_s, parameters, generated_path, query_string_keys)
499
-
500
- @request.session.update(session) if session
501
- @request.flash.update(flash || {})
502
-
503
- if xhr
504
- @request.set_header "HTTP_X_REQUESTED_WITH", "XMLHttpRequest"
505
- @request.fetch_header("HTTP_ACCEPT") do |k|
506
- @request.set_header k, [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(", ")
507
- end
508
- end
509
-
510
- @request.fetch_header("SCRIPT_NAME") do |k|
511
- @request.set_header k, @controller.config.relative_url_root
512
- end
513
-
514
- begin
515
- @controller.recycle!
516
- @controller.dispatch(action, @request, @response)
517
- ensure
518
- @request = @controller.request
519
- @response = @controller.response
520
-
521
- if @request.have_cookie_jar?
522
- unless @request.cookie_jar.committed?
523
- @request.cookie_jar.write(@response)
524
- cookies.update(@request.cookie_jar.instance_variable_get(:@cookies))
525
- end
526
- end
527
- @response.prepare!
528
-
529
- if flash_value = @request.flash.to_session_value
530
- @request.session["flash"] = flash_value
531
- else
532
- @request.session.delete("flash")
533
- end
534
-
535
- if xhr
536
- @request.delete_header "HTTP_X_REQUESTED_WITH"
537
- @request.delete_header "HTTP_ACCEPT"
538
- end
539
- @request.query_string = ""
540
-
541
- @response.sent!
542
- end
543
-
544
- @response
510
+ setup_request(controller_class_name, action, parameters, session, flash, xhr)
511
+ process_controller_response(action, cookies, xhr)
545
512
  end
546
513
 
547
514
  def controller_class_name
@@ -597,12 +564,75 @@ module ActionController
597
564
  end
598
565
 
599
566
  private
567
+ def setup_request(controller_class_name, action, parameters, session, flash, xhr)
568
+ generated_extras = @routes.generate_extras(parameters.merge(controller: controller_class_name, action: action))
569
+ generated_path = generated_path(generated_extras)
570
+ query_string_keys = query_parameter_names(generated_extras)
571
+
572
+ @request.assign_parameters(@routes, controller_class_name, action, parameters, generated_path, query_string_keys)
573
+
574
+ @request.session.update(session) if session
575
+ @request.flash.update(flash || {})
576
+
577
+ if xhr
578
+ @request.set_header "HTTP_X_REQUESTED_WITH", "XMLHttpRequest"
579
+ @request.fetch_header("HTTP_ACCEPT") do |k|
580
+ @request.set_header k, [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(", ")
581
+ end
582
+ end
583
+
584
+ @request.fetch_header("SCRIPT_NAME") do |k|
585
+ @request.set_header k, @controller.config.relative_url_root
586
+ end
587
+ end
588
+
589
+ def wrap_execution(&block)
590
+ if ActionController::TestCase.executor_around_each_request && defined?(Rails.application) && Rails.application
591
+ Rails.application.executor.wrap(&block)
592
+ else
593
+ yield
594
+ end
595
+ end
596
+
597
+ def process_controller_response(action, cookies, xhr)
598
+ begin
599
+ @controller.recycle!
600
+
601
+ wrap_execution { @controller.dispatch(action, @request, @response) }
602
+ ensure
603
+ @request = @controller.request
604
+ @response = @controller.response
605
+
606
+ if @request.have_cookie_jar?
607
+ unless @request.cookie_jar.committed?
608
+ @request.cookie_jar.write(@response)
609
+ cookies.update(@request.cookie_jar.instance_variable_get(:@cookies))
610
+ end
611
+ end
612
+ @response.prepare!
613
+
614
+ if flash_value = @request.flash.to_session_value
615
+ @request.session["flash"] = flash_value
616
+ else
617
+ @request.session.delete("flash")
618
+ end
619
+
620
+ if xhr
621
+ @request.delete_header "HTTP_X_REQUESTED_WITH"
622
+ @request.delete_header "HTTP_ACCEPT"
623
+ end
624
+ @request.query_string = ""
625
+
626
+ @response.sent!
627
+ end
628
+
629
+ @response
630
+ end
600
631
 
601
632
  def scrub_env!(env)
602
- env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
603
- env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
604
- env.delete "action_dispatch.request.query_parameters"
605
- env.delete "action_dispatch.request.request_parameters"
633
+ env.delete_if do |k, _|
634
+ k.start_with?("rack.request", "action_dispatch.request", "action_dispatch.rescue")
635
+ end
606
636
  env["rack.input"] = StringIO.new
607
637
  env.delete "CONTENT_LENGTH"
608
638
  env.delete "RAW_POST_DATA"
@@ -614,7 +644,7 @@ module ActionController
614
644
  end
615
645
 
616
646
  def check_required_ivars
617
- # Sanity check for required instance variables so we can give an
647
+ # Check for required instance variables so we can give an
618
648
  # understandable error message.
619
649
  [:@routes, :@controller, :@request, :@response].each do |iv_name|
620
650
  if !instance_variable_defined?(iv_name) || instance_variable_get(iv_name).nil?
@@ -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
 
@@ -25,16 +22,19 @@ module ActionController
25
22
  autoload :ContentSecurityPolicy
26
23
  autoload :Cookies
27
24
  autoload :DataStreaming
25
+ autoload :DefaultHeaders
28
26
  autoload :EtagWithTemplateDigest
29
27
  autoload :EtagWithFlash
28
+ autoload :PermissionsPolicy
30
29
  autoload :Flash
31
- autoload :ForceSSL
32
30
  autoload :Head
33
31
  autoload :Helpers
34
32
  autoload :HttpAuthentication
35
33
  autoload :BasicImplicitRender
36
34
  autoload :ImplicitRender
37
35
  autoload :Instrumentation
36
+ autoload :Live
37
+ autoload :Logging
38
38
  autoload :MimeResponds
39
39
  autoload :ParamsWrapper
40
40
  autoload :Redirecting
@@ -62,5 +62,4 @@ require "active_support/core_ext/module/attribute_accessors"
62
62
  require "active_support/core_ext/load_error"
63
63
  require "active_support/core_ext/module/attr_internal"
64
64
  require "active_support/core_ext/name_error"
65
- require "active_support/core_ext/uri"
66
65
  require "active_support/inflector"