actionpack 7.1.3 → 7.2.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +82 -501
  3. data/lib/abstract_controller/asset_paths.rb +2 -0
  4. data/lib/abstract_controller/base.rb +102 -98
  5. data/lib/abstract_controller/caching/fragments.rb +50 -53
  6. data/lib/abstract_controller/caching.rb +2 -0
  7. data/lib/abstract_controller/callbacks.rb +66 -64
  8. data/lib/abstract_controller/collector.rb +6 -6
  9. data/lib/abstract_controller/deprecator.rb +2 -0
  10. data/lib/abstract_controller/error.rb +2 -0
  11. data/lib/abstract_controller/helpers.rb +70 -85
  12. data/lib/abstract_controller/logger.rb +2 -0
  13. data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
  14. data/lib/abstract_controller/rendering.rb +13 -12
  15. data/lib/abstract_controller/translation.rb +15 -7
  16. data/lib/abstract_controller/url_for.rb +8 -6
  17. data/lib/abstract_controller.rb +2 -0
  18. data/lib/action_controller/api/api_rendering.rb +2 -0
  19. data/lib/action_controller/api.rb +74 -72
  20. data/lib/action_controller/base.rb +198 -126
  21. data/lib/action_controller/caching.rb +15 -12
  22. data/lib/action_controller/deprecator.rb +2 -0
  23. data/lib/action_controller/form_builder.rb +20 -17
  24. data/lib/action_controller/log_subscriber.rb +3 -1
  25. data/lib/action_controller/metal/allow_browser.rb +123 -0
  26. data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
  27. data/lib/action_controller/metal/conditional_get.rb +188 -174
  28. data/lib/action_controller/metal/content_security_policy.rb +25 -24
  29. data/lib/action_controller/metal/cookies.rb +4 -2
  30. data/lib/action_controller/metal/data_streaming.rb +64 -55
  31. data/lib/action_controller/metal/default_headers.rb +5 -3
  32. data/lib/action_controller/metal/etag_with_flash.rb +3 -1
  33. data/lib/action_controller/metal/etag_with_template_digest.rb +17 -15
  34. data/lib/action_controller/metal/exceptions.rb +11 -9
  35. data/lib/action_controller/metal/flash.rb +12 -10
  36. data/lib/action_controller/metal/head.rb +12 -10
  37. data/lib/action_controller/metal/helpers.rb +63 -55
  38. data/lib/action_controller/metal/http_authentication.rb +210 -205
  39. data/lib/action_controller/metal/implicit_render.rb +17 -15
  40. data/lib/action_controller/metal/instrumentation.rb +15 -12
  41. data/lib/action_controller/metal/live.rb +113 -107
  42. data/lib/action_controller/metal/logging.rb +6 -4
  43. data/lib/action_controller/metal/mime_responds.rb +151 -142
  44. data/lib/action_controller/metal/parameter_encoding.rb +34 -32
  45. data/lib/action_controller/metal/params_wrapper.rb +57 -59
  46. data/lib/action_controller/metal/permissions_policy.rb +13 -12
  47. data/lib/action_controller/metal/rate_limiting.rb +62 -0
  48. data/lib/action_controller/metal/redirecting.rb +108 -82
  49. data/lib/action_controller/metal/renderers.rb +50 -49
  50. data/lib/action_controller/metal/rendering.rb +103 -75
  51. data/lib/action_controller/metal/request_forgery_protection.rb +162 -133
  52. data/lib/action_controller/metal/rescue.rb +11 -9
  53. data/lib/action_controller/metal/streaming.rb +138 -136
  54. data/lib/action_controller/metal/strong_parameters.rb +525 -480
  55. data/lib/action_controller/metal/testing.rb +2 -0
  56. data/lib/action_controller/metal/url_for.rb +17 -15
  57. data/lib/action_controller/metal.rb +86 -60
  58. data/lib/action_controller/railtie.rb +3 -0
  59. data/lib/action_controller/railties/helpers.rb +2 -0
  60. data/lib/action_controller/renderer.rb +42 -36
  61. data/lib/action_controller/template_assertions.rb +4 -2
  62. data/lib/action_controller/test_case.rb +146 -126
  63. data/lib/action_controller.rb +10 -3
  64. data/lib/action_dispatch/constants.rb +2 -0
  65. data/lib/action_dispatch/deprecator.rb +2 -0
  66. data/lib/action_dispatch/http/cache.rb +27 -26
  67. data/lib/action_dispatch/http/content_disposition.rb +2 -0
  68. data/lib/action_dispatch/http/content_security_policy.rb +44 -38
  69. data/lib/action_dispatch/http/filter_parameters.rb +18 -9
  70. data/lib/action_dispatch/http/filter_redirect.rb +22 -1
  71. data/lib/action_dispatch/http/headers.rb +22 -22
  72. data/lib/action_dispatch/http/mime_negotiation.rb +30 -41
  73. data/lib/action_dispatch/http/mime_type.rb +31 -24
  74. data/lib/action_dispatch/http/mime_types.rb +2 -0
  75. data/lib/action_dispatch/http/parameters.rb +11 -9
  76. data/lib/action_dispatch/http/permissions_policy.rb +20 -44
  77. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  78. data/lib/action_dispatch/http/request.rb +94 -75
  79. data/lib/action_dispatch/http/response.rb +73 -61
  80. data/lib/action_dispatch/http/upload.rb +18 -16
  81. data/lib/action_dispatch/http/url.rb +75 -73
  82. data/lib/action_dispatch/journey/formatter.rb +13 -6
  83. data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
  84. data/lib/action_dispatch/journey/gtg/simulator.rb +2 -0
  85. data/lib/action_dispatch/journey/gtg/transition_table.rb +10 -8
  86. data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
  87. data/lib/action_dispatch/journey/nodes/node.rb +6 -5
  88. data/lib/action_dispatch/journey/parser.rb +4 -3
  89. data/lib/action_dispatch/journey/parser_extras.rb +2 -0
  90. data/lib/action_dispatch/journey/path/pattern.rb +4 -1
  91. data/lib/action_dispatch/journey/route.rb +9 -7
  92. data/lib/action_dispatch/journey/router/utils.rb +16 -15
  93. data/lib/action_dispatch/journey/router.rb +4 -2
  94. data/lib/action_dispatch/journey/routes.rb +4 -2
  95. data/lib/action_dispatch/journey/scanner.rb +4 -2
  96. data/lib/action_dispatch/journey/visitors.rb +2 -0
  97. data/lib/action_dispatch/journey.rb +2 -0
  98. data/lib/action_dispatch/log_subscriber.rb +2 -0
  99. data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -0
  100. data/lib/action_dispatch/middleware/assume_ssl.rb +8 -5
  101. data/lib/action_dispatch/middleware/callbacks.rb +3 -1
  102. data/lib/action_dispatch/middleware/cookies.rb +119 -104
  103. data/lib/action_dispatch/middleware/debug_exceptions.rb +13 -5
  104. data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
  105. data/lib/action_dispatch/middleware/debug_view.rb +2 -0
  106. data/lib/action_dispatch/middleware/exception_wrapper.rb +6 -11
  107. data/lib/action_dispatch/middleware/executor.rb +8 -0
  108. data/lib/action_dispatch/middleware/flash.rb +63 -51
  109. data/lib/action_dispatch/middleware/host_authorization.rb +17 -15
  110. data/lib/action_dispatch/middleware/public_exceptions.rb +8 -6
  111. data/lib/action_dispatch/middleware/reloader.rb +5 -3
  112. data/lib/action_dispatch/middleware/remote_ip.rb +77 -72
  113. data/lib/action_dispatch/middleware/request_id.rb +14 -9
  114. data/lib/action_dispatch/middleware/server_timing.rb +4 -2
  115. data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -0
  116. data/lib/action_dispatch/middleware/session/cache_store.rb +13 -8
  117. data/lib/action_dispatch/middleware/session/cookie_store.rb +27 -26
  118. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -3
  119. data/lib/action_dispatch/middleware/show_exceptions.rb +31 -21
  120. data/lib/action_dispatch/middleware/ssl.rb +43 -40
  121. data/lib/action_dispatch/middleware/stack.rb +11 -10
  122. data/lib/action_dispatch/middleware/static.rb +33 -31
  123. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +1 -1
  124. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.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 -4
  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 +671 -636
  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 +10 -3
  140. data/lib/action_dispatch/system_testing/driver.rb +3 -1
  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 +8 -6
  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 +223 -222
  149. data/lib/action_dispatch/testing/request_encoder.rb +2 -0
  150. data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
  151. data/lib/action_dispatch/testing/test_process.rb +12 -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 +6 -4
  156. data/lib/action_pack/version.rb +3 -1
  157. data/lib/action_pack.rb +17 -16
  158. metadata +39 -16
