actionpack 7.1.6 → 7.2.3

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 (158) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +117 -607
  3. data/README.rdoc +1 -1
  4. data/lib/abstract_controller/asset_paths.rb +2 -0
  5. data/lib/abstract_controller/base.rb +93 -100
  6. data/lib/abstract_controller/caching/fragments.rb +50 -53
  7. data/lib/abstract_controller/caching.rb +2 -0
  8. data/lib/abstract_controller/callbacks.rb +66 -64
  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 +2 -0
  14. data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
  15. data/lib/abstract_controller/rendering.rb +13 -12
  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 +75 -72
  21. data/lib/action_controller/base.rb +198 -126
  22. data/lib/action_controller/caching.rb +15 -12
  23. data/lib/action_controller/deprecator.rb +2 -0
  24. data/lib/action_controller/form_builder.rb +20 -17
  25. data/lib/action_controller/log_subscriber.rb +3 -1
  26. data/lib/action_controller/metal/allow_browser.rb +123 -0
  27. data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
  28. data/lib/action_controller/metal/conditional_get.rb +187 -174
  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 +69 -62
  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 +11 -9
  36. data/lib/action_controller/metal/flash.rb +12 -10
  37. data/lib/action_controller/metal/head.rb +12 -10
  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 +15 -12
  42. data/lib/action_controller/metal/live.rb +116 -108
  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 +13 -12
  48. data/lib/action_controller/metal/rate_limiting.rb +62 -0
  49. data/lib/action_controller/metal/redirecting.rb +112 -85
  50. data/lib/action_controller/metal/renderers.rb +50 -49
  51. data/lib/action_controller/metal/rendering.rb +104 -76
  52. data/lib/action_controller/metal/request_forgery_protection.rb +165 -134
  53. data/lib/action_controller/metal/rescue.rb +11 -9
  54. data/lib/action_controller/metal/streaming.rb +138 -136
  55. data/lib/action_controller/metal/strong_parameters.rb +483 -481
  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 +3 -0
  60. data/lib/action_controller/railties/helpers.rb +2 -0
  61. data/lib/action_controller/renderer.rb +41 -36
  62. data/lib/action_controller/template_assertions.rb +4 -2
  63. data/lib/action_controller/test_case.rb +148 -129
  64. data/lib/action_controller.rb +5 -1
  65. data/lib/action_dispatch/constants.rb +8 -0
  66. data/lib/action_dispatch/deprecator.rb +2 -0
  67. data/lib/action_dispatch/http/cache.rb +27 -26
  68. data/lib/action_dispatch/http/content_disposition.rb +2 -0
  69. data/lib/action_dispatch/http/content_security_policy.rb +40 -38
  70. data/lib/action_dispatch/http/filter_parameters.rb +9 -5
  71. data/lib/action_dispatch/http/filter_redirect.rb +22 -1
  72. data/lib/action_dispatch/http/headers.rb +22 -22
  73. data/lib/action_dispatch/http/mime_negotiation.rb +35 -41
  74. data/lib/action_dispatch/http/mime_type.rb +25 -21
  75. data/lib/action_dispatch/http/mime_types.rb +2 -0
  76. data/lib/action_dispatch/http/parameters.rb +11 -9
  77. data/lib/action_dispatch/http/permissions_policy.rb +19 -36
  78. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  79. data/lib/action_dispatch/http/request.rb +72 -72
  80. data/lib/action_dispatch/http/response.rb +88 -62
  81. data/lib/action_dispatch/http/upload.rb +18 -16
  82. data/lib/action_dispatch/http/url.rb +77 -75
  83. data/lib/action_dispatch/journey/formatter.rb +21 -9
  84. data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
  85. data/lib/action_dispatch/journey/gtg/simulator.rb +2 -0
  86. data/lib/action_dispatch/journey/gtg/transition_table.rb +14 -12
  87. data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
  88. data/lib/action_dispatch/journey/nodes/node.rb +6 -5
  89. data/lib/action_dispatch/journey/parser.rb +4 -3
  90. data/lib/action_dispatch/journey/parser_extras.rb +2 -0
  91. data/lib/action_dispatch/journey/path/pattern.rb +4 -1
  92. data/lib/action_dispatch/journey/route.rb +9 -7
  93. data/lib/action_dispatch/journey/router/utils.rb +16 -15
  94. data/lib/action_dispatch/journey/router.rb +4 -2
  95. data/lib/action_dispatch/journey/routes.rb +4 -2
  96. data/lib/action_dispatch/journey/scanner.rb +4 -2
  97. data/lib/action_dispatch/journey/visitors.rb +2 -0
  98. data/lib/action_dispatch/journey.rb +2 -0
  99. data/lib/action_dispatch/log_subscriber.rb +2 -0
  100. data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -0
  101. data/lib/action_dispatch/middleware/assume_ssl.rb +8 -5
  102. data/lib/action_dispatch/middleware/callbacks.rb +3 -1
  103. data/lib/action_dispatch/middleware/cookies.rb +119 -104
  104. data/lib/action_dispatch/middleware/debug_exceptions.rb +16 -6
  105. data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
  106. data/lib/action_dispatch/middleware/debug_view.rb +2 -0
  107. data/lib/action_dispatch/middleware/exception_wrapper.rb +9 -14
  108. data/lib/action_dispatch/middleware/executor.rb +7 -2
  109. data/lib/action_dispatch/middleware/flash.rb +63 -51
  110. data/lib/action_dispatch/middleware/host_authorization.rb +17 -15
  111. data/lib/action_dispatch/middleware/public_exceptions.rb +13 -7
  112. data/lib/action_dispatch/middleware/reloader.rb +5 -3
  113. data/lib/action_dispatch/middleware/remote_ip.rb +76 -72
  114. data/lib/action_dispatch/middleware/request_id.rb +14 -9
  115. data/lib/action_dispatch/middleware/server_timing.rb +4 -2
  116. data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -0
  117. data/lib/action_dispatch/middleware/session/cache_store.rb +13 -8
  118. data/lib/action_dispatch/middleware/session/cookie_store.rb +27 -26
  119. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -3
  120. data/lib/action_dispatch/middleware/show_exceptions.rb +16 -16
  121. data/lib/action_dispatch/middleware/ssl.rb +43 -40
  122. data/lib/action_dispatch/middleware/stack.rb +11 -10
  123. data/lib/action_dispatch/middleware/static.rb +33 -31
  124. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +1 -1
  125. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
  126. data/lib/action_dispatch/railtie.rb +2 -3
  127. data/lib/action_dispatch/request/session.rb +23 -21
  128. data/lib/action_dispatch/request/utils.rb +2 -0
  129. data/lib/action_dispatch/routing/endpoint.rb +2 -0
  130. data/lib/action_dispatch/routing/inspector.rb +5 -3
  131. data/lib/action_dispatch/routing/mapper.rb +622 -623
  132. data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
  133. data/lib/action_dispatch/routing/redirection.rb +37 -32
  134. data/lib/action_dispatch/routing/route_set.rb +59 -45
  135. data/lib/action_dispatch/routing/routes_proxy.rb +6 -4
  136. data/lib/action_dispatch/routing/url_for.rb +130 -125
  137. data/lib/action_dispatch/routing.rb +150 -148
  138. data/lib/action_dispatch/system_test_case.rb +91 -81
  139. data/lib/action_dispatch/system_testing/browser.rb +4 -2
  140. data/lib/action_dispatch/system_testing/driver.rb +2 -0
  141. data/lib/action_dispatch/system_testing/server.rb +2 -0
  142. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +32 -21
  143. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
  144. data/lib/action_dispatch/testing/assertion_response.rb +9 -7
  145. data/lib/action_dispatch/testing/assertions/response.rb +26 -23
  146. data/lib/action_dispatch/testing/assertions/routing.rb +153 -84
  147. data/lib/action_dispatch/testing/assertions.rb +2 -0
  148. data/lib/action_dispatch/testing/integration.rb +222 -222
  149. data/lib/action_dispatch/testing/request_encoder.rb +11 -9
  150. data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
  151. data/lib/action_dispatch/testing/test_process.rb +11 -8
  152. data/lib/action_dispatch/testing/test_request.rb +3 -1
  153. data/lib/action_dispatch/testing/test_response.rb +27 -26
  154. data/lib/action_dispatch.rb +22 -28
  155. data/lib/action_pack/gem_version.rb +5 -3
  156. data/lib/action_pack/version.rb +3 -1
  157. data/lib/action_pack.rb +17 -16
  158. metadata +34 -11
