actionpack 6.0.3.7 → 6.1.0.rc1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +242 -268
- data/MIT-LICENSE +1 -1
- data/lib/abstract_controller.rb +1 -0
- data/lib/abstract_controller/base.rb +35 -2
- data/lib/abstract_controller/callbacks.rb +2 -2
- data/lib/abstract_controller/helpers.rb +105 -90
- data/lib/abstract_controller/rendering.rb +9 -9
- data/lib/abstract_controller/translation.rb +8 -2
- data/lib/action_controller.rb +2 -3
- data/lib/action_controller/api.rb +2 -2
- data/lib/action_controller/base.rb +4 -2
- data/lib/action_controller/caching.rb +0 -1
- data/lib/action_controller/log_subscriber.rb +3 -3
- data/lib/action_controller/metal.rb +2 -2
- data/lib/action_controller/metal/conditional_get.rb +10 -2
- data/lib/action_controller/metal/content_security_policy.rb +1 -1
- data/lib/action_controller/metal/data_streaming.rb +1 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +2 -4
- data/lib/action_controller/metal/exceptions.rb +33 -0
- data/lib/action_controller/metal/feature_policy.rb +46 -0
- data/lib/action_controller/metal/head.rb +7 -4
- data/lib/action_controller/metal/helpers.rb +11 -1
- data/lib/action_controller/metal/http_authentication.rb +5 -3
- data/lib/action_controller/metal/implicit_render.rb +1 -1
- data/lib/action_controller/metal/instrumentation.rb +11 -9
- data/lib/action_controller/metal/live.rb +1 -1
- data/lib/action_controller/metal/logging.rb +20 -0
- data/lib/action_controller/metal/mime_responds.rb +6 -2
- data/lib/action_controller/metal/parameter_encoding.rb +35 -4
- data/lib/action_controller/metal/params_wrapper.rb +14 -8
- data/lib/action_controller/metal/redirecting.rb +1 -1
- data/lib/action_controller/metal/rendering.rb +6 -0
- data/lib/action_controller/metal/request_forgery_protection.rb +48 -24
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/strong_parameters.rb +103 -15
- data/lib/action_controller/renderer.rb +24 -13
- data/lib/action_controller/test_case.rb +62 -56
- data/lib/action_dispatch.rb +3 -2
- data/lib/action_dispatch/http/cache.rb +12 -10
- data/lib/action_dispatch/http/content_disposition.rb +2 -2
- data/lib/action_dispatch/http/content_security_policy.rb +5 -1
- data/lib/action_dispatch/http/feature_policy.rb +168 -0
- data/lib/action_dispatch/http/filter_parameters.rb +1 -1
- data/lib/action_dispatch/http/filter_redirect.rb +1 -1
- data/lib/action_dispatch/http/headers.rb +3 -2
- data/lib/action_dispatch/http/mime_negotiation.rb +20 -8
- data/lib/action_dispatch/http/mime_type.rb +29 -16
- data/lib/action_dispatch/http/parameters.rb +1 -19
- data/lib/action_dispatch/http/request.rb +26 -8
- data/lib/action_dispatch/http/response.rb +17 -16
- data/lib/action_dispatch/http/url.rb +3 -2
- data/lib/action_dispatch/journey.rb +0 -2
- data/lib/action_dispatch/journey/formatter.rb +53 -28
- data/lib/action_dispatch/journey/gtg/builder.rb +22 -36
- data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
- data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -4
- data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
- data/lib/action_dispatch/journey/nodes/node.rb +4 -3
- data/lib/action_dispatch/journey/parser.rb +13 -13
- data/lib/action_dispatch/journey/parser.y +1 -1
- data/lib/action_dispatch/journey/path/pattern.rb +13 -18
- data/lib/action_dispatch/journey/route.rb +7 -18
- data/lib/action_dispatch/journey/router.rb +26 -30
- data/lib/action_dispatch/journey/router/utils.rb +6 -4
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -2
- data/lib/action_dispatch/middleware/cookies.rb +74 -33
- data/lib/action_dispatch/middleware/debug_exceptions.rb +10 -17
- data/lib/action_dispatch/middleware/debug_view.rb +1 -1
- data/lib/action_dispatch/middleware/exception_wrapper.rb +29 -17
- data/lib/action_dispatch/middleware/host_authorization.rb +28 -17
- data/lib/action_dispatch/middleware/public_exceptions.rb +1 -1
- data/lib/action_dispatch/middleware/remote_ip.rb +5 -4
- data/lib/action_dispatch/middleware/request_id.rb +4 -5
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -2
- data/lib/action_dispatch/middleware/session/cookie_store.rb +2 -2
- data/lib/action_dispatch/middleware/ssl.rb +9 -6
- data/lib/action_dispatch/middleware/stack.rb +18 -0
- data/lib/action_dispatch/middleware/static.rb +154 -93
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +18 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +2 -5
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +88 -8
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +12 -1
- data/lib/action_dispatch/railtie.rb +3 -2
- data/lib/action_dispatch/request/session.rb +2 -8
- data/lib/action_dispatch/request/utils.rb +26 -2
- data/lib/action_dispatch/routing/inspector.rb +8 -7
- data/lib/action_dispatch/routing/mapper.rb +102 -71
- data/lib/action_dispatch/routing/polymorphic_routes.rb +16 -19
- data/lib/action_dispatch/routing/redirection.rb +3 -3
- data/lib/action_dispatch/routing/route_set.rb +49 -41
- data/lib/action_dispatch/routing/url_for.rb +1 -0
- data/lib/action_dispatch/system_test_case.rb +29 -24
- data/lib/action_dispatch/system_testing/browser.rb +33 -27
- data/lib/action_dispatch/system_testing/driver.rb +6 -7
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +47 -6
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +4 -7
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +2 -4
- data/lib/action_dispatch/testing/assertions/routing.rb +5 -5
- data/lib/action_dispatch/testing/integration.rb +38 -27
- data/lib/action_dispatch/testing/test_process.rb +29 -4
- data/lib/action_dispatch/testing/test_request.rb +3 -3
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/gem_version.rb +3 -3
- metadata +23 -24
- data/lib/action_controller/metal/force_ssl.rb +0 -58
- data/lib/action_dispatch/http/parameter_filter.rb +0 -12
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -119
@@ -13,6 +13,7 @@ module ActionDispatch
|
|
13
13
|
VERBS = %w{ DELETE GET HEAD OPTIONS LINK PATCH POST PUT TRACE UNLINK }
|
14
14
|
VERBS.each do |v|
|
15
15
|
class_eval <<-eoc, __FILE__, __LINE__ + 1
|
16
|
+
# frozen_string_literal: true
|
16
17
|
class #{v}
|
17
18
|
def self.verb; name.split("::").last; end
|
18
19
|
def self.call(req); req.#{v.downcase}?; end
|
@@ -27,7 +28,7 @@ module ActionDispatch
|
|
27
28
|
@verb = verb
|
28
29
|
end
|
29
30
|
|
30
|
-
def call(request); @verb
|
31
|
+
def call(request); @verb == request.request_method; end
|
31
32
|
end
|
32
33
|
|
33
34
|
class All
|
@@ -49,15 +50,10 @@ module ActionDispatch
|
|
49
50
|
end
|
50
51
|
end
|
51
52
|
|
52
|
-
def self.build(name, app, path, constraints, required_defaults, defaults)
|
53
|
-
request_method_match = verb_matcher(constraints.delete(:request_method))
|
54
|
-
new name, app, path, constraints, required_defaults, defaults, request_method_match, 0, {}
|
55
|
-
end
|
56
|
-
|
57
53
|
##
|
58
54
|
# +path+ is a path constraint.
|
59
55
|
# +constraints+ is a hash of constraints to be applied to this route.
|
60
|
-
def initialize(name
|
56
|
+
def initialize(name:, app: nil, path:, constraints: {}, required_defaults: [], defaults: {}, request_method_match: nil, precedence: 0, scope_options: {}, internal: false)
|
61
57
|
@name = name
|
62
58
|
@app = app
|
63
59
|
@path = path
|
@@ -92,7 +88,7 @@ module ActionDispatch
|
|
92
88
|
end
|
93
89
|
end
|
94
90
|
|
95
|
-
# Needed for `rails routes`. Picks up succinctly defined requirements
|
91
|
+
# Needed for `bin/rails routes`. Picks up succinctly defined requirements
|
96
92
|
# for a route, for example route
|
97
93
|
#
|
98
94
|
# get 'photo/:id', :controller => 'photos', :action => 'show',
|
@@ -115,18 +111,11 @@ module ActionDispatch
|
|
115
111
|
end
|
116
112
|
|
117
113
|
def score(supplied_keys)
|
118
|
-
|
119
|
-
|
120
|
-
required_keys.each do |k|
|
114
|
+
path.required_names.each do |k|
|
121
115
|
return -1 unless supplied_keys.include?(k)
|
122
116
|
end
|
123
117
|
|
124
|
-
|
125
|
-
path.names.each do |k|
|
126
|
-
score += 1 if supplied_keys.include?(k)
|
127
|
-
end
|
128
|
-
|
129
|
-
score + (required_defaults.length * 2)
|
118
|
+
(required_defaults.length * 2) + path.names.count { |k| supplied_keys.include?(k) }
|
130
119
|
end
|
131
120
|
|
132
121
|
def parts
|
@@ -153,7 +142,7 @@ module ActionDispatch
|
|
153
142
|
end
|
154
143
|
|
155
144
|
def glob?
|
156
|
-
|
145
|
+
path.spec.any?(Nodes::Star)
|
157
146
|
end
|
158
147
|
|
159
148
|
def dispatcher?
|
@@ -40,11 +40,12 @@ module ActionDispatch
|
|
40
40
|
req.path_info = "/" + req.path_info unless req.path_info.start_with? "/"
|
41
41
|
end
|
42
42
|
|
43
|
-
|
44
|
-
|
43
|
+
tmp_params = set_params.merge route.defaults
|
44
|
+
parameters.each_pair { |key, val|
|
45
|
+
tmp_params[key] = val.force_encoding(::Encoding::UTF_8)
|
45
46
|
}
|
46
47
|
|
47
|
-
req.path_parameters =
|
48
|
+
req.path_parameters = tmp_params
|
48
49
|
|
49
50
|
status, headers, body = route.app.serve(req)
|
50
51
|
|
@@ -65,7 +66,8 @@ module ActionDispatch
|
|
65
66
|
find_routes(rails_req).each do |match, parameters, route|
|
66
67
|
unless route.path.anchored
|
67
68
|
rails_req.script_name = match.to_s
|
68
|
-
rails_req.path_info = match.post_match
|
69
|
+
rails_req.path_info = match.post_match
|
70
|
+
rails_req.path_info = "/" + rails_req.path_info unless rails_req.path_info.start_with? "/"
|
69
71
|
end
|
70
72
|
|
71
73
|
parameters = route.defaults.merge parameters
|
@@ -105,23 +107,24 @@ module ActionDispatch
|
|
105
107
|
end
|
106
108
|
|
107
109
|
def find_routes(req)
|
108
|
-
|
109
|
-
|
110
|
+
path_info = req.path_info
|
111
|
+
routes = filter_routes(path_info).concat custom_routes.find_all { |r|
|
112
|
+
r.path.match?(path_info)
|
110
113
|
}
|
111
114
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
end
|
115
|
+
if req.head?
|
116
|
+
routes = match_head_routes(routes, req)
|
117
|
+
else
|
118
|
+
routes.select! { |r| r.matches?(req) }
|
119
|
+
end
|
118
120
|
|
119
121
|
routes.sort_by!(&:precedence)
|
120
122
|
|
121
123
|
routes.map! { |r|
|
122
|
-
match_data = r.path.match(
|
124
|
+
match_data = r.path.match(path_info)
|
123
125
|
path_parameters = {}
|
124
|
-
match_data.names.
|
126
|
+
match_data.names.each_with_index { |name, i|
|
127
|
+
val = match_data[i + 1]
|
125
128
|
path_parameters[name.to_sym] = Utils.unescape_uri(val) if val
|
126
129
|
}
|
127
130
|
[match_data, path_parameters, r]
|
@@ -129,24 +132,17 @@ module ActionDispatch
|
|
129
132
|
end
|
130
133
|
|
131
134
|
def match_head_routes(routes, req)
|
132
|
-
|
133
|
-
head_routes
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
end
|
142
|
-
else
|
143
|
-
head_routes
|
135
|
+
head_routes = routes.select { |r| r.requires_matching_verb? && r.matches?(req) }
|
136
|
+
return head_routes unless head_routes.empty?
|
137
|
+
|
138
|
+
begin
|
139
|
+
req.request_method = "GET"
|
140
|
+
routes.select! { |r| r.matches?(req) }
|
141
|
+
routes
|
142
|
+
ensure
|
143
|
+
req.request_method = "HEAD"
|
144
144
|
end
|
145
145
|
end
|
146
|
-
|
147
|
-
def match_routes(routes, req)
|
148
|
-
routes.select { |r| r.matches?(req) }
|
149
|
-
end
|
150
146
|
end
|
151
147
|
end
|
152
148
|
end
|
@@ -19,11 +19,13 @@ module ActionDispatch
|
|
19
19
|
encoding = path.encoding
|
20
20
|
path = +"/#{path}"
|
21
21
|
path.squeeze!("/")
|
22
|
-
|
23
|
-
path
|
24
|
-
|
22
|
+
|
23
|
+
unless path == "/"
|
24
|
+
path.delete_suffix!("/")
|
25
|
+
path.gsub!(/(%[a-f0-9]{2})/) { $1.upcase }
|
26
|
+
end
|
27
|
+
|
25
28
|
path.force_encoding(encoding)
|
26
|
-
path
|
27
29
|
end
|
28
30
|
|
29
31
|
# URI path and fragment escaping
|
@@ -24,7 +24,7 @@ module ActionDispatch
|
|
24
24
|
|
25
25
|
private
|
26
26
|
def actionable_request?(request)
|
27
|
-
request.get_header("action_dispatch.show_detailed_exceptions")
|
27
|
+
request.get_header("action_dispatch.show_detailed_exceptions") && request.post? && request.path == endpoint
|
28
28
|
end
|
29
29
|
|
30
30
|
def redirect_to(location)
|
@@ -33,7 +33,7 @@ module ActionDispatch
|
|
33
33
|
if uri.relative? || uri.scheme == "http" || uri.scheme == "https"
|
34
34
|
body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(location)}\">redirected</a>.</body></html>"
|
35
35
|
else
|
36
|
-
return [400, {"Content-Type" => "text/plain"}, ["Invalid redirection URI"]]
|
36
|
+
return [400, { "Content-Type" => "text/plain" }, ["Invalid redirection URI"]]
|
37
37
|
end
|
38
38
|
|
39
39
|
[302, {
|
@@ -69,6 +69,10 @@ module ActionDispatch
|
|
69
69
|
get_header Cookies::COOKIES_SERIALIZER
|
70
70
|
end
|
71
71
|
|
72
|
+
def cookies_same_site_protection
|
73
|
+
get_header(Cookies::COOKIES_SAME_SITE_PROTECTION) || Proc.new { }
|
74
|
+
end
|
75
|
+
|
72
76
|
def cookies_digest
|
73
77
|
get_header Cookies::COOKIES_DIGEST
|
74
78
|
end
|
@@ -84,11 +88,10 @@ module ActionDispatch
|
|
84
88
|
# :startdoc:
|
85
89
|
end
|
86
90
|
|
87
|
-
#
|
91
|
+
# Read and write data to cookies through ActionController#cookies.
|
88
92
|
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
# the cookie object itself back, just the value it holds.
|
93
|
+
# When reading cookie data, the data is read from the HTTP request header, Cookie.
|
94
|
+
# When writing cookie data, the data is sent out in the HTTP response header, Set-Cookie.
|
92
95
|
#
|
93
96
|
# Examples of writing:
|
94
97
|
#
|
@@ -150,8 +153,10 @@ module ActionDispatch
|
|
150
153
|
# * <tt>:domain</tt> - The domain for which this cookie applies so you can
|
151
154
|
# restrict to the domain level. If you use a schema like www.example.com
|
152
155
|
# and want to share session with user.example.com set <tt>:domain</tt>
|
153
|
-
# to <tt>:all</tt>.
|
154
|
-
#
|
156
|
+
# to <tt>:all</tt>. To support multiple domains, provide an array, and
|
157
|
+
# the first domain matching <tt>request.host</tt> will be used. Make
|
158
|
+
# sure to specify the <tt>:domain</tt> option with <tt>:all</tt> or
|
159
|
+
# <tt>Array</tt> again when deleting cookies.
|
155
160
|
#
|
156
161
|
# domain: nil # Does not set cookie domain. (default)
|
157
162
|
# domain: :all # Allow the cookie for the top most level
|
@@ -181,6 +186,7 @@ module ActionDispatch
|
|
181
186
|
COOKIES_SERIALIZER = "action_dispatch.cookies_serializer"
|
182
187
|
COOKIES_DIGEST = "action_dispatch.cookies_digest"
|
183
188
|
COOKIES_ROTATIONS = "action_dispatch.cookies_rotations"
|
189
|
+
COOKIES_SAME_SITE_PROTECTION = "action_dispatch.cookies_same_site_protection"
|
184
190
|
USE_COOKIES_WITH_METADATA = "action_dispatch.use_cookies_with_metadata"
|
185
191
|
|
186
192
|
# Cookies can typically store 4096 bytes.
|
@@ -259,6 +265,12 @@ module ActionDispatch
|
|
259
265
|
request.use_authenticated_cookie_encryption
|
260
266
|
end
|
261
267
|
|
268
|
+
def prepare_upgrade_legacy_hmac_aes_cbc_cookies?
|
269
|
+
request.secret_key_base.present? &&
|
270
|
+
request.authenticated_encrypted_cookie_salt.present? &&
|
271
|
+
!request.use_authenticated_cookie_encryption
|
272
|
+
end
|
273
|
+
|
262
274
|
def encrypted_cookie_cipher
|
263
275
|
request.encrypted_cookie_cipher || "aes-256-gcm"
|
264
276
|
end
|
@@ -286,9 +298,9 @@ module ActionDispatch
|
|
286
298
|
DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/
|
287
299
|
|
288
300
|
def self.build(req, cookies)
|
289
|
-
new(req)
|
290
|
-
|
291
|
-
|
301
|
+
jar = new(req)
|
302
|
+
jar.update(cookies)
|
303
|
+
jar
|
292
304
|
end
|
293
305
|
|
294
306
|
attr_reader :request
|
@@ -346,28 +358,6 @@ module ActionDispatch
|
|
346
358
|
@cookies.map { |k, v| "#{escape(k)}=#{escape(v)}" }.join "; "
|
347
359
|
end
|
348
360
|
|
349
|
-
def handle_options(options) # :nodoc:
|
350
|
-
if options[:expires].respond_to?(:from_now)
|
351
|
-
options[:expires] = options[:expires].from_now
|
352
|
-
end
|
353
|
-
|
354
|
-
options[:path] ||= "/"
|
355
|
-
|
356
|
-
if options[:domain] == :all || options[:domain] == "all"
|
357
|
-
# If there is a provided tld length then we use it otherwise default domain regexp.
|
358
|
-
domain_regexp = options[:tld_length] ? /([^.]+\.?){#{options[:tld_length]}}$/ : DOMAIN_REGEXP
|
359
|
-
|
360
|
-
# If host is not ip and matches domain regexp.
|
361
|
-
# (ip confirms to domain regexp so we explicitly check for ip)
|
362
|
-
options[:domain] = if (request.host !~ /^[\d.]+$/) && (request.host =~ domain_regexp)
|
363
|
-
".#{$&}"
|
364
|
-
end
|
365
|
-
elsif options[:domain].is_a? Array
|
366
|
-
# If host matches one of the supplied domains without a dot in front of it.
|
367
|
-
options[:domain] = options[:domain].find { |domain| request.host.include? domain.sub(/^\./, "") }
|
368
|
-
end
|
369
|
-
end
|
370
|
-
|
371
361
|
# Sets the cookie named +name+. The second argument may be the cookie's
|
372
362
|
# value or a hash of options as documented above.
|
373
363
|
def []=(name, options)
|
@@ -447,6 +437,34 @@ module ActionDispatch
|
|
447
437
|
def write_cookie?(cookie)
|
448
438
|
request.ssl? || !cookie[:secure] || always_write_cookie
|
449
439
|
end
|
440
|
+
|
441
|
+
def handle_options(options)
|
442
|
+
if options[:expires].respond_to?(:from_now)
|
443
|
+
options[:expires] = options[:expires].from_now
|
444
|
+
end
|
445
|
+
|
446
|
+
options[:path] ||= "/"
|
447
|
+
|
448
|
+
cookies_same_site_protection = request.cookies_same_site_protection
|
449
|
+
options[:same_site] ||= cookies_same_site_protection.call(request)
|
450
|
+
|
451
|
+
if options[:domain] == :all || options[:domain] == "all"
|
452
|
+
# If there is a provided tld length then we use it otherwise default domain regexp.
|
453
|
+
domain_regexp = options[:tld_length] ? /([^.]+\.?){#{options[:tld_length]}}$/ : DOMAIN_REGEXP
|
454
|
+
|
455
|
+
# If host is not ip and matches domain regexp.
|
456
|
+
# (ip confirms to domain regexp so we explicitly check for ip)
|
457
|
+
options[:domain] = if !request.host.match?(/^[\d.]+$/) && (request.host =~ domain_regexp)
|
458
|
+
".#{$&}"
|
459
|
+
end
|
460
|
+
elsif options[:domain].is_a? Array
|
461
|
+
# If host matches one of the supplied domains.
|
462
|
+
options[:domain] = options[:domain].find do |domain|
|
463
|
+
domain = domain.delete_prefix(".")
|
464
|
+
request.host == domain || request.host.end_with?(".#{domain}")
|
465
|
+
end
|
466
|
+
end
|
467
|
+
end
|
450
468
|
end
|
451
469
|
|
452
470
|
class AbstractCookieJar # :nodoc:
|
@@ -458,7 +476,13 @@ module ActionDispatch
|
|
458
476
|
|
459
477
|
def [](name)
|
460
478
|
if data = @parent_jar[name.to_s]
|
461
|
-
parse(name, data, purpose: "cookie.#{name}")
|
479
|
+
result = parse(name, data, purpose: "cookie.#{name}")
|
480
|
+
|
481
|
+
if result.nil?
|
482
|
+
parse(name, data)
|
483
|
+
else
|
484
|
+
result
|
485
|
+
end
|
462
486
|
end
|
463
487
|
end
|
464
488
|
|
@@ -502,6 +526,18 @@ module ActionDispatch
|
|
502
526
|
end
|
503
527
|
end
|
504
528
|
|
529
|
+
class MarshalWithJsonFallback # :nodoc:
|
530
|
+
def self.load(value)
|
531
|
+
Marshal.load(value)
|
532
|
+
rescue TypeError => e
|
533
|
+
ActiveSupport::JSON.decode(value) rescue raise e
|
534
|
+
end
|
535
|
+
|
536
|
+
def self.dump(value)
|
537
|
+
Marshal.dump(value)
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
505
541
|
class JsonSerializer # :nodoc:
|
506
542
|
def self.load(value)
|
507
543
|
ActiveSupport::JSON.decode(value)
|
@@ -549,7 +585,7 @@ module ActionDispatch
|
|
549
585
|
serializer = request.cookies_serializer || :marshal
|
550
586
|
case serializer
|
551
587
|
when :marshal
|
552
|
-
|
588
|
+
MarshalWithJsonFallback
|
553
589
|
when :json, :hybrid
|
554
590
|
JsonSerializer
|
555
591
|
else
|
@@ -619,6 +655,11 @@ module ActionDispatch
|
|
619
655
|
sign_secret = request.key_generator.generate_key(request.encrypted_signed_cookie_salt)
|
620
656
|
|
621
657
|
@encryptor.rotate(secret, sign_secret, cipher: legacy_cipher, digest: digest, serializer: SERIALIZER)
|
658
|
+
elsif prepare_upgrade_legacy_hmac_aes_cbc_cookies?
|
659
|
+
future_cipher = encrypted_cookie_cipher
|
660
|
+
secret = request.key_generator.generate_key(request.authenticated_encrypted_cookie_salt, ActiveSupport::MessageEncryptor.key_len(future_cipher))
|
661
|
+
|
662
|
+
@encryptor.rotate(secret, nil, cipher: future_cipher, serializer: SERIALIZER)
|
622
663
|
end
|
623
664
|
end
|
624
665
|
|
@@ -4,10 +4,7 @@ require "action_dispatch/http/request"
|
|
4
4
|
require "action_dispatch/middleware/exception_wrapper"
|
5
5
|
require "action_dispatch/routing/inspector"
|
6
6
|
|
7
|
-
require "active_support/actionable_error"
|
8
|
-
|
9
7
|
require "action_view"
|
10
|
-
require "action_view/base"
|
11
8
|
|
12
9
|
module ActionDispatch
|
13
10
|
# This middleware is responsible for logging exceptions and
|
@@ -63,8 +60,8 @@ module ActionDispatch
|
|
63
60
|
if request.get_header("action_dispatch.show_detailed_exceptions")
|
64
61
|
begin
|
65
62
|
content_type = request.formats.first
|
66
|
-
rescue
|
67
|
-
|
63
|
+
rescue ActionDispatch::Http::MimeNegotiation::InvalidType
|
64
|
+
content_type = Mime[:text]
|
68
65
|
end
|
69
66
|
|
70
67
|
if api_request?(content_type)
|
@@ -140,20 +137,16 @@ module ActionDispatch
|
|
140
137
|
return unless logger
|
141
138
|
|
142
139
|
exception = wrapper.exception
|
140
|
+
trace = wrapper.exception_trace
|
143
141
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
message << "#{exception.class} (#{exception.message}):"
|
151
|
-
message.concat(exception.annotated_source_code) if exception.respond_to?(:annotated_source_code)
|
152
|
-
message << " "
|
153
|
-
message.concat(trace)
|
142
|
+
message = []
|
143
|
+
message << " "
|
144
|
+
message << "#{exception.class} (#{exception.message}):"
|
145
|
+
message.concat(exception.annotated_source_code) if exception.respond_to?(:annotated_source_code)
|
146
|
+
message << " "
|
147
|
+
message.concat(trace)
|
154
148
|
|
155
|
-
|
156
|
-
end
|
149
|
+
log_array(logger, message)
|
157
150
|
end
|
158
151
|
|
159
152
|
def log_array(logger, array)
|