@@ -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
@@ -66,8 +68,8 @@ module ActionDispatch
66
68
  delete_header("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
75
  set_header PARAMETERS_KEY, parameters
@@ -75,10 +77,10 @@ module ActionDispatch
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
85
  get_header(PARAMETERS_KEY) || set_header(PARAMETERS_KEY, {})
84
86
  end
@@ -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)
@@ -35,7 +37,6 @@ module ActionDispatch # :nodoc:
35
37
  def call(env)
36
38
  _, headers, _ = response = @app.call(env)
37
39
 
38
- return response unless html_response?(headers)
39
40
  return response if policy_present?(headers)
40
41
 
41
42
  request = ActionDispatch::Request.new(env)
@@ -52,12 +53,6 @@ module ActionDispatch # :nodoc:
52
53
  end
53
54
 
54
55
  private
55
- def html_response?(headers)
56
- if content_type = headers[Rack::CONTENT_TYPE]
57
- content_type.include?("html")
58
- end
59
- end
60
-
61
56
  def policy_present?(headers)
62
57
  headers[ActionDispatch::Constants::FEATURE_POLICY]
63
58
  end
@@ -96,7 +91,7 @@ module ActionDispatch # :nodoc:
96
91
  geolocation: "geolocation",
97
92
  gyroscope: "gyroscope",
