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/module/attribute_accessors"
4
6
 
5
7
  module ActionDispatch
@@ -16,23 +18,9 @@ module ActionDispatch
16
18
 
17
19
  included do
18
20
  mattr_accessor :ignore_accept_header, 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
33
21
  end
34
22
 
35
- # The MIME type of the HTTP request, such as Mime[:xml].
23
+ # The MIME type of the HTTP request, such as [Mime](:xml).
36
24
  def content_mime_type
37
25
  fetch_header("action_dispatch.request.content_type") do |k|
38
26
  v = if get_header("CONTENT_TYPE") =~ /^([^,;]*)/
@@ -66,11 +54,16 @@ module ActionDispatch
66
54
  end
67
55
  end
68
56
 
69
- # Returns the MIME type for the \format used in the request.
57
+ # Returns the MIME type for the format used in the request.
58
+ #
59
+ # # GET /posts/5.xml
60
+ # request.format # => Mime[:xml]
70
61
  #
71
- # GET /posts/5.xml | request.format => Mime[:xml]
72
- # GET /posts/5.xhtml | request.format => Mime[:html]
73
- # GET /posts/5 | request.format => Mime[:html] or Mime[:js], or request.accepts.first
62
+ # # GET /posts/5.xhtml
63
+ # request.format # => Mime[:html]
64
+ #
65
+ # # GET /posts/5
66
+ # request.format # => Mime[:html] or Mime[:js], or request.accepts.first
74
67
  #
75
68
  def format(_view_path = nil)
76
69
  formats.first || Mime::NullType.instance
@@ -98,7 +91,49 @@ module ActionDispatch
98
91
  end
99
92
  end
100
93
 
101
- # Sets the \variant for template.
94
+ # Sets the \variant for the response template.
95
+ #
96
+ # When determining which template to render, Action View will incorporate
97
+ # all variants from the request. For example, if an
98
+ # `ArticlesController#index` action needs to respond to
99
+ # `request.variant = [:ios, :turbo_native]`, it will render the
100
+ # first template file it can find in the following list:
101
+ #
102
+ # - `app/views/articles/index.html+ios.erb`
103
+ # - `app/views/articles/index.html+turbo_native.erb`
104
+ # - `app/views/articles/index.html.erb`
105
+ #
106
+ # Variants add context to the requests that views render appropriately.
107
+ # Variant names are arbitrary, and can communicate anything from the
108
+ # request's platform (`:android`, `:ios`, `:linux`, `:macos`, `:windows`)
109
+ # to its browser (`:chrome`, `:edge`, `:firefox`, `:safari`), to the type
110
+ # of user (`:admin`, `:guest`, `:user`).
111
+ #
112
+ # Note: Adding many new variant templates with similarities to existing
113
+ # template files can make maintaining your view code more difficult.
114
+ #
115
+ # #### Parameters
116
+ #
117
+ # * `variant` - a symbol name or an array of symbol names for variants
118
+ # used to render the response template
119
+ #
120
+ # #### Examples
121
+ #
122
+ # class ApplicationController < ActionController::Base
123
+ # before_action :determine_variants
124
+ #
125
+ # private
126
+ # def determine_variants
127
+ # variants = []
128
+ #
129
+ # # some code to determine the variant(s) to use
130
+ #
131
+ # variants << :ios if request.user_agent.include?("iOS")
132
+ # variants << :turbo_native if request.user_agent.include?("Turbo Native")
133
+ #
134
+ # request.variant = variants
135
+ # end
136
+ # end
102
137
  def variant=(variant)
103
138
  variant = Array(variant)
104
139
 
@@ -109,40 +144,53 @@ module ActionDispatch
109
144
  end
110
145
  end
111
146
 
