actionpack 7.1.5.1 → 8.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +308 -523
  3. data/README.rdoc +1 -1
  4. data/lib/abstract_controller/asset_paths.rb +6 -2
  5. data/lib/abstract_controller/base.rb +104 -105
  6. data/lib/abstract_controller/caching/fragments.rb +50 -53
  7. data/lib/abstract_controller/caching.rb +8 -3
  8. data/lib/abstract_controller/callbacks.rb +70 -62
  9. data/lib/abstract_controller/collector.rb +7 -7
  10. data/lib/abstract_controller/deprecator.rb +2 -0
  11. data/lib/abstract_controller/error.rb +2 -0
  12. data/lib/abstract_controller/helpers.rb +71 -84
  13. data/lib/abstract_controller/logger.rb +4 -1
  14. data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
  15. data/lib/abstract_controller/rendering.rb +13 -13
  16. data/lib/abstract_controller/translation.rb +12 -13
  17. data/lib/abstract_controller/url_for.rb +8 -6
  18. data/lib/abstract_controller.rb +2 -0
  19. data/lib/action_controller/api/api_rendering.rb +2 -0
  20. data/lib/action_controller/api.rb +76 -72
  21. data/lib/action_controller/base.rb +199 -126
  22. data/lib/action_controller/caching.rb +16 -14
  23. data/lib/action_controller/deprecator.rb +2 -0
  24. data/lib/action_controller/form_builder.rb +21 -18
  25. data/lib/action_controller/log_subscriber.rb +23 -2
  26. data/lib/action_controller/metal/allow_browser.rb +133 -0
  27. data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
  28. data/lib/action_controller/metal/conditional_get.rb +217 -175
  29. data/lib/action_controller/metal/content_security_policy.rb +25 -24
  30. data/lib/action_controller/metal/cookies.rb +4 -2
  31. data/lib/action_controller/metal/data_streaming.rb +72 -63
  32. data/lib/action_controller/metal/default_headers.rb +5 -3
  33. data/lib/action_controller/metal/etag_with_flash.rb +3 -1
  34. data/lib/action_controller/metal/etag_with_template_digest.rb +17 -15
  35. data/lib/action_controller/metal/exceptions.rb +16 -9
  36. data/lib/action_controller/metal/flash.rb +13 -14
  37. data/lib/action_controller/metal/head.rb +15 -11
  38. data/lib/action_controller/metal/helpers.rb +63 -55
  39. data/lib/action_controller/metal/http_authentication.rb +209 -201
  40. data/lib/action_controller/metal/implicit_render.rb +17 -15
  41. data/lib/action_controller/metal/instrumentation.rb +16 -14
  42. data/lib/action_controller/metal/live.rb +177 -128
  43. data/lib/action_controller/metal/logging.rb +6 -4
  44. data/lib/action_controller/metal/mime_responds.rb +151 -142
  45. data/lib/action_controller/metal/parameter_encoding.rb +34 -32
  46. data/lib/action_controller/metal/params_wrapper.rb +57 -59
  47. data/lib/action_controller/metal/permissions_policy.rb +22 -12
  48. data/lib/action_controller/metal/rate_limiting.rb +92 -0
  49. data/lib/action_controller/metal/redirecting.rb +213 -94
  50. data/lib/action_controller/metal/renderers.rb +78 -57
  51. data/lib/action_controller/metal/rendering.rb +111 -77
  52. data/lib/action_controller/metal/request_forgery_protection.rb +182 -143
  53. data/lib/action_controller/metal/rescue.rb +20 -9
  54. data/lib/action_controller/metal/streaming.rb +118 -195
  55. data/lib/action_controller/metal/strong_parameters.rb +720 -530
  56. data/lib/action_controller/metal/testing.rb +2 -0
  57. data/lib/action_controller/metal/url_for.rb +17 -15
  58. data/lib/action_controller/metal.rb +86 -60
  59. data/lib/action_controller/railtie.rb +36 -15
  60. data/lib/action_controller/railties/helpers.rb +2 -0
  61. data/lib/action_controller/renderer.rb +41 -36
  62. data/lib/action_controller/structured_event_subscriber.rb +116 -0
  63. data/lib/action_controller/template_assertions.rb +4 -2
  64. data/lib/action_controller/test_case.rb +160 -131
  65. data/lib/action_controller.rb +5 -1
  66. data/lib/action_dispatch/constants.rb +8 -0
  67. data/lib/action_dispatch/deprecator.rb +2 -0
  68. data/lib/action_dispatch/http/cache.rb +163 -35
  69. data/lib/action_dispatch/http/content_disposition.rb +2 -0
  70. data/lib/action_dispatch/http/content_security_policy.rb +54 -39
  71. data/lib/action_dispatch/http/filter_parameters.rb +14 -8
  72. data/lib/action_dispatch/http/filter_redirect.rb +22 -1
  73. data/lib/action_dispatch/http/headers.rb +22 -22
  74. data/lib/action_dispatch/http/mime_negotiation.rb +89 -41
  75. data/lib/action_dispatch/http/mime_type.rb +25 -21
  76. data/lib/action_dispatch/http/mime_types.rb +3 -0
  77. data/lib/action_dispatch/http/param_builder.rb +187 -0
  78. data/lib/action_dispatch/http/param_error.rb +26 -0
  79. data/lib/action_dispatch/http/parameters.rb +14 -12
  80. data/lib/action_dispatch/http/permissions_policy.rb +25 -36
  81. data/lib/action_dispatch/http/query_parser.rb +55 -0
  82. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  83. data/lib/action_dispatch/http/request.rb +141 -92
  84. data/lib/action_dispatch/http/response.rb +137 -77
  85. data/lib/action_dispatch/http/upload.rb +18 -16
  86. data/lib/action_dispatch/http/url.rb +187 -89
  87. data/lib/action_dispatch/journey/formatter.rb +21 -9
  88. data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
  89. data/lib/action_dispatch/journey/gtg/simulator.rb +34 -11
  90. data/lib/action_dispatch/journey/gtg/transition_table.rb +47 -53
  91. data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
  92. data/lib/action_dispatch/journey/nodes/node.rb +8 -6
  93. data/lib/action_dispatch/journey/parser.rb +99 -195
  94. data/lib/action_dispatch/journey/path/pattern.rb +4 -1
  95. data/lib/action_dispatch/journey/route.rb +54 -38
  96. data/lib/action_dispatch/journey/router/utils.rb +22 -27
  97. data/lib/action_dispatch/journey/router.rb +63 -83
  98. data/lib/action_dispatch/journey/routes.rb +11 -2
  99. data/lib/action_dispatch/journey/scanner.rb +46 -42
  100. data/lib/action_dispatch/journey/visitors.rb +57 -23
  101. data/lib/action_dispatch/journey/visualizer/fsm.js +4 -6
  102. data/lib/action_dispatch/journey.rb +2 -0
  103. data/lib/action_dispatch/log_subscriber.rb +7 -1
  104. data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -0
  105. data/lib/action_dispatch/middleware/assume_ssl.rb +8 -5
  106. data/lib/action_dispatch/middleware/callbacks.rb +3 -1
  107. data/lib/action_dispatch/middleware/cookies.rb +125 -106
  108. data/lib/action_dispatch/middleware/debug_exceptions.rb +37 -8
  109. data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
  110. data/lib/action_dispatch/middleware/debug_view.rb +13 -5
  111. data/lib/action_dispatch/middleware/exception_wrapper.rb +18 -23
  112. data/lib/action_dispatch/middleware/executor.rb +19 -4
  113. data/lib/action_dispatch/middleware/flash.rb +63 -51
  114. data/lib/action_dispatch/middleware/host_authorization.rb +17 -15
  115. data/lib/action_dispatch/middleware/public_exceptions.rb +14 -12
  116. data/lib/action_dispatch/middleware/reloader.rb +5 -3
  117. data/lib/action_dispatch/middleware/remote_ip.rb +87 -77
  118. data/lib/action_dispatch/middleware/request_id.rb +16 -10
  119. data/lib/action_dispatch/middleware/server_timing.rb +4 -2
  120. data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -0
  121. data/lib/action_dispatch/middleware/session/cache_store.rb +30 -8
  122. data/lib/action_dispatch/middleware/session/cookie_store.rb +27 -26
  123. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -3
  124. data/lib/action_dispatch/middleware/show_exceptions.rb +16 -16
  125. data/lib/action_dispatch/middleware/ssl.rb +53 -40
  126. data/lib/action_dispatch/middleware/stack.rb +11 -10
  127. data/lib/action_dispatch/middleware/static.rb +33 -31
  128. data/lib/action_dispatch/middleware/templates/rescues/_copy_button.html.erb +1 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +3 -5
  130. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +9 -5
  131. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +1 -0
  132. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +1 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +50 -0
  136. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -0
  137. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -0
  138. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -0
  139. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -0
  140. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -0
  141. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
  142. data/lib/action_dispatch/railtie.rb +23 -3
  143. data/lib/action_dispatch/request/session.rb +24 -21
  144. data/lib/action_dispatch/request/utils.rb +11 -3
  145. data/lib/action_dispatch/routing/endpoint.rb +2 -0
  146. data/lib/action_dispatch/routing/inspector.rb +85 -60
  147. data/lib/action_dispatch/routing/mapper.rb +1031 -851
  148. data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
  149. data/lib/action_dispatch/routing/redirection.rb +47 -39
  150. data/lib/action_dispatch/routing/route_set.rb +79 -56
  151. data/lib/action_dispatch/routing/routes_proxy.rb +7 -4
  152. data/lib/action_dispatch/routing/url_for.rb +130 -125
  153. data/lib/action_dispatch/routing.rb +150 -148
  154. data/lib/action_dispatch/structured_event_subscriber.rb +20 -0
  155. data/lib/action_dispatch/system_test_case.rb +91 -81
  156. data/lib/action_dispatch/system_testing/browser.rb +16 -23
  157. data/lib/action_dispatch/system_testing/driver.rb +2 -0
  158. data/lib/action_dispatch/system_testing/server.rb +2 -0
  159. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +34 -23
  160. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
  161. data/lib/action_dispatch/testing/assertion_response.rb +9 -7
  162. data/lib/action_dispatch/testing/assertions/response.rb +52 -25
  163. data/lib/action_dispatch/testing/assertions/routing.rb +168 -87
  164. data/lib/action_dispatch/testing/assertions.rb +2 -0
  165. data/lib/action_dispatch/testing/integration.rb +233 -223
  166. data/lib/action_dispatch/testing/request_encoder.rb +11 -9
  167. data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
  168. data/lib/action_dispatch/testing/test_process.rb +11 -8
  169. data/lib/action_dispatch/testing/test_request.rb +3 -1
  170. data/lib/action_dispatch/testing/test_response.rb +27 -26
  171. data/lib/action_dispatch.rb +36 -32
  172. data/lib/action_pack/gem_version.rb +6 -4
  173. data/lib/action_pack/version.rb +3 -1
  174. data/lib/action_pack.rb +17 -16
  175. metadata +36 -32
  176. data/lib/action_dispatch/journey/parser.y +0 -50
  177. data/lib/action_dispatch/journey/parser_extras.rb +0 -31
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "active_support/core_ext/hash/indifferent_access"
4
6
 
