actionpack 7.1.5.1 → 7.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (157) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +61 -642
  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 +12 -13
  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 +155 -117
  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 +119 -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 +214 -203
  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 +483 -478
  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 +58 -57
  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 +5 -1
  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 +48 -59
  69. data/lib/action_dispatch/http/filter_parameters.rb +13 -14
  70. data/lib/action_dispatch/http/filter_redirect.rb +15 -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 +25 -21
  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 +26 -36
  77. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  78. data/lib/action_dispatch/http/request.rb +75 -95
  79. data/lib/action_dispatch/http/response.rb +61 -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 +2 -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 +16 -16
  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/routes/_table.html.erb +1 -1
  125. data/lib/action_dispatch/railtie.rb +2 -3
  126. data/lib/action_dispatch/request/session.rb +23 -21
  127. data/lib/action_dispatch/request/utils.rb +2 -0
  128. data/lib/action_dispatch/routing/endpoint.rb +2 -0
  129. data/lib/action_dispatch/routing/inspector.rb +6 -4
  130. data/lib/action_dispatch/routing/mapper.rb +623 -625
  131. data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
  132. data/lib/action_dispatch/routing/redirection.rb +37 -32
  133. data/lib/action_dispatch/routing/route_set.rb +60 -46
  134. data/lib/action_dispatch/routing/routes_proxy.rb +6 -4
  135. data/lib/action_dispatch/routing/url_for.rb +130 -125
  136. data/lib/action_dispatch/routing.rb +150 -148
  137. data/lib/action_dispatch/system_test_case.rb +91 -81
  138. data/lib/action_dispatch/system_testing/browser.rb +4 -2
  139. data/lib/action_dispatch/system_testing/driver.rb +2 -0
  140. data/lib/action_dispatch/system_testing/server.rb +2 -0
  141. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +32 -21
  142. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
  143. data/lib/action_dispatch/testing/assertion_response.rb +8 -6
  144. data/lib/action_dispatch/testing/assertions/response.rb +26 -23
  145. data/lib/action_dispatch/testing/assertions/routing.rb +153 -84
  146. data/lib/action_dispatch/testing/assertions.rb +2 -0
  147. data/lib/action_dispatch/testing/integration.rb +223 -222
  148. data/lib/action_dispatch/testing/request_encoder.rb +2 -0
  149. data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
  150. data/lib/action_dispatch/testing/test_process.rb +12 -8
  151. data/lib/action_dispatch/testing/test_request.rb +3 -1
  152. data/lib/action_dispatch/testing/test_response.rb +27 -26
  153. data/lib/action_dispatch.rb +22 -32
  154. data/lib/action_pack/gem_version.rb +6 -4
  155. data/lib/action_pack/version.rb +3 -1
  156. data/lib/action_pack.rb +17 -16
  157. metadata +33 -16
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "active_support/core_ext/hash/keys"
4
6
  require "active_support/key_generator"
5
7
  require "active_support/message_verifier"
@@ -94,97 +96,100 @@ module ActionDispatch
94
96
 
95
97
  # Read and write data to cookies through ActionController::Cookies#cookies.
96
98
  #
97
- # When reading cookie data, the data is read from the HTTP request header, Cookie.
98
- # When writing cookie data, the data is sent out in the HTTP response header, +Set-Cookie+.
99
+ # When reading cookie data, the data is read from the HTTP request header,
100
+ # Cookie. When writing cookie data, the data is sent out in the HTTP response
101
+ # header, `Set-Cookie`.
99
102
  #
100
103
  # Examples of writing:
101
104
  #
102
- # # Sets a simple session cookie.
103
- # # This cookie will be deleted when the user's browser is closed.
104
- # cookies[:user_name] = "david"
105
+ # # Sets a simple session cookie.
106
+ # # This cookie will be deleted when the user's browser is closed.
107
+ # cookies[:user_name] = "david"
105
108
  #