147
+ # Returns the \variant for the response template as an instance of
148
+ # ActiveSupport::ArrayInquirer.
149
+ #
150
+ # request.variant = :phone
151
+ # request.variant.phone? # => true
152
+ # request.variant.tablet? # => false
153
+ #
154
+ # request.variant = [:phone, :tablet]
155
+ # request.variant.phone? # => true
156
+ # request.variant.desktop? # => false
157
+ # request.variant.any?(:phone, :desktop) # => true
158
+ # request.variant.any?(:desktop, :watch) # => false
112
159
  def variant
113
160
  @variant ||= ActiveSupport::ArrayInquirer.new
114
161
  end
115
162
 
116
- # Sets the \format by string extension, which can be used to force custom formats
163
+ # Sets the format by string extension, which can be used to force custom formats
117
164
  # that are not controlled by the extension.
118
165
  #
119
- # class ApplicationController < ActionController::Base
120
- # before_action :adjust_format_for_iphone
166
+ # class ApplicationController < ActionController::Base
167
+ # before_action :adjust_format_for_iphone
121
168
  #
122
- # private
123
- # def adjust_format_for_iphone
124
- # request.format = :iphone if request.env["HTTP_USER_AGENT"][/iPhone/]
125
- # end
126
- # end
169
+ # private
170
+ # def adjust_format_for_iphone
171
+ # request.format = :iphone if request.env["HTTP_USER_AGENT"][/iPhone/]
172
+ # end
173
+ # end
127
174
  def format=(extension)
128
175
  parameters[:format] = extension.to_s
129
176
  set_header "action_dispatch.request.formats", [Mime::Type.lookup_by_extension(parameters[:format])]
130
177
  end
131
178
 
132
- # Sets the \formats by string extensions. This differs from #format= by allowing you
133
- # to set multiple, ordered formats, which is useful when you want to have a fallback.
179
+ # Sets the formats by string extensions. This differs from #format= by allowing
180
+ # you to set multiple, ordered formats, which is useful when you want to have a
181
+ # fallback.
134
182
  #
135
- # In this example, the +:iphone+ format will be used if it's available, otherwise it'll fall back
136
- # to the +:html+ format.
183
+ # In this example, the `:iphone` format will be used if it's available,
184
+ # otherwise it'll fall back to the `:html` format.
137
185
  #
138
- # class ApplicationController < ActionController::Base
139
- # before_action :adjust_format_for_iphone_with_html_fallback
186
+ # class ApplicationController < ActionController::Base
187
+ # before_action :adjust_format_for_iphone_with_html_fallback
140
188
  #
141
- # private
142
- # def adjust_format_for_iphone_with_html_fallback
143
- # request.formats = [ :iphone, :html ] if request.env["HTTP_USER_AGENT"][/iPhone/]
144
- # end
145
- # end
189
+ # private
190
+ # def adjust_format_for_iphone_with_html_fallback
191
+ # request.formats = [ :iphone, :html ] if request.env["HTTP_USER_AGENT"][/iPhone/]
192
+ # end
193
+ # end
146
194
  def formats=(extensions)
147
195
  parameters[:format] = extensions.first.to_s