98
93
  hid: "hid",
99
- idle_detection: "idle_detection",
94
+ idle_detection: "idle-detection",
100
95
  magnetometer: "magnetometer",
101
96
  microphone: "microphone",
102
97
  midi: "midi",
@@ -132,25 +127,6 @@ module ActionDispatch # :nodoc:
132
127
  end
133
128
  end
134
129
 
135
- %w[speaker vibrate vr].each do |directive|
136
- define_method(directive) do |*sources|
137
- ActionDispatch.deprecator.warn(<<~MSG)
138
- The `#{directive}` permissions policy directive is deprecated
139
- and will be removed in Rails 7.2.
140
-
141
- There is no browser support for this directive, and no plan
142
- for browser support in the future. You can just remove this
143
- directive from your application.
144
- MSG
145
-
146
- if sources.first
147
- @directives[directive] = apply_mappings(sources)
148
- else
149
- @directives.delete(directive)
150
- end
151
- end
152
- end
153
-
154
130
  def build(context = nil)
155
131
  build_directives(context).compact.join("; ")
156
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
@@ -135,20 +137,19 @@ module ActionDispatch
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,62 +221,61 @@ 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 Link headers.
232
+ # If the env contains `rack.early_hints` then the server accepts HTTP2 push for
233
+ # link headers.
233
234
  #
234
- # 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:
235
236
  #
236
- # send_early_hints("Link" => "</style.css>; rel=preload; as=style\n</script.js>; rel=preload")
237
+ # send_early_hints("link" => "</style.css>; rel=preload; as=style,</script.js>; rel=preload")
237
238
  #
238
- # If you are using +javascript_include_tag+ or +stylesheet_link_tag+ the
239
- # Early Hints headers are included by default if supported.
239
+ # If you are using `javascript_include_tag` or `stylesheet_link_tag` the Early
240
+ # Hints headers are included by default if supported.
240
241
  def send_early_hints(links)