106
- # # Cookie values are String-based. Other data types need to be serialized.
107
- # cookies[:lat_lon] = JSON.generate([47.68, -122.37])
109
+ # # Cookie values are String-based. Other data types need to be serialized.
110
+ # cookies[:lat_lon] = JSON.generate([47.68, -122.37])
108
111
  #
109
- # # Sets a cookie that expires in 1 hour.
110
- # cookies[:login] = { value: "XJ-122", expires: 1.hour }
112
+ # # Sets a cookie that expires in 1 hour.
113
+ # cookies[:login] = { value: "XJ-122", expires: 1.hour }
111
114
  #
112
- # # Sets a cookie that expires at a specific time.
113
- # cookies[:login] = { value: "XJ-122", expires: Time.utc(2020, 10, 15, 5) }
115
+ # # Sets a cookie that expires at a specific time.
116
+ # cookies[:login] = { value: "XJ-122", expires: Time.utc(2020, 10, 15, 5) }
114
117
  #
115
- # # Sets a signed cookie, which prevents users from tampering with its value.
116
- # # It can be read using the signed method `cookies.signed[:name]`
117
- # cookies.signed[:user_id] = current_user.id
118
+ # # Sets a signed cookie, which prevents users from tampering with its value.
119
+ # # It can be read using the signed method `cookies.signed[:name]`
120
+ # cookies.signed[:user_id] = current_user.id
118
121
  #
119
- # # Sets an encrypted cookie value before sending it to the client which
120
- # # prevent users from reading and tampering with its value.
121
- # # It can be read using the encrypted method `cookies.encrypted[:name]`
122
- # cookies.encrypted[:discount] = 45
122
+ # # Sets an encrypted cookie value before sending it to the client which
123
+ # # prevent users from reading and tampering with its value.
124
+ # # It can be read using the encrypted method `cookies.encrypted[:name]`
125
+ # cookies.encrypted[:discount] = 45
123
126
  #
124
- # # Sets a "permanent" cookie (which expires in 20 years from now).
125
- # cookies.permanent[:login] = "XJ-122"
127
+ # # Sets a "permanent" cookie (which expires in 20 years from now).
128
+ # cookies.permanent[:login] = "XJ-122"
126
129
  #
127
- # # You can also chain these methods:
128
- # cookies.signed.permanent[:login] = "XJ-122"
130
+ # # You can also chain these methods:
131
+ # cookies.signed.permanent[:login] = "XJ-122"
129
132
  #
130
133
  # Examples of reading:
131
134
  #
132
- # cookies[:user_name] # => "david"
133
- # cookies.size # => 2
134
- # JSON.parse(cookies[:lat_lon]) # => [47.68, -122.37]
135
- # cookies.signed[:login] # => "XJ-122"
136
- # cookies.encrypted[:discount] # => 45
135
+ # cookies[:user_name] # => "david"
136
+ # cookies.size # => 2
137
+ # JSON.parse(cookies[:lat_lon]) # => [47.68, -122.37]
138
+ # cookies.signed[:login] # => "XJ-122"
139
+ # cookies.encrypted[:discount] # => 45
137
140
  #
138
141
  # Example for deleting:
139
142
  #
140
- # cookies.delete :user_name
143
+ # cookies.delete :user_name
141
144
  #
142
- # Please note that if you specify a +:domain+ when setting a cookie, you must also specify the domain when deleting the cookie:
145
+ # Please note that if you specify a `:domain` when setting a cookie, you must
146
+ # also specify the domain when deleting the cookie:
143
147
  #
144
- # cookies[:name] = {
145
- # value: 'a yummy cookie',
146
- # expires: 1.year,
147
- # domain: 'domain.com'
148
- # }
148
+ # cookies[:name] = {
149
+ # value: 'a yummy cookie',
150
+ # expires: 1.year,
151
+ # domain: 'domain.com'
152
+ # }
149
153
  #
150
- # cookies.delete(:name, domain: 'domain.com')
154
+ # cookies.delete(:name, domain: 'domain.com')
151
155
  #
152
156
  # The option symbols for setting cookies are:
153
157
  #