148
196
  set_header "action_dispatch.request.formats", extensions.collect { |extension|
@@ -168,8 +216,8 @@ module ActionDispatch
168
216
  end
169
217
 
170
218
  private
171
- # We use normal content negotiation unless you include */* in your list,
172
- # in which case we assume you're a browser and send HTML.
219
+ # We use normal content negotiation unless you include **/** in your list, in
220
+ # which case we assume you're a browser and send HTML.
173
221
  BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/
174
222
 
175
223
  def params_readable?
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "singleton"
4
6
 
5
7
  module Mime
@@ -65,19 +67,20 @@ module Mime
65
67
  end
66
68
  end
67
69
 
68
- # Encapsulates the notion of a MIME type. Can be used at render time, for example, with:
70
+ # Encapsulates the notion of a MIME type. Can be used at render time, for
71
+ # example, with:
69
72
  #
70
- # class PostsController < ActionController::Base
71
- # def show
72
- # @post = Post.find(params[:id])
73
+ # class PostsController < ActionController::Base
74
+ # def show
75
+ # @post = Post.find(params[:id])
73
76
  #
74
- # respond_to do |format|
75
- # format.html
76
- # format.ics { render body: @post.to_ics, mime_type: Mime::Type.lookup("text/calendar") }
77
- # format.xml { render xml: @post }
77
+ # respond_to do |format|
78
+ # format.html
79
+ # format.ics { render body: @post.to_ics, mime_type: Mime::Type.lookup("text/calendar") }
80
+ # format.xml { render xml: @post }
81
+ # end
78
82
  # end
79
83
  # end
80
- # end
81
84
  class Type
82
85
  attr_reader :symbol
83
86
 
@@ -173,8 +176,9 @@ module Mime
173
176
  EXTENSION_LOOKUP[extension.to_s]
174
177
  end
175
178
 
176
- # Registers an alias that's not used on MIME type lookup, but can be referenced directly. Especially useful for
177
- # rendering different HTML versions depending on the user agent, like an iPhone.
179
+ # Registers an alias that's not used on MIME type lookup, but can be referenced
180
+ # directly. Especially useful for rendering different HTML versions depending on
181
+ # the user agent, like an iPhone.
178
182
  def register_alias(string, symbol, extension_synonyms = [])
179
183
  register(string, symbol, [], extension_synonyms, true)
180
184
  end
@@ -224,11 +228,11 @@ module Mime
224
228
  parse_data_with_trailing_star($1) if accept_header =~ TRAILING_STAR_REGEXP
225
229
  end
226
230
 
227
- # For an input of <tt>'text'</tt>, returns <tt>[Mime[:json], Mime[:xml], Mime[:ics],
228
- # Mime[:html], Mime[:css], Mime[:csv], Mime[:js], Mime[:yaml], Mime[:text]]</tt>.
231
+ # For an input of `'text'`, returns `[Mime[:json], Mime[:xml], Mime[:ics],
232
+ # Mime[:html], Mime[:css], Mime[:csv], Mime[:js], Mime[:yaml], Mime[:text]]`.
229
233
  #
230
- # For an input of <tt>'application'</tt>, returns <tt>[Mime[:html], Mime[:js],
231
- # Mime[:xml], Mime[:yaml], Mime[:atom], Mime[:json], Mime[:rss], Mime[:url_encoded_form]]</tt>.
234
+ # For an input of `'application'`, returns `[Mime[:html], Mime[:js], Mime[:xml],
235
+ # Mime[:yaml], Mime[:atom], Mime[:json], Mime[:rss], Mime[:url_encoded_form]]`.
232
236
  def parse_data_with_trailing_star(type)
233
237
  Mime::SET.select { |m| m.match?(type) }
234
238
  end
@@ -237,7 +241,7 @@ module Mime
237
241
  #
238
242
  # To unregister a MIME type:
239
243
  #
240
- # Mime::Type.unregister(:mobile)
244
+ # Mime::Type.unregister(:mobile)
241
245
  def unregister(symbol)
242
246
  symbol = symbol.downcase
243
247
  if mime = Mime[symbol]
@@ -329,7 +333,7 @@ module Mime
329
333
  def to_ary; end
330
334
  def to_a; end
331
335
 
332
- def method_missing(method, *args)
336
+ def method_missing(method, ...)
333
337
  if method.end_with?("?")
334
338
  method[0..-2].downcase.to_sym == to_sym
335
339
  else
@@ -353,9 +357,9 @@ module Mime
353
357
  def html?; true; end
354
358
  end
355
359
 
356
- # ALL isn't a real MIME type, so we don't register it for lookup with the
357
- # other concrete types. It's a wildcard match that we use for +respond_to+
358
- # negotiation internals.
360
+ # ALL isn't a real MIME type, so we don't register it for lookup with the other
361
+ # concrete types. It's a wildcard match that we use for `respond_to` negotiation
362
+ # internals.
359
363
  ALL = AllType.instance
360
364
 
361
365
  class NullType
@@ -376,7 +380,7 @@ module Mime
376
380
  method.end_with?("?")
377
381
  end
378
382
 
379
- def method_missing(method, *args)
383
+ def method_missing(method, ...)
380
384
  false if method.end_with?("?")
381
385
  end
382
386
  end
@@ -3,6 +3,8 @@
3
3
  # Build list of Mime types for HTTP responses
4
4
  # https://www.iana.org/assignments/media-types/
5
5
 
6
+ # :markup: markdown
7
+
6
8
  Mime::Type.register "text/html", :html, %w( application/xhtml+xml ), %w( xhtml )
7
9
  Mime::Type.register "text/plain", :text, [], %w(txt)
8
10
  Mime::Type.register "text/javascript", :js, %w( application/javascript application/x-javascript )
@@ -11,6 +13,7 @@ Mime::Type.register "text/calendar", :ics
11
13
  Mime::Type.register "text/csv", :csv
12
14
  Mime::Type.register "text/vcard", :vcf
13
15
  Mime::Type.register "text/vtt", :vtt, %w(vtt)
16
+ Mime::Type.register "text/markdown", :md, [], %w(md markdown)
14
17
 
15
18
  Mime::Type.register "image/png", :png, [], %w(png)
16
19
  Mime::Type.register "image/jpeg", :jpeg, [], %w(jpg jpeg jpe pjpeg)
@@ -0,0 +1,187 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ class ParamBuilder
5
+ # --
6
+ # This implementation is based on Rack::QueryParser,
7
+ # Copyright (C) 2007-2021 Leah Neukirchen <http://leahneukirchen.org/infopage.html>
8
+
9
+ def self.make_default(param_depth_limit)
10
+ new param_depth_limit
11
+ end
12
+
13
+ attr_reader :param_depth_limit
14
+
15
+ def initialize(param_depth_limit)
16
+ @param_depth_limit = param_depth_limit
17
+ end
18
+
19
+ cattr_accessor :default
20
+ self.default = make_default(100)
21
+
22
+ class << self
23
+ delegate :from_query_string, :from_pairs, :from_hash, to: :default
24
+
25
+ def ignore_leading_brackets
26
+ ActionDispatch.deprecator.warn <<~MSG
27
+ ActionDispatch::ParamBuilder.ignore_leading_brackets is deprecated and have no effect and will be removed in Rails 8.2.
28
+ MSG
29
+
30
+ @ignore_leading_brackets
31
+ end
32
+
33
+ def ignore_leading_brackets=(value)
34
+ ActionDispatch.deprecator.warn <<~MSG
35
+ ActionDispatch::ParamBuilder.ignore_leading_brackets is deprecated and have no effect and will be removed in Rails 8.2.
36
+ MSG
37
+
38
+ @ignore_leading_brackets = value
39
+ end
40
+ end
41
+
42
+ def from_query_string(qs, separator: nil, encoding_template: nil)
43
+ from_pairs QueryParser.each_pair(qs, separator), encoding_template: encoding_template
44
+ end
45
+
46
+ def from_pairs(pairs, encoding_template: nil)
47
+ params = make_params
48
+
49
+ pairs.each do |k, v|
50
+ if Hash === v
51
+ v = ActionDispatch::Http::UploadedFile.new(v)
52
+ end
53
+
54
+ store_nested_param(params, k, v, 0, encoding_template)
55
+ end
56
+
57
+ params
58
+ rescue ArgumentError => e
59
+ raise InvalidParameterError, e.message, e.backtrace
60
+ end
61
+
62
+ def from_hash(hash, encoding_template: nil)
63
+ # Force encodings from encoding template
64
+ hash = Request::Utils::CustomParamEncoder.encode_for_template(hash, encoding_template)
65
+
66
+ # Assert valid encoding
67
+ Request::Utils.check_param_encoding(hash)
68
+
69
+ # Convert hashes to HWIA (or UploadedFile), and deep-munge nils
70
+ # out of arrays
71
+ hash = Request::Utils.normalize_encode_params(hash)
72
+
73
+ hash
74
+ end
75
+
76
+ private
77
+ def store_nested_param(params, name, v, depth, encoding_template = nil)
78
+ raise ParamsTooDeepError if depth >= param_depth_limit
79
+
80
+ if !name
81
+ # nil name, treat same as empty string (required by tests)
82
+ k = after = ""
83
+ elsif depth == 0
84
+ # Start of parsing, don't treat [] or [ at start of string specially
85
+ if start = name.index("[", 1)
86
+ # Start of parameter nesting, use part before brackets as key
87
+ k = name[0, start]
88
+ after = name[start, name.length]
89
+ else
90
+ # Plain parameter with no nesting
91
+ k = name
92
+ after = ""
93
+ end
94
+ elsif name.start_with?("[]")
95
+ # Array nesting
96
+ k = "[]"
97
+ after = name[2, name.length]
98
+ elsif name.start_with?("[") && (start = name.index("]", 1))
99
+ # Hash nesting, use the part inside brackets as the key
100
+ k = name[1, start - 1]
101
+ after = name[start + 1, name.length]
102
+ else
103
+ # Probably malformed input, nested but not starting with [
104
+ # treat full name as key for backwards compatibility.
105
+ k = name
106
+ after = ""
107
+ end
108
+
109
+ return if k.empty?
110
+
111
+ unless k.valid_encoding?
112
+ raise InvalidParameterError, "Invalid encoding for parameter: #{k}"
113
+ end
114
+
115
+ if depth == 0 && String === v
116
+ # We have to wait until we've found the top part of the name,
117
+ # because that's what the encoding template is configured with
118
+ if encoding_template && (designated_encoding = encoding_template[k]) && !v.frozen?
119
+ v.force_encoding(designated_encoding)
120
+ end
121
+
122
+ # ... and we can't validate the encoding until after we've
123
+ # applied any template override
124
+ unless v.valid_encoding?
125
+ raise InvalidParameterError, "Invalid encoding for parameter: #{v.scrub}"
126
+ end
127
+ end
128
+
129
+ if after == ""
130
+ if k == "[]" && depth != 0
131
+ return (v || !ActionDispatch::Request::Utils.perform_deep_munge) ? [v] : []
132
+ else
133
+ params[k] = v
134
+ end
135
+ elsif after == "["
136
+ params[name] = v
137
+ elsif after == "[]"
138
+ params[k] ||= []
139
+ raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
140
+ params[k] << v if v || !ActionDispatch::Request::Utils.perform_deep_munge
141
+ elsif after.start_with?("[]")
142
+ # Recognize x[][y] (hash inside array) parameters
143
+ unless after[2] == "[" && after.end_with?("]") && (child_key = after[3, after.length - 4]) && !child_key.empty? && !child_key.index("[") && !child_key.index("]")
144
+ # Handle other nested array parameters
145
+ child_key = after[2, after.length]
146
+ end
147
+ params[k] ||= []
148
+ raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
149
+ if params_hash_type?(params[k].last) && !params_hash_has_key?(params[k].last, child_key)
150
+ store_nested_param(params[k].last, child_key, v, depth + 1)
151
+ else
152
+ params[k] << store_nested_param(make_params, child_key, v, depth + 1)
153
+ end
154
+ else
155
+ params[k] ||= make_params
156
+ raise ParameterTypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params_hash_type?(params[k])
157
+ params[k] = store_nested_param(params[k], after, v, depth + 1)
158
+ end
159
+
160
+ params
161
+ end
162
+
163
+ def make_params
164
+ ActiveSupport::HashWithIndifferentAccess.new
165
+ end
166
+
167
+ def new_depth_limit(param_depth_limit)
168
+ self.class.new @params_class, param_depth_limit
169
+ end
170
+
171
+ def params_hash_type?(obj)
172
+ Hash === obj
173
+ end
174
+
175
+ def params_hash_has_key?(hash, key)
176
+ return false if key.include?("[]")
177
+
178
+ key.split(/[\[\]]+/).inject(hash) do |h, part|
179
+ next h if part == ""
180
+ return false unless params_hash_type?(h) && h.key?(part)
181
+ h[part]
182
+ end
183
+
184
+ true
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ class ParamError < ActionDispatch::Http::Parameters::ParseError
5
+ def initialize(message = nil)
6
+ super
7
+ end
8
+
9
+ def self.===(other)
10
+ super || (
11
+ defined?(Rack::Utils::ParameterTypeError) && Rack::Utils::ParameterTypeError === other ||
12
+ defined?(Rack::Utils::InvalidParameterError) && Rack::Utils::InvalidParameterError === other ||
13
+ defined?(Rack::QueryParser::ParamsTooDeepError) && Rack::QueryParser::ParamsTooDeepError === other
14
+ )
15
+ end
16
+ end
17
+
18
+ class ParameterTypeError < ParamError
19
+ end
20
+
21
+ class InvalidParameterError < ParamError
22
+ end
23
+
24
+ class ParamsTooDeepError < ParamError
25
+ end
26
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionDispatch
4
6
  module Http
5
7
  module Parameters
@@ -14,8 +16,8 @@ module ActionDispatch
14
16
  }