241
- return unless env["rack.early_hints"]
242
-
243
- env["rack.early_hints"].call(links)
242
+ env["rack.early_hints"]&.call(links)
244
243
  end
245
244
 
246
- # Returns a +String+ with the last requested path including their params.
245
+ # Returns a `String` with the last requested path including their params.
247
246
  #
248
- # # get '/foo'
249
- # request.original_fullpath # => '/foo'
247
+ # # get '/foo'
248
+ # request.original_fullpath # => '/foo'
250
249
  #
251
- # # get '/foo?bar'
252
- # request.original_fullpath # => '/foo?bar'
250
+ # # get '/foo?bar'
251
+ # request.original_fullpath # => '/foo?bar'
253
252
  def original_fullpath
254
253
  @original_fullpath ||= (get_header("ORIGINAL_FULLPATH") || fullpath)
255
254
  end
256
255
 
257
- # Returns the +String+ full path including params of the last URL requested.
256
+ # Returns the `String` full path including params of the last URL requested.
258
257
  #
259
- # # get "/articles"
260
- # request.fullpath # => "/articles"
258
+ # # get "/articles"
259
+ # request.fullpath # => "/articles"
261
260
  #
262
- # # get "/articles?page=2"
263
- # request.fullpath # => "/articles?page=2"
261
+ # # get "/articles?page=2"
262
+ # request.fullpath # => "/articles?page=2"
264
263
  def fullpath
265
264
  @fullpath ||= super
266
265
  end
267
266
 
268
- # Returns the original request URL as a +String+.
267
+ # Returns the original request URL as a `String`.
269
268
  #
270
- # # get "/articles?page=2"
271
- # request.original_url # => "http://www.example.com/articles?page=2"
269
+ # # get "/articles?page=2"
270
+ # request.original_url # => "http://www.example.com/articles?page=2"
272
271
  def original_url
273
272
  base_url + original_fullpath
274
273
  end
275
274
 
276
- # The +String+ MIME type of the request.
275
+ # The `String` MIME type of the request.
277
276
  #
278
- # # get "/articles"
279
- # request.media_type # => "application/x-www-form-urlencoded"
277
+ # # get "/articles"
278
+ # request.media_type # => "application/x-www-form-urlencoded"
280
279
  def media_type
281
280
  content_mime_type&.to_s
282
281
  end
@@ -287,7 +286,7 @@ module ActionDispatch
287
286
  super.to_i
288
287
  end
289
288
 
290
- # Returns true if the +X-Requested-With+ header contains "XMLHttpRequest"
289
+ # Returns true if the `X-Requested-With` header contains "XMLHttpRequest"
291
290
  # (case-insensitive), which may need to be manually added depending on the
292
291
  # choice of JavaScript libraries and frameworks.
293
292
  def xml_http_request?
@@ -295,13 +294,13 @@ module ActionDispatch
295
294
  end
296
295
  alias :xhr? :xml_http_request?
297
296
 
298
- # Returns the IP address of client as a +String+.
297
+ # Returns the IP address of client as a `String`.
299
298
  def ip
300
299
  @ip ||= super
301
300
  end
302
301
 
303
- # Returns the IP address of client as a +String+,
304
- # usually set by the RemoteIp middleware.
302
+ # Returns the IP address of client as a `String`, usually set by the RemoteIp
303
+ # middleware.
305
304
  def remote_ip
306
305
  @remote_ip ||= (get_header("action_dispatch.remote_ip") || ip).to_s
307
306
  end
@@ -313,12 +312,14 @@ module ActionDispatch
313
312
 
314
313
  ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id" # :nodoc:
315
314
 
316
- # Returns the unique request id, which is based on either the +X-Request-Id+ header that can
317
- # be generated by a firewall, load balancer, or web server, or by the RequestId middleware
318
- # (which sets the +action_dispatch.request_id+ environment variable).
315
+ # Returns the unique request id, which is based on either the `X-Request-Id`
316
+ # header that can be generated by a firewall, load balancer, or web server, or
317
+ # by the RequestId middleware (which sets the `action_dispatch.request_id`
318
+ # environment variable).
319
319
  #