154
- # * <tt>:value</tt> - The cookie's value.
155
- # * <tt>:path</tt> - The path for which this cookie applies. Defaults to the root
156
- # of the application.
157
- # * <tt>:domain</tt> - The domain for which this cookie applies so you can
158
- # restrict to the domain level. If you use a schema like www.example.com
159
- # and want to share session with user.example.com set <tt>:domain</tt>
160
- # to <tt>:all</tt>. To support multiple domains, provide an array, and
161
- # the first domain matching <tt>request.host</tt> will be used. Make
162
- # sure to specify the <tt>:domain</tt> option with <tt>:all</tt> or
163
- # <tt>Array</tt> again when deleting cookies. For more flexibility you
164
- # can set the domain on a per-request basis by specifying <tt>:domain</tt>
165
- # with a proc.
158
+ # * `:value` - The cookie's value.
159
+ # * `:path` - The path for which this cookie applies. Defaults to the root of
160
+ # the application.
161
+ # * `:domain` - The domain for which this cookie applies so you can restrict
162
+ # to the domain level. If you use a schema like www.example.com and want to
163
+ # share session with user.example.com set `:domain` to `:all`. To support
164
+ # multiple domains, provide an array, and the first domain matching
165
+ # `request.host` will be used. Make sure to specify the `:domain` option
166
+ # with `:all` or `Array` again when deleting cookies. For more flexibility
167
+ # you can set the domain on a per-request basis by specifying `:domain` with
168
+ # a proc.
166
169
  #
167
- # domain: nil # Does not set cookie domain. (default)
168
- # domain: :all # Allow the cookie for the top most level
169
- # # domain and subdomains.
170
- # domain: %w(.example.com .example.org) # Allow the cookie
171
- # # for concrete domain names.
172
- # domain: proc { Tenant.current.cookie_domain } # Set cookie domain dynamically
173
- # domain: proc { |req| ".sub.#{req.host}" } # Set cookie domain dynamically based on request
170
+ # domain: nil # Does not set cookie domain. (default)
171
+ # domain: :all # Allow the cookie for the top most level
172
+ # # domain and subdomains.
173
+ # domain: %w(.example.com .example.org) # Allow the cookie
174
+ # # for concrete domain names.
175
+ # domain: proc { Tenant.current.cookie_domain } # Set cookie domain dynamically
176
+ # domain: proc { |req| ".sub.#{req.host}" } # Set cookie domain dynamically based on request
174
177
  #
178
+ # * `:tld_length` - When using `:domain => :all`, this option can be used to
179
+ # explicitly set the TLD length when using a short (<= 3 character) domain
180
+ # that is being interpreted as part of a TLD. For example, to share cookies
181
+ # between user1.lvh.me and user2.lvh.me, set `:tld_length` to 2.
182
+ # * `:expires` - The time at which this cookie expires, as a Time or
183
+ # ActiveSupport::Duration object.
184
+ # * `:secure` - Whether this cookie is only transmitted to HTTPS servers.
185
+ # Default is `false`.
186
+ # * `:httponly` - Whether this cookie is accessible via scripting or only
187
+ # HTTP. Defaults to `false`.
188
+ # * `:same_site` - The value of the `SameSite` cookie attribute, which
189
+ # determines how this cookie should be restricted in cross-site contexts.
190
+ # Possible values are `nil`, `:none`, `:lax`, and `:strict`. Defaults to
191
+ # `:lax`.
175
192
  #
176
- # * <tt>:tld_length</tt> - When using <tt>:domain => :all</tt>, this option can be used to explicitly
177
- # set the TLD length when using a short (<= 3 character) domain that is being interpreted as part of a TLD.
178
- # For example, to share cookies between user1.lvh.me and user2.lvh.me, set <tt>:tld_length</tt> to 2.
179
- # * <tt>:expires</tt> - The time at which this cookie expires, as a \Time or ActiveSupport::Duration object.
180
- # * <tt>:secure</tt> - Whether this cookie is only transmitted to HTTPS servers.
181
- # Default is +false+.
182
- # * <tt>:httponly</tt> - Whether this cookie is accessible via scripting or
183
- # only HTTP. Defaults to +false+.
184
- # * <tt>:same_site</tt> - The value of the +SameSite+ cookie attribute, which
185
- # determines how this cookie should be restricted in cross-site contexts.
186
- # Possible values are +nil+, +:none+, +:lax+, and +:strict+. Defaults to
187
- # +:lax+.
188
193
  class Cookies