15
17
  }
16
18
 
17
- # Raised when raw data from the request cannot be parsed by the parser
18
- # defined for request's content MIME type.
19
+ # Raised when raw data from the request cannot be parsed by the parser defined
20
+ # for request's content MIME type.
19
21
  class ParseError < StandardError
20
22
  def initialize(message = $!.message)
21
23
  super(message)
@@ -34,8 +36,8 @@ module ActionDispatch
34
36
  module ClassMethods
35
37
  # Configure the parameter parser for a given MIME type.
36
38
  #
37
- # It accepts a hash where the key is the symbol of the MIME type
38
- # and the value is a proc.
39
+ # It accepts a hash where the key is the symbol of the MIME type and the value
40
+ # is a proc.
39
41
  #
40
42
  # original_parsers = ActionDispatch::Request.parameter_parsers
41
43
  # xml_parser = -> (raw_post) { Hash.from_xml(raw_post) || {} }
@@ -46,7 +48,7 @@ module ActionDispatch
46
48
  end
47
49
  end
48
50
 
49
- # Returns both GET and POST \parameters in a single hash.
51
+ # Returns both GET and POST parameters in a single hash.
50
52
  def parameters
51
53
  params = get_header("action_dispatch.request.parameters")
52
54
  return params if params
@@ -63,24 +65,24 @@ module ActionDispatch
63
65
  alias :params :parameters