@@ -1,31 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "active_support/core_ext/object/deep_dup"
4
6
 
5
7
  module ActionDispatch # :nodoc:
6
- # = Action Dispatch \PermissionsPolicy
8
+ # # Action Dispatch PermissionsPolicy
7
9
  #
8
10
  # Configures the HTTP
9
- # {Feature-Policy}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy]
10
- # response header to specify which browser features the current document and
11
- # its iframes can use.
11
+ # [Feature-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy)
12
+ # response header to specify which browser features the current
13
+ # document and its iframes can use.
12
14
  #
13
15
  # Example global policy:
14
16
  #
15
- # Rails.application.config.permissions_policy do |policy|
16
- # policy.camera :none
17
- # policy.gyroscope :none
18
- # policy.microphone :none
19
- # policy.usb :none
20
- # policy.fullscreen :self
21
- # policy.payment :self, "https://secure.example.com"
22
- # end
17
+ # Rails.application.config.permissions_policy do |policy|
18
+ # policy.camera :none
19
+ # policy.gyroscope :none
20
+ # policy.microphone :none
21
+ # policy.usb :none
22
+ # policy.fullscreen :self
23
+ # policy.payment :self, "https://secure.example.com"
24
+ # end
23
25
  #
24
- # The Feature-Policy header has been renamed to Permissions-Policy.
25
- # The Permissions-Policy requires a different implementation and isn't
26
- # yet supported by all browsers. To avoid having to rename this
27
- # middleware in the future we use the new name for the middleware but
28
- # keep the old header name and implementation for now.
26
+ # The Feature-Policy header has been renamed to Permissions-Policy. The
27
+ # Permissions-Policy requires a different implementation and isn't yet supported
28
+ # by all browsers. To avoid having to rename this middleware in the future we
29
+ # use the new name for the middleware but keep the old header name and
30
+ # implementation for now.
29
31
  class PermissionsPolicy