189
194
  HTTP_HEADER = "Set-Cookie"
190
195
  GENERATOR_KEY = "action_dispatch.key_generator"
@@ -208,59 +213,69 @@ module ActionDispatch
208
213
  # Raised when storing more than 4K of session data.
209
214
  CookieOverflow = Class.new StandardError
210
215
 
211
- # Include in a cookie jar to allow chaining, e.g. +cookies.permanent.signed+.
216
+ # Include in a cookie jar to allow chaining, e.g. `cookies.permanent.signed`.
212
217
  module ChainedCookieJars
213
- # Returns a jar that'll automatically set the assigned cookies to have an expiration date 20 years from now. Example:
218
+ # Returns a jar that'll automatically set the assigned cookies to have an
219
+ # expiration date 20 years from now. Example:
214
220
  #
215
- # cookies.permanent[:prefers_open_id] = true
216
- # # => Set-Cookie: prefers_open_id=true; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
221
+ # cookies.permanent[:prefers_open_id] = true
222
+ # # => Set-Cookie: prefers_open_id=true; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
217
223
  #
218
- # This jar is only meant for writing. You'll read permanent cookies through the regular accessor.
224
+ # This jar is only meant for writing. You'll read permanent cookies through the
225
+ # regular accessor.
219
226
  #
220
- # This jar allows chaining with the signed jar as well, so you can set permanent, signed cookies. Examples:
227
+ # This jar allows chaining with the signed jar as well, so you can set
228
+ # permanent, signed cookies. Examples:
221
229
  #
222
- # cookies.permanent.signed[:remember_me] = current_user.id
223
- # # => Set-Cookie: remember_me=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
230
+ # cookies.permanent.signed[:remember_me] = current_user.id
231
+ # # => Set-Cookie: remember_me=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
224
232
  def permanent
225
233
  @permanent ||= PermanentCookieJar.new(self)
226
234
  end
227
235
 
228
- # Returns a jar that'll automatically generate a signed representation of cookie value and verify it when reading from
229
- # the cookie again. This is useful for creating cookies with values that the user is not supposed to change. If a signed
230
- # cookie was tampered with by the user (or a 3rd party), +nil+ will be returned.
236
+ # Returns a jar that'll automatically generate a signed representation of cookie
237
+ # value and verify it when reading from the cookie again. This is useful for
238
+ # creating cookies with values that the user is not supposed to change. If a
239
+ # signed cookie was tampered with by the user (or a 3rd party), `nil` will be
240
+ # returned.
231
241
  #
232
- # This jar requires that you set a suitable secret for the verification on your app's +secret_key_base+.
242
+ # This jar requires that you set a suitable secret for the verification on your
243
+ # app's `secret_key_base`.
233
244
  #
234
245
  # Example:
235
246
  #
236
- # cookies.signed[:discount] = 45
237
- # # => Set-Cookie: discount=BAhpMg==--2c1c6906c90a3bc4fd54a51ffb41dffa4bf6b5f7; path=/
247
+ # cookies.signed[:discount] = 45
248
+ # # => Set-Cookie: discount=BAhpMg==--2c1c6906c90a3bc4fd54a51ffb41dffa4bf6b5f7; path=/
238
249
  #
239
- # cookies.signed[:discount] # => 45
250
+ # cookies.signed[:discount] # => 45
240
251
  def signed
241
252
  @signed ||= SignedKeyRotatingCookieJar.new(self)
242
253
  end
243
254
 