5
7
  module ActionDispatch
@@ -81,8 +83,8 @@ module ActionDispatch
81
83
  end
82
84
 
83
85
  class CustomParamEncoder # :nodoc:
84
- def self.encode(request, params, controller, action)
85
- return params unless controller && controller.valid_encoding? && encoding_template = action_encoding_template(request, controller, action)
86
+ def self.encode_for_template(params, encoding_template)
87
+ return params unless encoding_template
86
88
  params.except(:controller, :action).each do |key, value|
87
89
  ActionDispatch::Request::Utils.each_param_value(value) do |param|
88
90
  # If `param` is frozen, it comes from the router defaults
@@ -96,8 +98,14 @@ module ActionDispatch
96
98
  params
97
99
  end
98
100
 
101
+ def self.encode(request, params, controller, action)
102
+ encoding_template = action_encoding_template(request, controller, action)
103
+ encode_for_template(params, encoding_template)
104
+ end
105
+
99
106
  def self.action_encoding_template(request, controller, action) # :nodoc:
100
- request.controller_class_for(controller).action_encoding_template(action)
107
+ controller && controller.valid_encoding? &&
108
+ request.controller_class_for(controller).action_encoding_template(action)
101
109
  rescue MissingController
102
110
  nil
103
111
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionDispatch
4
6
  module Routing