30
32
  class Middleware
31
33
  def initialize(app)
@@ -125,25 +127,6 @@ module ActionDispatch # :nodoc:
125
127
  end
126
128
  end
127
129
 
128
- %w[speaker vibrate vr].each do |directive|
129
- define_method(directive) do |*sources|
130
- ActionDispatch.deprecator.warn(<<~MSG)
131
- The `#{directive}` permissions policy directive is deprecated
132
- and will be removed in Rails 7.2.
133
-
134
- There is no browser support for this directive, and no plan
135
- for browser support in the future. You can just remove this
136
- directive from your application.
137
- MSG
138
-
139
- if sources.first
140
- @directives[directive] = apply_mappings(sources)
141
- else
142
- @directives.delete(directive)
143
- end
144
- end
145
- end
146
-
147
130
  def build(context = nil)
148
131
  build_directives(context).compact.join("; ")
149
132
  end
@@ -2,6 +2,8 @@
2
2
 
3
3
  # :enddoc:
4
4
 
5
+ # :markup: markdown
6
+
5
7
  require "rack/cache"
6
8
  require "rack/cache/context"
7
9
  require "active_support/cache"
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "stringio"
4
6
 
5
7
  require "active_support/inflector"
@@ -102,26 +104,26 @@ module ActionDispatch
102
104
 
103
105
  # Returns true if the request has a header matching the given key parameter.
104
106
  #
105
- # request.key? :ip_spoofing_check # => true
107
+ # request.key? :ip_spoofing_check # => true
106
108
  def key?(key)
107
109
  has_header? key
108
110
  end
109
111
 
110
- # HTTP methods from {RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1}[https://www.ietf.org/rfc/rfc2616.txt]
112
+ # HTTP methods from [RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1](https://www.ietf.org/rfc/rfc2616.txt)
111
113
  RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT)
112
- # HTTP methods from {RFC 2518: HTTP Extensions for Distributed Authoring -- WEBDAV}[https://www.ietf.org/rfc/rfc2518.txt]
114
+ # HTTP methods from [RFC 2518: HTTP Extensions for Distributed Authoring -- WEBDAV](https://www.ietf.org/rfc/rfc2518.txt)
113
115
  RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK)
114
- # HTTP methods from {RFC 3253: Versioning Extensions to WebDAV}[https://www.ietf.org/rfc/rfc3253.txt]
116
+ # HTTP methods from [RFC 3253: Versioning Extensions to WebDAV](https://www.ietf.org/rfc/rfc3253.txt)
115
117
  RFC3253 = %w(VERSION-CONTROL REPORT CHECKOUT CHECKIN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE BASELINE-CONTROL MKACTIVITY)
116
- # HTTP methods from {RFC 3648: WebDAV Ordered Collections Protocol}[https://www.ietf.org/rfc/rfc3648.txt]
118
+ # HTTP methods from [RFC 3648: WebDAV Ordered Collections Protocol](https://www.ietf.org/rfc/rfc3648.txt)
117
119
  RFC3648 = %w(ORDERPATCH)
118
- # HTTP methods from {RFC 3744: WebDAV Access Control Protocol}[https://www.ietf.org/rfc/rfc3744.txt]
120
+ # HTTP methods from [RFC 3744: WebDAV Access Control Protocol](https://www.ietf.org/rfc/rfc3744.txt)
119
121
  RFC3744 = %w(ACL)
120
- # HTTP methods from {RFC 5323: WebDAV SEARCH}[https://www.ietf.org/rfc/rfc5323.txt]
122
+ # HTTP methods from [RFC 5323: WebDAV SEARCH](https://www.ietf.org/rfc/rfc5323.txt)
121
123
  RFC5323 = %w(SEARCH)