244
- # Returns a jar that'll automatically encrypt cookie values before sending them to the client and will decrypt them for read.
245
- # If the cookie was tampered with by the user (or a 3rd party), +nil+ will be returned.
255
+ # Returns a jar that'll automatically encrypt cookie values before sending them
256
+ # to the client and will decrypt them for read. If the cookie was tampered with
257
+ # by the user (or a 3rd party), `nil` will be returned.
246
258
  #
247
- # If +config.action_dispatch.encrypted_cookie_salt+ and +config.action_dispatch.encrypted_signed_cookie_salt+
248
- # are both set, legacy cookies encrypted with HMAC AES-256-CBC will be transparently upgraded.
259
+ # If `config.action_dispatch.encrypted_cookie_salt` and
260
+ # `config.action_dispatch.encrypted_signed_cookie_salt` are both set, legacy
261
+ # cookies encrypted with HMAC AES-256-CBC will be transparently upgraded.
249
262
  #
250
- # This jar requires that you set a suitable secret for the verification on your app's +secret_key_base+.
263
+ # This jar requires that you set a suitable secret for the verification on your
264
+ # app's `secret_key_base`.
251
265
  #
252
266
  # Example:
253
267
  #
254
- # cookies.encrypted[:discount] = 45
255
- # # => Set-Cookie: discount=DIQ7fw==--K3n//8vvnSbGq9dA--7Xh91HfLpwzbj1czhBiwOg==; path=/
268
+ # cookies.encrypted[:discount] = 45
269
+ # # => Set-Cookie: discount=DIQ7fw==--K3n//8vvnSbGq9dA--7Xh91HfLpwzbj1czhBiwOg==; path=/
256
270
  #
257
- # cookies.encrypted[:discount] # => 45
271
+ # cookies.encrypted[:discount] # => 45
258
272
  def encrypted
259
273
  @encrypted ||= EncryptedKeyRotatingCookieJar.new(self)
260
274
  end
261
275
 
262
- # Returns the +signed+ or +encrypted+ jar, preferring +encrypted+ if +secret_key_base+ is set.
263
- # Used by ActionDispatch::Session::CookieStore to avoid the need to introduce new cookie stores.
276
+ # Returns the `signed` or `encrypted` jar, preferring `encrypted` if
277
+ # `secret_key_base` is set. Used by ActionDispatch::Session::CookieStore to
278
+ # avoid the need to introduce new cookie stores.
264
279
  def signed_or_encrypted
265
280
  @signed_or_encrypted ||=
266
281
  if request.secret_key_base.present?
@@ -324,7 +339,7 @@ module ActionDispatch
324
339
  @cookies.each(&block)
325
340
  end
326
341
 
327
- # Returns the value of the cookie by +name+, or +nil+ if no such cookie exists.
342
+ # Returns the value of the cookie by `name`, or `nil` if no such cookie exists.
328
343
  def [](name)
329
344
  @cookies[name.to_s]
330
345
  end
@@ -357,8 +372,8 @@ module ActionDispatch
357
372
  @cookies.map { |k, v| "#{escape(k)}=#{escape(v)}" }.join "; "
358
373
  end
359
374
 
360
- # Sets the cookie named +name+. The second argument may be the cookie's
361
- # value or a hash of options as documented above.
375
+ # Sets the cookie named `name`. The second argument may be the cookie's value or
376
+ # a hash of options as documented above.
362
377
  def []=(name, options)
363
378
  if options.is_a?(Hash)
364
379
  options.symbolize_keys!
@@ -379,11 +394,11 @@ module ActionDispatch
379
394
  value
380
395
  end
381
396
 
382
- # Removes the cookie on the client machine by setting the value to an empty string
383
- # and the expiration date in the past. Like <tt>[]=</tt>, you can pass in
384
- # an options hash to delete cookies with extra data such as a <tt>:path</tt>.
397
+ # Removes the cookie on the client machine by setting the value to an empty
398
+ # string and the expiration date in the past. Like `[]=`, you can pass in an
399
+ # options hash to delete cookies with extra data such as a `:path`.
385
400
  #