320
- # This unique ID is useful for tracing a request from end-to-end as part of logging or debugging.
321
- # This relies on the Rack variable set by the ActionDispatch::RequestId middleware.
320
+ # This unique ID is useful for tracing a request from end-to-end as part of
321
+ # logging or debugging. This relies on the Rack variable set by the
322
+ # ActionDispatch::RequestId middleware.
322
323
  def request_id
323
324
  get_header ACTION_DISPATCH_REQUEST_ID
324
325
  end
@@ -334,12 +335,11 @@ module ActionDispatch
334
335
  (get_header("SERVER_SOFTWARE") && /^([a-zA-Z]+)/ =~ get_header("SERVER_SOFTWARE")) ? $1.downcase : nil
335
336
  end
336
337
 
337
- # Read the request \body. This is useful for web services that need to
338
- # work with raw requests directly.
338
+ # Read the request body. This is useful for web services that need to work with
339
+ # raw requests directly.
339
340
  def raw_post
340
341
  unless has_header? "RAW_POST_DATA"
341
342
  set_header("RAW_POST_DATA", read_body_stream)
342
- body_stream.rewind if body_stream.respond_to?(:rewind)
343
343
  end
344
344
  get_header "RAW_POST_DATA"
345
345
  end
@@ -355,14 +355,13 @@ module ActionDispatch
355
355
  end
356
356
  end
357
357
 
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.
358
+ # Determine whether the request body contains form-data by checking the request
359
+ # `Content-Type` for one of the media-types: `application/x-www-form-urlencoded`
360
+ # or `multipart/form-data`. The list of form-data media types can be modified
361
+ # through the `FORM_DATA_MEDIA_TYPES` array.
363
362
  #
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.
363
+ # A request body is not assumed to contain form-data when no `Content-Type`
364
+ # header is provided and the request_method is POST.
366
365
  def form_data?
367
366
  FORM_DATA_MEDIA_TYPES.include?(media_type)
368
367
  end
@@ -415,8 +414,8 @@ module ActionDispatch
415
414
  end
416
415
  alias :request_parameters :POST
417
416
 
418
- # Returns the authorization header regardless of whether it was specified directly or through one of the
419
- # proxy alternatives.
417
+ # Returns the authorization header regardless of whether it was specified
418
+ # directly or through one of the proxy alternatives.
420
419
  def authorization
421
420
  get_header("HTTP_AUTHORIZATION") ||
422
421
  get_header("X-HTTP_AUTHORIZATION") ||
@@ -456,7 +455,7 @@ module ActionDispatch
456
455
  private
457
456
  def check_method(name)
458
457
  if name
459
- HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS[0...-1].join(', ')}, and #{HTTP_METHODS[-1]}")
458
+ HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(locale: false)}")
460
459
  end
461
460
 
462
461
  name
@@ -467,9 +466,29 @@ module ActionDispatch
467
466
  end
468
467
 
469
468
  def read_body_stream
470
- body_stream.rewind if body_stream.respond_to?(:rewind)
471
- return body_stream.read if headers.key?("Transfer-Encoding") # Read body stream until EOF if "Transfer-Encoding" is present
472
- body_stream.read(content_length)
469
+ if body_stream
470
+ reset_stream(body_stream) do
471
+ if headers.key?("Transfer-Encoding")
472
+ body_stream.read # Read body stream until EOF if "Transfer-Encoding" is present
473
+ else
474
+ body_stream.read(content_length)
475
+ end
476
+ end
477
+ end
478
+ end
479
+
480
+ def reset_stream(body_stream)
481
+ if body_stream.respond_to?(:rewind)
482
+ body_stream.rewind
483
+
484
+ content = yield
485
+
486
+ body_stream.rewind
487
+
488
+ content
489
+ else
490
+ yield
491
+ end
473
492
  end
474
493
  end
475
494
  end