122
- # HTTP methods from {RFC 4791: Calendaring Extensions to WebDAV}[https://www.ietf.org/rfc/rfc4791.txt]
124
+ # HTTP methods from [RFC 4791: Calendaring Extensions to WebDAV](https://www.ietf.org/rfc/rfc4791.txt)
123
125
  RFC4791 = %w(MKCALENDAR)
124
- # HTTP methods from {RFC 5789: PATCH Method for HTTP}[https://www.ietf.org/rfc/rfc5789.txt]
126
+ # HTTP methods from [RFC 5789: PATCH Method for HTTP](https://www.ietf.org/rfc/rfc5789.txt)
125
127
  RFC5789 = %w(PATCH)
126
128
 
127
129
  HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789
@@ -130,25 +132,24 @@ module ActionDispatch
130
132
 
131
133
  # Populate the HTTP method lookup cache.
132
134
  HTTP_METHODS.each { |method|
133
- HTTP_METHOD_LOOKUP[method] = method.underscore.to_sym
135
+ HTTP_METHOD_LOOKUP[method] = method.downcase.underscore.to_sym
134
136
  }
135
137
 
136
138
  alias raw_request_method request_method # :nodoc:
137
139
 
138
- # Returns the HTTP \method that the application should see.
139
- # In the case where the \method was overridden by a middleware
140
- # (for instance, if a HEAD request was converted to a GET,
141
- # or if a _method parameter was used to determine the \method
142
- # the application should use), this \method returns the overridden
143
- # value, not the original.
140
+ # Returns the HTTP method that the application should see. In the case where the
141
+ # method was overridden by a middleware (for instance, if a HEAD request was
142
+ # converted to a GET, or if a _method parameter was used to determine the method
143
+ # the application should use), this method returns the overridden value, not the
144
+ # original.
144
145
  def request_method
145
146
  @request_method ||= check_method(super)
146
147
  end
147
148
 
148
- # Returns the URI pattern of the matched route for the request,
149
- # using the same format as `bin/rails routes`:
149
+ # Returns the URI pattern of the matched route for the request, using the same
150
+ # format as `bin/rails routes`:
150
151
  #
151
- # request.route_uri_pattern # => "/:controller(/:action(/:id))(.:format)"
152
+ # request.route_uri_pattern # => "/:controller(/:action(/:id))(.:format)"
152
153
  def route_uri_pattern
153
154
  get_header("action_dispatch.route_uri_pattern")
154
155
  end
@@ -196,12 +197,11 @@ module ActionDispatch
196
197
  HTTP_METHOD_LOOKUP[request_method]
197
198
  end
198
199
 
199
- # Returns the original value of the environment's REQUEST_METHOD,
200
- # even if it was overridden by middleware. See #request_method for
201
- # more information.
200
+ # Returns the original value of the environment's REQUEST_METHOD, even if it was
201
+ # overridden by middleware. See #request_method for more information.
202
202
  #
203
- # For debugging purposes, when called with arguments this method will
204
- # fall back to Object#method
203
+ # For debugging purposes, when called with arguments this method will fall back
204
+ # to Object#method
205
205
  def method(*args)
206
206
  if args.empty?