5
7
  class Endpoint # :nodoc:
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "delegate"
4
6
  require "io/console/size"
5
7
 
@@ -62,44 +64,73 @@ module ActionDispatch
62
64
  def engine?
63
65
  app.engine?
64
66
  end
67
+
68
+ def to_h
69
+ { name: name,
70
+ verb: verb,
71
+ path: path,
72
+ reqs: reqs,
73
+ source_location: source_location }
74
+ end
65
75
  end
66
76
 
67
77
  ##
68
78
  # This class is just used for displaying route information when someone
69
- # executes `bin/rails routes` or looks at the RoutingError page.
70
- # People should not use this class.
79
+ # executes `bin/rails routes` or looks at the RoutingError page. People should
80
+ # not use this class.
71
81
  class RoutesInspector # :nodoc:
72
82
  def initialize(routes)
73
- @engines = {}
74
- @routes = routes
83
+ @routes = wrap_routes(routes)
84
+ @engines = load_engines_routes
75
85
  end
76
86
 
77
87
  def format(formatter, filter = {})
78
- routes_to_display = filter_routes(normalize_filter(filter))
79
- routes = collect_routes(routes_to_display)
80
- if routes.none?
81
- formatter.no_routes(collect_routes(@routes), filter)
82
- return formatter.result
83
- end
84
-
85
- formatter.header routes
86
- formatter.section routes
88
+ all_routes = { nil => @routes }.merge(@engines)
87
89
 