386
- # Returns the value of the cookie, or +nil+ if the cookie does not exist.
401
+ # Returns the value of the cookie, or `nil` if the cookie does not exist.
387
402
  def delete(name, options = {})
388
403
  return unless @cookies.has_key? name.to_s
389
404
 
@@ -395,16 +410,16 @@ module ActionDispatch
395
410
  value
396
411
  end
397
412
 
398
- # Whether the given cookie is to be deleted by this CookieJar.
399
- # Like <tt>[]=</tt>, you can pass in an options hash to test if a
400
- # deletion applies to a specific <tt>:path</tt>, <tt>:domain</tt> etc.
413
+ # Whether the given cookie is to be deleted by this CookieJar. Like `[]=`, you
414
+ # can pass in an options hash to test if a deletion applies to a specific
415
+ # `:path`, `:domain` etc.
401
416
  def deleted?(name, options = {})
402
417
  options.symbolize_keys!
403
418
  handle_options(options)
404
419
  @delete_cookies[name.to_s] == options
405
420
  end
406
421
 
407
- # Removes all cookies on the client machine by calling <tt>delete</tt> for each cookie.
422
+ # Removes all cookies on the client machine by calling `delete` for each cookie.
408
423
  def clear(options = {})
409
424
  @cookies.each_key { |k| delete(k, options) }
410
425
  end
@@ -447,8 +462,8 @@ module ActionDispatch
447
462
  cookie_domain = ""
448
463
  dot_splitted_host = request.host.split(".", -1)
449
464
 
450
- # Case where request.host is not an IP address or it's an invalid domain
451
- # (ip confirms to the domain structure we expect so we explicitly check for ip)
465
+ # Case where request.host is not an IP address or it's an invalid domain (ip
466
+ # confirms to the domain structure we expect so we explicitly check for ip)
452
467
  if request.host.match?(/^[\d.]+$/) || dot_splitted_host.include?("") || dot_splitted_host.length == 1
453
468
  options[:domain] = nil
454
469
  return
@@ -1,15 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "action_dispatch/middleware/exception_wrapper"
4
6
  require "action_dispatch/routing/inspector"
5
7
 
6
8
  require "action_view"
7
9
 
8
10
  module ActionDispatch
9
- # = Action Dispatch \DebugExceptions
11
+ # # Action Dispatch DebugExceptions
10
12
  #
11
- # This middleware is responsible for logging exceptions and
12
- # showing a debugging page in case the request is local.
13
+ # This middleware is responsible for logging exceptions and showing a debugging
14
+ # page in case the request is local.
13
15
  class DebugExceptions
14
16
  cattr_reader :interceptors, instance_accessor: false, default: []
15
17
 