207
207
  @method ||= check_method(
@@ -221,63 +221,62 @@ module ActionDispatch
221
221
 
222
222
  # Provides access to the request's HTTP headers, for example:
223
223
  #
224
- # request.headers["Content-Type"] # => "text/plain"
224
+ # request.headers["Content-Type"] # => "text/plain"
225
225
  def headers
226
226
  @headers ||= Http::Headers.new(self)
227
227
  end
228
228
 
229
- # Early Hints is an HTTP/2 status code that indicates hints to help a client start
230
- # making preparations for processing the final response.
229
+ # Early Hints is an HTTP/2 status code that indicates hints to help a client
230
+ # start making preparations for processing the final response.
231
231
  #
232
- # If the env contains +rack.early_hints+ then the server accepts HTTP2 push for
232
+ # If the env contains `rack.early_hints` then the server accepts HTTP2 push for
233
233
  # link headers.
234
234
  #
235
- # The +send_early_hints+ method accepts a hash of links as follows:
235
+ # The `send_early_hints` method accepts a hash of links as follows:
236
236
  #
237
- # send_early_hints("link" => "</style.css>; rel=preload; as=style,</script.js>; rel=preload")
237
+ # send_early_hints("link" => "</style.css>; rel=preload; as=style,</script.js>; rel=preload")
238
238
  #
239
- # If you are using +javascript_include_tag+ or +stylesheet_link_tag+ the
240
- # Early Hints headers are included by default if supported.
239
+ # If you are using {javascript_include_tag}[rdoc-ref:ActionView::Helpers::AssetTagHelper#javascript_include_tag]
240
+ # or {stylesheet_link_tag}[rdoc-ref:ActionView::Helpers::AssetTagHelper#stylesheet_link_tag]
241
+ # the Early Hints headers are included by default if supported.
241
242
  def send_early_hints(links)
242
- return unless env["rack.early_hints"]
243
-
244
- env["rack.early_hints"].call(links)
243
+ env["rack.early_hints"]&.call(links)
245
244
  end
246
245
 
247
- # Returns a +String+ with the last requested path including their params.
246
+ # Returns a `String` with the last requested path including their params.
248
247
  #
249
- # # get '/foo'
250
- # request.original_fullpath # => '/foo'
248
+ # # get '/foo'
249
+ # request.original_fullpath # => '/foo'
251
250
  #
252
- # # get '/foo?bar'
253
- # request.original_fullpath # => '/foo?bar'
251
+ # # get '/foo?bar'
252
+ # request.original_fullpath # => '/foo?bar'
254
253
  def original_fullpath
255
254
  @original_fullpath ||= (get_header("ORIGINAL_FULLPATH") || fullpath)
256
255
  end
257
256
 
258
- # Returns the +String+ full path including params of the last URL requested.
257
+ # Returns the `String` full path including params of the last URL requested.
259
258
  #
260
- # # get "/articles"
261
- # request.fullpath # => "/articles"
259
+ # # get "/articles"
260
+ # request.fullpath # => "/articles"
262
261
  #
263
- # # get "/articles?page=2"
264
- # request.fullpath # => "/articles?page=2"
262
+ # # get "/articles?page=2"
263
+ # request.fullpath # => "/articles?page=2"
265
264
  def fullpath
266
265
  @fullpath ||= super
267
266
  end
268
267
 
269
- # Returns the original request URL as a +String+.
268
+ # Returns the original request URL as a `String`.
270
269
  #
271
- # # get "/articles?page=2"
272
- # request.original_url # => "http://www.example.com/articles?page=2"
270
+ # # get "/articles?page=2"
271
+ # request.original_url # => "http://www.example.com/articles?page=2"
273
272
  def original_url
274
273
  base_url + original_fullpath
275
274
  end
276
275
 
277
- # The +String+ MIME type of the request.
276
+ # The `String` MIME type of the request.
278
277
  #
279
- # # get "/articles"
280
- # request.media_type # => "application/x-www-form-urlencoded"
278
+ # # get "/articles"
279
+ # request.media_type # => "application/x-www-form-urlencoded"
281
280
  def media_type
282
281
  content_mime_type&.to_s
283
282
  end
@@ -288,7 +287,7 @@ module ActionDispatch
288
287
  super.to_i
289
288
  end
290
289
 
291
- # Returns true if the +X-Requested-With+ header contains "XMLHttpRequest"
290
+ # Returns true if the `X-Requested-With` header contains "XMLHttpRequest"
292
291
  # (case-insensitive), which may need to be manually added depending on the
293
292
  # choice of JavaScript libraries and frameworks.
294
293
  def xml_http_request?
@@ -296,13 +295,13 @@ module ActionDispatch
296
295
  end
297
296
  alias :xhr? :xml_http_request?
298
297
 
299
- # Returns the IP address of client as a +String+.
298
+ # Returns the IP address of client as a `String`.
300
299
  def ip
301
300
  @ip ||= super
302
301
  end
303
302
 
304
- # Returns the IP address of client as a +String+,
305
- # usually set by the RemoteIp middleware.
303
+ # Returns the IP address of client as a `String`, usually set by the RemoteIp
304
+ # middleware.
306
305
  def remote_ip
307
306
  @remote_ip ||= (get_header("action_dispatch.remote_ip") || ip).to_s
308
307
  end
@@ -314,12 +313,14 @@ module ActionDispatch
314
313
 
315
314
  ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id" # :nodoc:
316
315
 
317
- # Returns the unique request id, which is based on either the +X-Request-Id+ header that can
318
- # be generated by a firewall, load balancer, or web server, or by the RequestId middleware
319
- # (which sets the +action_dispatch.request_id+ environment variable).
316
+ # Returns the unique request id, which is based on either the `X-Request-Id`
317
+ # header that can be generated by a firewall, load balancer, or web server, or
318
+ # by the RequestId middleware (which sets the `action_dispatch.request_id`
319
+ # environment variable).
320
320
  #
321
- # This unique ID is useful for tracing a request from end-to-end as part of logging or debugging.
322
- # This relies on the Rack variable set by the ActionDispatch::RequestId middleware.
321
+ # This unique ID is useful for tracing a request from end-to-end as part of
322
+ # logging or debugging. This relies on the Rack variable set by the
323
+ # ActionDispatch::RequestId middleware.
323
324
  def request_id
324
325
  get_header ACTION_DISPATCH_REQUEST_ID
325
326
  end
@@ -335,8 +336,8 @@ module ActionDispatch
335
336
  (get_header("SERVER_SOFTWARE") && /^([a-zA-Z]+)/ =~ get_header("SERVER_SOFTWARE")) ? $1.downcase : nil
336
337
  end
337
338
 
338
- # Read the request \body. This is useful for web services that need to
339
- # work with raw requests directly.
339
+ # Read the request body. This is useful for web services that need to work with
340
+ # raw requests directly.
340
341
  def raw_post
341
342
  unless has_header? "RAW_POST_DATA"
342
343
  set_header("RAW_POST_DATA", read_body_stream)
@@ -355,14 +356,13 @@ module ActionDispatch
355
356
  end
356
357
  end
357
358
 
358
- # Determine whether the request body contains form-data by checking
359
- # the request +Content-Type+ for one of the media-types:
360
- # +application/x-www-form-urlencoded+ or +multipart/form-data+. The
361
- # list of form-data media types can be modified through the
362
- # +FORM_DATA_MEDIA_TYPES+ array.
359
+ # Determine whether the request body contains form-data by checking the request
360
+ # `Content-Type` for one of the media-types: `application/x-www-form-urlencoded`
361
+ # or `multipart/form-data`. The list of form-data media types can be modified
362
+ # through the `FORM_DATA_MEDIA_TYPES` array.
363
363
  #
364
- # A request body is not assumed to contain form-data when no
365
- # +Content-Type+ header is provided and the request_method is POST.
364
+ # A request body is not assumed to contain form-data when no `Content-Type`
365
+ # header is provided and the request_method is POST.
366
366
  def form_data?
367
367
  FORM_DATA_MEDIA_TYPES.include?(media_type)
368
368
  end
@@ -415,8 +415,8 @@ module ActionDispatch
415
415
  end
416
416
  alias :request_parameters :POST
417
417
 
418
- # Returns the authorization header regardless of whether it was specified directly or through one of the
419
- # proxy alternatives.
418
+ # Returns the authorization header regardless of whether it was specified
419
+ # directly or through one of the proxy alternatives.
420
420
  def authorization
421
421
  get_header("HTTP_AUTHORIZATION") ||
422
422
  get_header("X-HTTP_AUTHORIZATION") ||
@@ -456,7 +456,7 @@ module ActionDispatch
456
456
  private
457
457
  def check_method(name)
458
458
  if name
459
- HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS[0...-1].join(', ')}, and #{HTTP_METHODS[-1]}")
459
+ HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(locale: false)}")
460
460
  end