64
66
 
65
67
  def path_parameters=(parameters) # :nodoc:
66
- delete_header("action_dispatch.request.parameters")
68
+ @env.delete("action_dispatch.request.parameters")
67
69
 
68
70
  parameters = Request::Utils.set_binary_encoding(self, parameters, parameters[:controller], parameters[:action])
69
- # If any of the path parameters has an invalid encoding then
70
- # raise since it's likely to trigger errors further on.
71
+ # If any of the path parameters has an invalid encoding then raise since it's
72
+ # likely to trigger errors further on.
71
73
  Request::Utils.check_param_encoding(parameters)
72
74
 
73
- set_header PARAMETERS_KEY, parameters
75
+ @env[PARAMETERS_KEY] = parameters
74
76
  rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
75
77
  raise ActionController::BadRequest.new("Invalid path parameters: #{e.message}")
76
78
  end
77
79
 
78
- # Returns a hash with the \parameters used to form the \path of the request.
80
+ # Returns a hash with the parameters used to form the path of the request.
79
81
  # Returned hash keys are symbols:
80
82
  #
81
- # { action: "my_action", controller: "my_controller" }
83
+ # { action: "my_action", controller: "my_controller" }
82
84
  def path_parameters
83
- get_header(PARAMETERS_KEY) || set_header(PARAMETERS_KEY, {})
85
+ @env[PARAMETERS_KEY] ||= {}
84
86
  end
85
87
 
86
88
  private