88
- @engines.each do |name, engine_routes|
89
- formatter.section_title "Routes for #{name}"
90
- formatter.section engine_routes
90
+ all_routes.each do |engine_name, routes|
91
+ format_routes(formatter, filter, engine_name, routes)
91
92
  end
92
93
 
93
94
  formatter.result
94
95
  end
95
96
 
96
97
  private
98
+ def format_routes(formatter, filter, engine_name, routes)
99
+ routes = filter_routes(routes, normalize_filter(filter)).map(&:to_h)
100
+
101
+ formatter.section_title "Routes for #{engine_name || "application"}" if @engines.any?
102
+ if routes.any?
103
+ formatter.header routes
104
+ formatter.section routes
105
+ else
106
+ formatter.no_routes engine_name, routes, filter
107
+ end
108
+ formatter.footer routes
109
+ end
110
+
111
+ def wrap_routes(routes)
112
+ routes.routes.map { |route| RouteWrapper.new(route) }.reject(&:internal?)
113
+ end
114
+
115
+ def load_engines_routes
116
+ engine_routes = @routes.select(&:engine?)
117
+
118
+ engines = engine_routes.to_h do |engine_route|
119
+ engine_app_routes = engine_route.rack_app.routes
120
+ engine_app_routes = engine_app_routes.routes if engine_app_routes.is_a?(ActionDispatch::Routing::RouteSet)
121
+
122
+ [engine_route.endpoint, wrap_routes(engine_app_routes)]
123
+ end
124
+
125
+ engines
126
+ end
127
+
97
128
  def normalize_filter(filter)
98
129
  if filter[:controller]