@@ -115,8 +117,8 @@ module ActionDispatch
115
117
  DebugView.new(
116
118
  request: request,
117
119
  exception_wrapper: wrapper,
118
- # Everything should use the wrapper, but we need to pass
119
- # `exception` for legacy code.
120
+ # Everything should use the wrapper, but we need to pass `exception` for legacy
121
+ # code.
120
122
  exception: wrapper.exception,
121
123
  traces: wrapper.traces,
122
124
  show_source_idx: wrapper.source_to_show_id,
@@ -141,6 +143,12 @@ module ActionDispatch
141
143
  message = []
142
144
  message << " "
143
145
  message << "#{wrapper.exception_class_name} (#{wrapper.message}):"
146
+ if wrapper.has_cause?
147
+ message << "\nCauses:"
148
+ wrapper.wrapped_causes.each do |wrapped_cause|
149
+ message << "#{wrapped_cause.exception_class_name} (#{wrapped_cause.message})"
150
+ end
151
+ end
144
152
  message.concat(wrapper.annotated_source_code)
145
153
  message << " "
146
154
  message.concat(trace)
@@ -1,19 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionDispatch
4
- # = Action Dispatch \DebugLocks
6
+ # # Action Dispatch DebugLocks
5
7
  #
6
8
  # This middleware can be used to diagnose deadlocks in the autoload interlock.
7
9
  #
8
10
  # To use it, insert it near the top of the middleware stack, using
9
- # <tt>config/application.rb</tt>:
11
+ # `config/application.rb`:
10
12
  #
11
13
  # config.middleware.insert_before Rack::Sendfile, ActionDispatch::DebugLocks
12
14
  #
13
- # After restarting the application and re-triggering the deadlock condition,
14
- # the route <tt>/rails/locks</tt> will show a summary of all threads currently
15
- # known to the interlock, which lock level they are holding or awaiting, and
16
- # their current backtrace.
15
+ # After restarting the application and re-triggering the deadlock condition, the
16
+ # route `/rails/locks` will show a summary of all threads currently known to the
17
+ # interlock, which lock level they are holding or awaiting, and their current
18
+ # backtrace.
17
19
  #
18
20
  # Generally a deadlock will be caused by the interlock conflicting with some
19
21
  # other external lock or blocking I/O call. These cannot be automatically
@@ -46,14 +48,14 @@ module ActionDispatch
46
48
  private
47
49
  def render_details(req)
48
50
  threads = ActiveSupport::Dependencies.interlock.raw_state do |raw_threads|
49
- # The Interlock itself comes to a complete halt as long as this block
50
- # is executing. That gives us a more consistent picture of everything,
51
- # but creates a pretty strong Observer Effect.
51
+ # The Interlock itself comes to a complete halt as long as this block is
52
+ # executing. That gives us a more consistent picture of everything, but creates
53
+ # a pretty strong Observer Effect.
52
54
  #
53
- # Most directly, that means we need to do as little as possible in
54
- # this block. More widely, it means this middleware should remain a
55
- # strictly diagnostic tool (to be used when something has gone wrong),
56
- # and not for any sort of general monitoring.
55
+ # Most directly, that means we need to do as little as possible in this block.
56
+ # More widely, it means this middleware should remain a strictly diagnostic tool
57
+ # (to be used when something has gone wrong), and not for any sort of general
58
+ # monitoring.
57
59
 
58
60
  raw_threads.each.with_index do |(thread, info), idx|
59
61
  info[:index] = idx
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "pp"
4
6
 
5
7
  require "action_view"
@@ -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
  require "active_support/syntax_error_proxy"
5
7
  require "active_support/core_ext/thread/backtrace/location"
@@ -175,23 +177,15 @@ module ActionDispatch
175
177
  end
176
178
 
177
179
  def show?(request)
178
- # We're treating `nil` as "unset", and we want the default setting to be
179
- # `:all`. This logic should be extracted to `env_config` and calculated
180
- # once.
180
+ # We're treating `nil` as "unset", and we want the default setting to be `:all`.
181
+ # This logic should be extracted to `env_config` and calculated once.
181
182
  config = request.get_header("action_dispatch.show_exceptions")
182
183
 
183
- # Include true and false for backwards compatibility.
184
184
  case config
185
185
  when :none
186
186
  false
187
187
  when :rescuable
188
188
  rescue_response?
189
- when true
190
- ActionDispatch.deprecator.warn("Setting action_dispatch.show_exceptions to true is deprecated. Set to :all instead.")
191
- true
192
- when false
193
- ActionDispatch.deprecator.warn("Setting action_dispatch.show_exceptions to false is deprecated. Set to :none instead.")
194
- false
195
189
  else
196
190
  true
197
191
  end
@@ -208,7 +202,8 @@ module ActionDispatch
208
202
  end
209
203
 
210
204
  def error_highlight_available?
211
- # ErrorHighlight.spot with backtrace_location keyword is available since error_highlight 0.4.0
205
+ # ErrorHighlight.spot with backtrace_location keyword is available since
206
+ # error_highlight 0.4.0
212
207
  defined?(ErrorHighlight) && Gem::Version.new(ErrorHighlight::VERSION) >= Gem::Version.new("0.4.0")
213
208
  end
214
209
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "rack/body_proxy"
4
6
 
5
7
  module ActionDispatch