461
461
 
462
462
  name
@@ -1,38 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "active_support/core_ext/module/attribute_accessors"
4
6
  require "action_dispatch/http/filter_redirect"
5
7
  require "action_dispatch/http/cache"
6
8
  require "monitor"
7
9
 
8
10
  module ActionDispatch # :nodoc:
9
- # = Action Dispatch \Response
11
+ # # Action Dispatch Response
10
12
  #
11
13
  # Represents an HTTP response generated by a controller action. Use it to
12
14
  # retrieve the current state of the response, or customize the response. It can
13
- # either represent a real HTTP response (i.e. one that is meant to be sent
14
- # back to the web browser) or a TestResponse (i.e. one that is generated
15
- # from integration tests).
15
+ # either represent a real HTTP response (i.e. one that is meant to be sent back
16
+ # to the web browser) or a TestResponse (i.e. one that is generated from
17
+ # integration tests).
16
18
  #
17
- # The \Response object for the current request is exposed on controllers as
18
- # ActionController::Metal#response. ActionController::Metal also provides a
19
- # few additional methods that delegate to attributes of the \Response such as
19
+ # The Response object for the current request is exposed on controllers as
20
+ # ActionController::Metal#response. ActionController::Metal also provides a few
21
+ # additional methods that delegate to attributes of the Response such as
20
22
  # ActionController::Metal#headers.
21
23
  #
22
- # Integration tests will likely also want to inspect responses in
23
- # more detail. Methods such as Integration::RequestHelpers#get
24
- # and Integration::RequestHelpers#post return instances of
25
- # TestResponse (which inherits from \Response) for this purpose.
24
+ # Integration tests will likely also want to inspect responses in more detail.
25
+ # Methods such as Integration::RequestHelpers#get and
26
+ # Integration::RequestHelpers#post return instances of TestResponse (which
27
+ # inherits from Response) for this purpose.
26
28
  #
27
29
  # For example, the following demo integration test prints the body of the
28
30
  # controller response to the console:
29
31
  #