99
130
  { controller: /#{filter[:controller].underscore.sub(/_?controller\z/, "")}/ }
100
131
  elsif filter[:grep]
101
132
  grep_pattern = Regexp.new(filter[:grep])
102
- path = RFC2396_PARSER.escape(filter[:grep])
133
+ path = URI::RFC2396_PARSER.escape(filter[:grep])
103
134
  normalized_path = ("/" + path).squeeze("/")
104
135
 
105
136
  {
@@ -113,39 +144,13 @@ module ActionDispatch
113
144
  end
114
145
  end
115
146
 
116
- def filter_routes(filter)
147
+ def filter_routes(routes, filter)
117
148
  if filter
118
- @routes.select do |route|
119
- route_wrapper = RouteWrapper.new(route)
120
- filter.any? { |filter_type, value| route_wrapper.matches_filter?(filter_type, value) }
149
+ routes.select do |route|
150
+ filter.any? { |filter_type, value| route.matches_filter?(filter_type, value) }
121
151
  end
122
152
  else
123
- @routes
124
- end
125
- end
126
-
127
- def collect_routes(routes)
128
- routes.collect do |route|
129
- RouteWrapper.new(route)
130
- end.reject(&:internal?).collect do |route|
131
- collect_engine_routes(route)
132
-
133
- { name: route.name,
134
- verb: route.verb,
135
- path: route.path,
136
- reqs: route.reqs,
137
- source_location: route.source_location }
138
- end
139
- end
140
-
141
- def collect_engine_routes(route)
142
- name = route.endpoint
143
- return unless route.engine?
144
- return if @engines[name]
145
-
146
- routes = route.rack_app.routes
147
- if routes.is_a?(ActionDispatch::Routing::RouteSet)
148
- @engines[name] = collect_routes(routes.routes)
153
+ routes
149
154
  end
150
155
  end
151
156
  end
@@ -169,27 +174,36 @@ module ActionDispatch
169
174
  def header(routes)
170
175
  end
171
176
 
172
- def no_routes(routes, filter)
173
- @buffer <<
174
- if routes.none?
175
- <<~MESSAGE
176
- You don't have any routes defined!
177
+ def footer(routes)
178
+ end
177
179
 
178
- Please add some routes in config/routes.rb.
179
- MESSAGE
180
- elsif filter.key?(:controller)
180
+ def no_routes(engine, routes, filter)
181
+ @buffer <<
182
+ if filter.key?(:controller)
181
183
  "No routes were found for this controller."
182
184
  elsif filter.key?(:grep)
183
185
  "No routes were found for this grep pattern."
186
+ elsif routes.none?
187
+ if engine
188
+ "No routes defined."
189
+ else
190
+ <<~MESSAGE
191
+ You don't have any routes defined!
192
+
193
+ Please add some routes in config/routes.rb.
194
+ MESSAGE
195
+ end
184
196
  end
185
197
 
186
- @buffer << "For more information about routes, see the Rails guide: https://guides.rubyonrails.org/routing.html."
198
+ unless engine
199
+ @buffer << "For more information about routes, see the Rails guide: https://guides.rubyonrails.org/routing.html."
200
+ end
187
201
  end
188
202
  end
189
203
 
190
204
  class Sheet < Base
191
205
  def section_title(title)
192
- @buffer << "\n#{title}:"
206
+ @buffer << "#{title}:"
193
207
  end
194
208
 
195
209
  def section(routes)
@@ -200,6 +214,10 @@ module ActionDispatch
200
214
  @buffer << draw_header(routes)
201
215
  end
202
216
 
217
+ def footer(routes)
218
+ @buffer << ""
219
+ end
220
+
203
221
  private
204
222
  def draw_section(routes)
205
223
  header_lengths = ["Prefix", "Verb", "URI Pattern"].map(&:length)
@@ -230,13 +248,17 @@ module ActionDispatch
230
248
  end
231
249
 
232
250
  def section_title(title)
233
- @buffer << "\n#{"[ #{title} ]"}"
251
+ @buffer << "#{"[ #{title} ]"}"
234
252
  end
235
253
 
236
254
  def section(routes)
237
255
  @buffer << draw_expanded_section(routes)
238
256
  end
239
257
 
258
+ def footer(routes)
259
+ @buffer << ""
260
+ end
261
+
240
262
  private
241
263
  def draw_expanded_section(routes)
242
264
  routes.map.each_with_index do |r, i|
@@ -267,7 +289,7 @@ module ActionDispatch
267
289
  super
268
290
  end
269
291
 
270
- def no_routes(routes, filter)
292
+ def no_routes(engine, routes, filter)
271
293
  @buffer <<
272
294
  if filter.none?
273
295
  "No unused routes found."
@@ -287,7 +309,7 @@ module ActionDispatch
287
309
  end
288
310
 
289
311
  def section_title(title)
290
- @buffer << %(<tr><th colspan="4">#{title}</th></tr>)
312
+ @buffer << %(<tr><th colspan="5">#{title}</th></tr>)
291
313
  end
292
314
 
293
315
  def section(routes)
@@ -298,6 +320,9 @@ module ActionDispatch
298
320
  def header(routes)
299
321
  end
300
322
 
323
+ def footer(routes)
324
+ end
325
+
301
326
  def no_routes(*)
302
327
  @buffer << <<~MESSAGE
303
328
  <p>You don't have any routes defined!</p>