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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +82 -501
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +102 -98
- data/lib/abstract_controller/caching/fragments.rb +50 -53
- data/lib/abstract_controller/caching.rb +2 -0
- data/lib/abstract_controller/callbacks.rb +66 -64
- data/lib/abstract_controller/collector.rb +6 -6
- data/lib/abstract_controller/deprecator.rb +2 -0
- data/lib/abstract_controller/error.rb +2 -0
- data/lib/abstract_controller/helpers.rb +70 -85
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/rendering.rb +13 -12
- data/lib/abstract_controller/translation.rb +15 -7
- data/lib/abstract_controller/url_for.rb +8 -6
- data/lib/abstract_controller.rb +2 -0
- data/lib/action_controller/api/api_rendering.rb +2 -0
- data/lib/action_controller/api.rb +74 -72
- data/lib/action_controller/base.rb +198 -126
- data/lib/action_controller/caching.rb +15 -12
- data/lib/action_controller/deprecator.rb +2 -0
- data/lib/action_controller/form_builder.rb +20 -17
- data/lib/action_controller/log_subscriber.rb +3 -1
- data/lib/action_controller/metal/allow_browser.rb +123 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
- data/lib/action_controller/metal/conditional_get.rb +188 -174
- data/lib/action_controller/metal/content_security_policy.rb +25 -24
- data/lib/action_controller/metal/cookies.rb +4 -2
- data/lib/action_controller/metal/data_streaming.rb +64 -55
- data/lib/action_controller/metal/default_headers.rb +5 -3
- data/lib/action_controller/metal/etag_with_flash.rb +3 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +17 -15
- data/lib/action_controller/metal/exceptions.rb +11 -9
- data/lib/action_controller/metal/flash.rb +12 -10
- data/lib/action_controller/metal/head.rb +12 -10
- data/lib/action_controller/metal/helpers.rb +63 -55
- data/lib/action_controller/metal/http_authentication.rb +210 -205
- data/lib/action_controller/metal/implicit_render.rb +17 -15
- data/lib/action_controller/metal/instrumentation.rb +15 -12
- data/lib/action_controller/metal/live.rb +113 -107
- data/lib/action_controller/metal/logging.rb +6 -4
- data/lib/action_controller/metal/mime_responds.rb +151 -142
- data/lib/action_controller/metal/parameter_encoding.rb +34 -32
- data/lib/action_controller/metal/params_wrapper.rb +57 -59
- data/lib/action_controller/metal/permissions_policy.rb +13 -12
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +108 -82
- data/lib/action_controller/metal/renderers.rb +50 -49
- data/lib/action_controller/metal/rendering.rb +103 -75
- data/lib/action_controller/metal/request_forgery_protection.rb +162 -133
- data/lib/action_controller/metal/rescue.rb +11 -9
- data/lib/action_controller/metal/streaming.rb +138 -136
- data/lib/action_controller/metal/strong_parameters.rb +525 -480
- data/lib/action_controller/metal/testing.rb +2 -0
- data/lib/action_controller/metal/url_for.rb +17 -15
- data/lib/action_controller/metal.rb +86 -60
- data/lib/action_controller/railtie.rb +3 -0
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +42 -36
- data/lib/action_controller/template_assertions.rb +4 -2
- data/lib/action_controller/test_case.rb +146 -126
- data/lib/action_controller.rb +10 -3
- data/lib/action_dispatch/constants.rb +2 -0
- data/lib/action_dispatch/deprecator.rb +2 -0
- data/lib/action_dispatch/http/cache.rb +27 -26
- data/lib/action_dispatch/http/content_disposition.rb +2 -0
- data/lib/action_dispatch/http/content_security_policy.rb +44 -38
- data/lib/action_dispatch/http/filter_parameters.rb +18 -9
- data/lib/action_dispatch/http/filter_redirect.rb +22 -1
- data/lib/action_dispatch/http/headers.rb +22 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +30 -41
- data/lib/action_dispatch/http/mime_type.rb +31 -24
- data/lib/action_dispatch/http/mime_types.rb +2 -0
- data/lib/action_dispatch/http/parameters.rb +11 -9
- data/lib/action_dispatch/http/permissions_policy.rb +20 -44
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +94 -75
- data/lib/action_dispatch/http/response.rb +73 -61
- data/lib/action_dispatch/http/upload.rb +18 -16
- data/lib/action_dispatch/http/url.rb +75 -73
- data/lib/action_dispatch/journey/formatter.rb +13 -6
- data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +2 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +10 -8
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
- data/lib/action_dispatch/journey/nodes/node.rb +6 -5
- data/lib/action_dispatch/journey/parser.rb +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +2 -0
- data/lib/action_dispatch/journey/path/pattern.rb +4 -1
- data/lib/action_dispatch/journey/route.rb +9 -7
- data/lib/action_dispatch/journey/router/utils.rb +16 -15
- data/lib/action_dispatch/journey/router.rb +4 -2
- data/lib/action_dispatch/journey/routes.rb +4 -2
- data/lib/action_dispatch/journey/scanner.rb +4 -2
- data/lib/action_dispatch/journey/visitors.rb +2 -0
- data/lib/action_dispatch/journey.rb +2 -0
- data/lib/action_dispatch/log_subscriber.rb +2 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +8 -5
- data/lib/action_dispatch/middleware/callbacks.rb +3 -1
- data/lib/action_dispatch/middleware/cookies.rb +119 -104
- data/lib/action_dispatch/middleware/debug_exceptions.rb +13 -5
- data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
- data/lib/action_dispatch/middleware/debug_view.rb +2 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +6 -11
- data/lib/action_dispatch/middleware/executor.rb +8 -0
- data/lib/action_dispatch/middleware/flash.rb +63 -51
- data/lib/action_dispatch/middleware/host_authorization.rb +17 -15
- data/lib/action_dispatch/middleware/public_exceptions.rb +8 -6
- data/lib/action_dispatch/middleware/reloader.rb +5 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +77 -72
- data/lib/action_dispatch/middleware/request_id.rb +14 -9
- data/lib/action_dispatch/middleware/server_timing.rb +4 -2
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +13 -8
- data/lib/action_dispatch/middleware/session/cookie_store.rb +27 -26
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +31 -21
- data/lib/action_dispatch/middleware/ssl.rb +43 -40
- data/lib/action_dispatch/middleware/stack.rb +11 -10
- data/lib/action_dispatch/middleware/static.rb +33 -31
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
- data/lib/action_dispatch/railtie.rb +2 -4
- data/lib/action_dispatch/request/session.rb +23 -21
- data/lib/action_dispatch/request/utils.rb +2 -0
- data/lib/action_dispatch/routing/endpoint.rb +2 -0
- data/lib/action_dispatch/routing/inspector.rb +5 -3
- data/lib/action_dispatch/routing/mapper.rb +671 -636
- data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
- data/lib/action_dispatch/routing/redirection.rb +37 -32
- data/lib/action_dispatch/routing/route_set.rb +59 -45
- data/lib/action_dispatch/routing/routes_proxy.rb +6 -4
- data/lib/action_dispatch/routing/url_for.rb +130 -125
- data/lib/action_dispatch/routing.rb +150 -148
- data/lib/action_dispatch/system_test_case.rb +91 -81
- data/lib/action_dispatch/system_testing/browser.rb +10 -3
- data/lib/action_dispatch/system_testing/driver.rb +3 -1
- data/lib/action_dispatch/system_testing/server.rb +2 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +32 -21
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
- data/lib/action_dispatch/testing/assertion_response.rb +8 -6
- data/lib/action_dispatch/testing/assertions/response.rb +26 -23
- data/lib/action_dispatch/testing/assertions/routing.rb +153 -84
- data/lib/action_dispatch/testing/assertions.rb +2 -0
- data/lib/action_dispatch/testing/integration.rb +223 -222
- data/lib/action_dispatch/testing/request_encoder.rb +2 -0
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +12 -8
- data/lib/action_dispatch/testing/test_request.rb +3 -1
- data/lib/action_dispatch/testing/test_response.rb +27 -26
- data/lib/action_dispatch.rb +22 -28
- data/lib/action_pack/gem_version.rb +6 -4
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +17 -16
- metadata +39 -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,
|
98
|
-
# When writing cookie data, the data is sent out in the HTTP response
|
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
|
-
#
|
103
|
-
#
|
104
|
-
#
|
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
|
-
#
|
107
|
-
#
|
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
|
-
#
|
110
|
-
#
|
112
|
+
# # Sets a cookie that expires in 1 hour.
|
113
|
+
# cookies[:login] = { value: "XJ-122", expires: 1.hour }
|
111
114
|
#
|
112
|
-
#
|
113
|
-
#
|
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
|
-
#
|
116
|
-
#
|
117
|
-
#
|
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
|
-
#
|
120
|
-
#
|
121
|
-
#
|
122
|
-
#
|
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
|
-
#
|
125
|
-
#
|
127
|
+
# # Sets a "permanent" cookie (which expires in 20 years from now).
|
128
|
+
# cookies.permanent[:login] = "XJ-122"
|
126
129
|
#
|
127
|
-
#
|
128
|
-
#
|
130
|
+
# # You can also chain these methods:
|
131
|
+
# cookies.signed.permanent[:login] = "XJ-122"
|
129
132
|
#
|
130
133
|
# Examples of reading:
|
131
134
|
#
|
132
|
-
#
|
133
|
-
#
|
134
|
-
#
|
135
|
-
#
|
136
|
-
#
|
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
|
-
#
|
143
|
+
# cookies.delete :user_name
|
141
144
|
#
|
142
|
-
# Please note that if you specify a
|
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
|
-
#
|
145
|
-
#
|
146
|
-
#
|
147
|
-
#
|
148
|
-
#
|
148
|
+
# cookies[:name] = {
|
149
|
+
# value: 'a yummy cookie',
|
150
|
+
# expires: 1.year,
|
151
|
+
# domain: 'domain.com'
|
152
|
+
# }
|
149
153
|
#
|
150
|
-
#
|
154
|
+
# cookies.delete(:name, domain: 'domain.com')
|
151
155
|
#
|
152
156
|
# The option symbols for setting cookies are:
|
153
157
|
#
|
154
|
-
# *
|
155
|
-
# *
|
156
|
-
#
|
157
|
-
# *
|
158
|
-
#
|
159
|
-
#
|
160
|
-
#
|
161
|
-
#
|
162
|
-
#
|
163
|
-
#
|
164
|
-
#
|
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
|
-
#
|
168
|
-
#
|
169
|
-
#
|
170
|
-
#
|
171
|
-
#
|
172
|
-
#
|
173
|
-
#
|
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.
|
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
|
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
|
-
#
|
216
|
-
#
|
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
|
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
|
227
|
+
# This jar allows chaining with the signed jar as well, so you can set
|
228
|
+
# permanent, signed cookies. Examples:
|
221
229
|
#
|
222
|
-
#
|
223
|
-
#
|
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
|
229
|
-
# the cookie again. This is useful for
|
230
|
-
#
|
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
|
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
|
-
#
|
237
|
-
#
|
247
|
+
# cookies.signed[:discount] = 45
|
248
|
+
# # => Set-Cookie: discount=BAhpMg==--2c1c6906c90a3bc4fd54a51ffb41dffa4bf6b5f7; path=/
|
238
249
|
#
|
239
|
-
#
|
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
|
245
|
-
#
|
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
|
248
|
-
# are both set, legacy
|
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
|
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
|
-
#
|
255
|
-
#
|
268
|
+
# cookies.encrypted[:discount] = 45
|
269
|
+
# # => Set-Cookie: discount=DIQ7fw==--K3n//8vvnSbGq9dA--7Xh91HfLpwzbj1czhBiwOg==; path=/
|
256
270
|
#
|
257
|
-
#
|
271
|
+
# cookies.encrypted[:discount] # => 45
|
258
272
|
def encrypted
|
259
273
|
@encrypted ||= EncryptedKeyRotatingCookieJar.new(self)
|
260
274
|
end
|
261
275
|
|
262
|
-
# Returns the
|
263
|
-
# Used by ActionDispatch::Session::CookieStore to
|
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
|
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
|
361
|
-
#
|
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
|
383
|
-
# and the expiration date in the past. Like
|
384
|
-
#
|
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
|
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
|
-
#
|
400
|
-
#
|
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
|
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
|
-
#
|
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
|
-
#
|
11
|
+
# # Action Dispatch DebugExceptions
|
10
12
|
#
|
11
|
-
# This middleware is responsible for logging exceptions and
|
12
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
15
|
-
#
|
16
|
-
#
|
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
|
-
#
|
51
|
-
#
|
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
|
-
#
|
55
|
-
#
|
56
|
-
#
|
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 "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
|
-
#
|
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
|
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
|
@@ -12,6 +14,12 @@ module ActionDispatch
|
|
12
14
|
state = @executor.run!(reset: true)
|
13
15
|
begin
|
14
16
|
response = @app.call(env)
|
17
|
+
|
18
|
+
if env["action_dispatch.report_exception"]
|
19
|
+
error = env["action_dispatch.exception"]
|
20
|
+
@executor.error_reporter.report(error, handled: false, source: "application.action_dispatch")
|
21
|
+
end
|
22
|
+
|
15
23
|
returned = response << ::Rack::BodyProxy.new(response.pop) { state.complete! }
|
16
24
|
rescue => error
|
17
25
|
@executor.error_reporter.report(error, handled: false, source: "application.action_dispatch")
|