30
- # class DemoControllerTest < ActionDispatch::IntegrationTest
31
- # def test_print_root_path_to_console
32
- # get('/')
33
- # puts response.body
34
- # end
35
- # end
32
+ # class DemoControllerTest < ActionDispatch::IntegrationTest
33
+ # def test_print_root_path_to_console
34
+ # get('/')
35
+ # puts response.body
36
+ # end
37
+ # end
36
38
  class Response
37
39
  begin
38
40
  # For `Rack::Headers` (Rack 3+):
@@ -44,6 +46,20 @@ module ActionDispatch # :nodoc:
44
46
  Headers = ::Rack::Utils::HeaderHash
45
47
  end
46
48
 
49
+ class << self
50
+ if ActionDispatch::Constants::UNPROCESSABLE_CONTENT == :unprocessable_content
51
+ def rack_status_code(status) # :nodoc:
52
+ status = :unprocessable_content if status == :unprocessable_entity
53
+ Rack::Utils.status_code(status)
54
+ end
55
+ else
56
+ def rack_status_code(status) # :nodoc:
57
+ status = :unprocessable_entity if status == :unprocessable_content
58
+ Rack::Utils.status_code(status)
59
+ end
60
+ end
61
+ end
62
+
47
63
  # To be deprecated:
48
64
  Header = Headers
49
65
 
@@ -55,17 +71,17 @@ module ActionDispatch # :nodoc:
55
71
 
56
72
  # The headers for the response.
57
73
  #
58
- # header["Content-Type"] # => "text/plain"
59
- # header["Content-Type"] = "application/json"
60
- # header["Content-Type"] # => "application/json"
74
+ # header["Content-Type"] # => "text/plain"
75
+ # header["Content-Type"] = "application/json"
76
+ # header["Content-Type"] # => "application/json"
61
77
  #
62
- # Also aliased as +headers+.
78
+ # Also aliased as `headers`.
63
79
  #
64
- # headers["Content-Type"] # => "text/plain"
65
- # headers["Content-Type"] = "application/json"
66
- # headers["Content-Type"] # => "application/json"
80
+ # headers["Content-Type"] # => "text/plain"
81
+ # headers["Content-Type"] = "application/json"
82
+ # headers["Content-Type"] # => "application/json"
67
83
  #
68
- # Also aliased as +header+ for compatibility.
84
+ # Also aliased as `header` for compatibility.
69
85
  attr_reader :headers
70
86
 
71
87
  alias_method :header, :headers
@@ -229,18 +245,30 @@ module ActionDispatch # :nodoc:
229
245
  def committed?; synchronize { @committed }; end
230
246
  def sent?; synchronize { @sent }; end
231
247
 
248
+ ##
249
+ # :method: location
250
+ #
251
+ # Location of the response.
252
+
253
+ ##
254
+ # :method: location=
255
+ #
256
+ # :call-seq: location=(location)
257
+ #
258
+ # Sets the location of the response
259
+
232
260
  # Sets the HTTP status code.
233
261
  def status=(status)
234
- @status = Rack::Utils.status_code(status)
262
+ @status = Response.rack_status_code(status)
235
263
  end
236
264
 
237
- # Sets the HTTP response's content MIME type. For example, in the controller
238
- # you could write this:
265
+ # Sets the HTTP response's content MIME type. For example, in the controller you
266
+ # could write this:
239
267
  #
240
- # response.content_type = "text/plain"
268
+ # response.content_type = "text/plain"
241
269
  #
242
- # If a character set has been defined for this response (see charset=) then
243
- # the character set information will also be included in the content type
270
+ # If a character set has been defined for this response (see #charset=) then the
271
+ # character set information will also be included in the content type
244
272
  # information.
245
273
  def content_type=(content_type)
246
274
  return unless content_type
@@ -267,11 +295,11 @@ module ActionDispatch # :nodoc:
267
295
  end
268
296
  end
269
297
 
270
- # Sets the HTTP character set. In case of +nil+ parameter
271
- # it sets the charset to +default_charset+.
298
+ # Sets the HTTP character set. In case of `nil` parameter it sets the charset to
299
+ # `default_charset`.
272
300
  #
273
- # response.charset = 'utf-16' # => 'utf-16'
274
- # response.charset = nil # => 'utf-8'
301
+ # response.charset = 'utf-16' # => 'utf-16'
302
+ # response.charset = nil # => 'utf-8'
275
303
  def charset=(charset)
276
304
  content_type = parsed_content_type_header.mime_type
277
305
  if false == charset
@@ -281,8 +309,8 @@ module ActionDispatch # :nodoc:
281
309
  end
282
310
  end
283
311
 
284
- # The charset of the response. HTML wants to know the encoding of the
285
- # content you're giving them, so we need to send that along.
312
+ # The charset of the response. HTML wants to know the encoding of the content
313
+ # you're giving them, so we need to send that along.
286
314
  def charset
287
315
  header_info = parsed_content_type_header
288
316
  header_info.charset || self.class.default_charset
@@ -293,26 +321,26 @@ module ActionDispatch # :nodoc:
293
321
  @status
294
322
  end
295
323
 
296
- # Returns a string to ensure compatibility with +Net::HTTPResponse+.
324
+ # Returns a string to ensure compatibility with `Net::HTTPResponse`.
297
325
  def code
298
326
  @status.to_s
299
327
  end
300
328
 
301
329
  # Returns the corresponding message for the current HTTP status code:
302
330
  #
303
- # response.status = 200
304
- # response.message # => "OK"
331
+ # response.status = 200
332
+ # response.message # => "OK"
305
333
  #
306
- # response.status = 404
307
- # response.message # => "Not Found"
334
+ # response.status = 404
335
+ # response.message # => "Not Found"
308
336
  #
309
337
  def message
310
338
  Rack::Utils::HTTP_STATUS_CODES[@status]
311
339
  end
312
340
  alias_method :status_message, :message
313
341
 
314
- # Returns the content of the response as a string. This contains the contents
315
- # of any calls to <tt>render</tt>.
342
+ # Returns the content of the response as a string. This contains the contents of
343
+ # any calls to `render`.
316
344
  def body
317
345
  @stream.body
318
346
  end
@@ -332,9 +360,9 @@ module ActionDispatch # :nodoc:
332
360
  end
333
361
  end
334
362
 
335
- # Avoid having to pass an open file handle as the response body.
336
- # Rack::Sendfile will usually intercept the response and uses
337
- # the path directly, so there is no reason to open the file.
363
+ # Avoid having to pass an open file handle as the response body. Rack::Sendfile
364
+ # will usually intercept the response and uses the path directly, so there is no
365
+ # reason to open the file.
338
366
  class FileBody # :nodoc:
339
367
  attr_reader :to_path
340
368
 
@@ -356,7 +384,7 @@ module ActionDispatch # :nodoc:
356
384
  end
357
385
  end
358
386
 
359
- # Send the file stored at +path+ as the response body.
387
+ # Send the file stored at `path` as the response body.
360
388
  def send_file(path)
361
389
  commit!
362
390
  @stream = FileBody.new(path)
@@ -383,17 +411,16 @@ module ActionDispatch # :nodoc:
383
411
  if stream.respond_to?(:abort)
384
412
  stream.abort
385
413
  elsif stream.respond_to?(:close)
386
- # `stream.close` should really be reserved for a close from the
387
- # other direction, but we must fall back to it for
388
- # compatibility.
414
+ # `stream.close` should really be reserved for a close from the other direction,
415
+ # but we must fall back to it for compatibility.
389
416
  stream.close
390
417
  end
391
418
  end
392
419
 
393
- # Turns the Response into a Rack-compatible array of the status, headers,
394
- # and body. Allows explicit splatting:
420
+ # Turns the Response into a Rack-compatible array of the status, headers, and
421
+ # body. Allows explicit splatting:
395
422
  #
396
- # status, headers, body = *response
423
+ # status, headers, body = *response
397
424
  def to_a
398
425
  commit!
399
426
  rack_response @status, @headers.to_hash
@@ -402,7 +429,7 @@ module ActionDispatch # :nodoc:
402
429
 
403
430
  # Returns the response cookies, converted to a Hash of (name => value) pairs
404
431
  #
405
- # assert_equal 'AuthorOfNewPage', r.cookies['author']
432
+ # assert_equal 'AuthorOfNewPage', r.cookies['author']
406
433
  def cookies
407
434
  cookies = {}
408
435
  if header = get_header(SET_COOKIE)
@@ -456,11 +483,10 @@ module ActionDispatch # :nodoc:
456
483
  end
457
484
 
458
485
  def before_sending
459
- # Normally we've already committed by now, but it's possible
460
- # (e.g., if the controller action tries to read back its own
461
- # response) to get here before that. In that case, we must force
462
- # an "early" commit: we're about to freeze the headers, so this is
463
- # our last chance.
486
+ # Normally we've already committed by now, but it's possible (e.g., if the
487
+ # controller action tries to read back its own response) to get here before
488
+ # that. In that case, we must force an "early" commit: we're about to freeze the
489
+ # headers, so this is our last chance.
464
490
  commit! unless committed?
465
491
 
466
492
  @request.commit_cookie_jar! unless committed?
@@ -488,8 +514,8 @@ module ActionDispatch # :nodoc:
488
514
  end
489
515
 
490
516
  def close
491
- # Rack "close" maps to Response#abort, and *not* Response#close
492
- # (which is used when the controller's finished writing)
517
+ # Rack "close" maps to Response#abort, and **not** Response#close (which is used
518
+ # when the controller's finished writing)
493
519
  @response.abort
494
520
  end
495
521