actionpack 7.0.8.4 → 7.1.3.4
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 +358 -362
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/lib/abstract_controller/base.rb +20 -11
- data/lib/abstract_controller/caching/fragments.rb +2 -0
- data/lib/abstract_controller/callbacks.rb +31 -6
- data/lib/abstract_controller/deprecator.rb +7 -0
- data/lib/abstract_controller/helpers.rb +61 -18
- data/lib/abstract_controller/railties/routes_helpers.rb +1 -16
- data/lib/abstract_controller/rendering.rb +3 -3
- data/lib/abstract_controller/translation.rb +1 -20
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/abstract_controller.rb +6 -0
- data/lib/action_controller/api.rb +5 -3
- data/lib/action_controller/base.rb +3 -17
- data/lib/action_controller/caching.rb +2 -0
- data/lib/action_controller/deprecator.rb +7 -0
- data/lib/action_controller/form_builder.rb +2 -0
- data/lib/action_controller/log_subscriber.rb +16 -4
- data/lib/action_controller/metal/content_security_policy.rb +1 -1
- data/lib/action_controller/metal/data_streaming.rb +2 -0
- data/lib/action_controller/metal/default_headers.rb +2 -0
- data/lib/action_controller/metal/etag_with_flash.rb +2 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +2 -0
- data/lib/action_controller/metal/exceptions.rb +8 -0
- data/lib/action_controller/metal/head.rb +8 -6
- data/lib/action_controller/metal/helpers.rb +3 -14
- data/lib/action_controller/metal/http_authentication.rb +17 -8
- data/lib/action_controller/metal/implicit_render.rb +5 -3
- data/lib/action_controller/metal/instrumentation.rb +8 -1
- data/lib/action_controller/metal/live.rb +24 -0
- data/lib/action_controller/metal/mime_responds.rb +2 -2
- data/lib/action_controller/metal/params_wrapper.rb +4 -2
- data/lib/action_controller/metal/permissions_policy.rb +1 -1
- data/lib/action_controller/metal/redirecting.rb +7 -7
- data/lib/action_controller/metal/renderers.rb +2 -2
- data/lib/action_controller/metal/rendering.rb +0 -7
- data/lib/action_controller/metal/request_forgery_protection.rb +139 -50
- data/lib/action_controller/metal/rescue.rb +2 -0
- data/lib/action_controller/metal/streaming.rb +70 -30
- data/lib/action_controller/metal/strong_parameters.rb +132 -52
- data/lib/action_controller/metal/url_for.rb +7 -0
- data/lib/action_controller/metal.rb +79 -21
- data/lib/action_controller/railtie.rb +22 -9
- data/lib/action_controller/renderer.rb +98 -65
- data/lib/action_controller/test_case.rb +15 -5
- data/lib/action_controller.rb +8 -1
- data/lib/action_dispatch/constants.rb +32 -0
- data/lib/action_dispatch/deprecator.rb +7 -0
- data/lib/action_dispatch/http/cache.rb +1 -3
- data/lib/action_dispatch/http/content_security_policy.rb +9 -8
- data/lib/action_dispatch/http/filter_parameters.rb +11 -5
- data/lib/action_dispatch/http/headers.rb +2 -0
- data/lib/action_dispatch/http/mime_negotiation.rb +22 -22
- data/lib/action_dispatch/http/mime_type.rb +35 -12
- data/lib/action_dispatch/http/mime_types.rb +3 -1
- data/lib/action_dispatch/http/parameters.rb +1 -1
- data/lib/action_dispatch/http/permissions_policy.rb +38 -16
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +48 -14
- data/lib/action_dispatch/http/response.rb +80 -59
- data/lib/action_dispatch/http/upload.rb +2 -0
- data/lib/action_dispatch/journey/formatter.rb +8 -2
- data/lib/action_dispatch/journey/path/pattern.rb +14 -14
- data/lib/action_dispatch/journey/route.rb +3 -2
- data/lib/action_dispatch/journey/router.rb +9 -8
- data/lib/action_dispatch/journey/routes.rb +2 -2
- data/lib/action_dispatch/log_subscriber.rb +23 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +5 -6
- data/lib/action_dispatch/middleware/assume_ssl.rb +24 -0
- data/lib/action_dispatch/middleware/callbacks.rb +2 -0
- data/lib/action_dispatch/middleware/cookies.rb +81 -98
- data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -25
- data/lib/action_dispatch/middleware/debug_locks.rb +4 -1
- data/lib/action_dispatch/middleware/debug_view.rb +7 -2
- data/lib/action_dispatch/middleware/exception_wrapper.rb +186 -27
- data/lib/action_dispatch/middleware/executor.rb +1 -1
- data/lib/action_dispatch/middleware/flash.rb +7 -0
- data/lib/action_dispatch/middleware/host_authorization.rb +6 -3
- data/lib/action_dispatch/middleware/public_exceptions.rb +5 -3
- data/lib/action_dispatch/middleware/reloader.rb +7 -5
- data/lib/action_dispatch/middleware/remote_ip.rb +17 -16
- data/lib/action_dispatch/middleware/request_id.rb +2 -0
- data/lib/action_dispatch/middleware/server_timing.rb +4 -4
- data/lib/action_dispatch/middleware/session/abstract_store.rb +5 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +11 -5
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +3 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +19 -15
- data/lib/action_dispatch/middleware/ssl.rb +18 -6
- data/lib/action_dispatch/middleware/stack.rb +7 -2
- data/lib/action_dispatch/middleware/static.rb +12 -8
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +7 -7
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +17 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +16 -12
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +46 -37
- data/lib/action_dispatch/railtie.rb +14 -4
- data/lib/action_dispatch/request/session.rb +16 -6
- data/lib/action_dispatch/request/utils.rb +8 -3
- data/lib/action_dispatch/routing/inspector.rb +54 -6
- data/lib/action_dispatch/routing/mapper.rb +35 -24
- data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -0
- data/lib/action_dispatch/routing/redirection.rb +15 -6
- data/lib/action_dispatch/routing/route_set.rb +52 -22
- data/lib/action_dispatch/routing/routes_proxy.rb +10 -15
- data/lib/action_dispatch/routing/url_for.rb +5 -1
- data/lib/action_dispatch/routing.rb +7 -7
- data/lib/action_dispatch/system_test_case.rb +3 -3
- data/lib/action_dispatch/system_testing/browser.rb +20 -19
- data/lib/action_dispatch/system_testing/driver.rb +13 -21
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +27 -16
- data/lib/action_dispatch/testing/assertion_response.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +13 -6
- data/lib/action_dispatch/testing/assertions/routing.rb +67 -28
- data/lib/action_dispatch/testing/assertions.rb +3 -1
- data/lib/action_dispatch/testing/integration.rb +27 -17
- data/lib/action_dispatch/testing/request_encoder.rb +4 -1
- data/lib/action_dispatch/testing/test_process.rb +4 -3
- data/lib/action_dispatch/testing/test_request.rb +1 -1
- data/lib/action_dispatch/testing/test_response.rb +23 -9
- data/lib/action_dispatch.rb +37 -4
- data/lib/action_pack/gem_version.rb +3 -3
- data/lib/action_pack/version.rb +1 -1
- data/lib/action_pack.rb +1 -1
- metadata +62 -26
@@ -57,6 +57,9 @@ module ActionDispatch
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def generate(name, options, path_parameters)
|
60
|
+
original_options = options.dup
|
61
|
+
path_params = options.delete(:path_params) || {}
|
62
|
+
options = path_params.merge(options)
|
60
63
|
constraints = path_parameters.merge(options)
|
61
64
|
missing_keys = nil
|
62
65
|
|
@@ -70,8 +73,11 @@ module ActionDispatch
|
|
70
73
|
|
71
74
|
missing_keys = missing_keys(route, parameterized_parts)
|
72
75
|
next if missing_keys && !missing_keys.empty?
|
73
|
-
params = options.
|
74
|
-
|
76
|
+
params = options.delete_if do |key, _|
|
77
|
+
# top-level params' normal behavior of generating query_params
|
78
|
+
# should be preserved even if the same key is also a bind_param
|
79
|
+
parameterized_parts.key?(key) || route.defaults.key?(key) ||
|
80
|
+
(path_params.key?(key) && !original_options.key?(key))
|
75
81
|
end
|
76
82
|
|
77
83
|
defaults = route.defaults
|
@@ -183,22 +183,22 @@ module ActionDispatch
|
|
183
183
|
end
|
184
184
|
|
185
185
|
def offsets
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
186
|
+
@offsets ||= begin
|
187
|
+
offsets = [0]
|
188
|
+
|
189
|
+
spec.find_all(&:symbol?).each do |node|
|
190
|
+
node = node.to_sym
|
191
|
+
|
192
|
+
if @requirements.key?(node)
|
193
|
+
re = /#{Regexp.union(@requirements[node])}|/
|
194
|
+
offsets.push((re.match("").length - 1) + offsets.last)
|
195
|
+
else
|
196
|
+
offsets << offsets.last
|
197
|
+
end
|
198
198
|
end
|
199
|
-
end
|
200
199
|
|
201
|
-
|
200
|
+
offsets
|
201
|
+
end
|
202
202
|
end
|
203
203
|
end
|
204
204
|
end
|
@@ -5,7 +5,7 @@ module ActionDispatch
|
|
5
5
|
module Journey
|
6
6
|
class Route
|
7
7
|
attr_reader :app, :path, :defaults, :name, :precedence, :constraints,
|
8
|
-
:internal, :scope_options, :ast
|
8
|
+
:internal, :scope_options, :ast, :source_location
|
9
9
|
|
10
10
|
alias :conditions :constraints
|
11
11
|
|
@@ -53,7 +53,7 @@ module ActionDispatch
|
|
53
53
|
##
|
54
54
|
# +path+ is a path constraint.
|
55
55
|
# +constraints+ is a hash of constraints to be applied to this route.
|
56
|
-
def initialize(name:, app: nil, path:, constraints: {}, required_defaults: [], defaults: {}, request_method_match: nil, precedence: 0, scope_options: {}, internal: false)
|
56
|
+
def initialize(name:, app: nil, path:, constraints: {}, required_defaults: [], defaults: {}, request_method_match: nil, precedence: 0, scope_options: {}, internal: false, source_location: nil)
|
57
57
|
@name = name
|
58
58
|
@app = app
|
59
59
|
@path = path
|
@@ -69,6 +69,7 @@ module ActionDispatch
|
|
69
69
|
@path_formatter = @path.build_formatter
|
70
70
|
@scope_options = scope_options
|
71
71
|
@internal = internal
|
72
|
+
@source_location = source_location
|
72
73
|
|
73
74
|
@ast = @path.ast.root
|
74
75
|
@path.ast.route = self
|
@@ -29,7 +29,7 @@ module ActionDispatch
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def serve(req)
|
32
|
-
find_routes(req)
|
32
|
+
find_routes(req) do |match, parameters, route|
|
33
33
|
set_params = req.path_parameters
|
34
34
|
path_info = req.path_info
|
35
35
|
script_name = req.script_name
|
@@ -46,24 +46,25 @@ module ActionDispatch
|
|
46
46
|
}
|
47
47
|
|
48
48
|
req.path_parameters = tmp_params
|
49
|
+
req.route_uri_pattern = route.path.spec.to_s
|
49
50
|
|
50
|
-
|
51
|
+
_, headers, _ = response = route.app.serve(req)
|
51
52
|
|
52
|
-
if "pass" == headers[
|
53
|
+
if "pass" == headers[Constants::X_CASCADE]
|
53
54
|
req.script_name = script_name
|
54
55
|
req.path_info = path_info
|
55
56
|
req.path_parameters = set_params
|
56
57
|
next
|
57
58
|
end
|
58
59
|
|
59
|
-
return
|
60
|
+
return response
|
60
61
|
end
|
61
62
|
|
62
|
-
[404, {
|
63
|
+
[404, { Constants::X_CASCADE => "pass" }, ["Not Found"]]
|
63
64
|
end
|
64
65
|
|
65
66
|
def recognize(rails_req)
|
66
|
-
find_routes(rails_req)
|
67
|
+
find_routes(rails_req) do |match, parameters, route|
|
67
68
|
unless route.path.anchored
|
68
69
|
rails_req.script_name = match.to_s
|
69
70
|
rails_req.path_info = match.post_match
|
@@ -120,14 +121,14 @@ module ActionDispatch
|
|
120
121
|
|
121
122
|
routes.sort_by!(&:precedence)
|
122
123
|
|
123
|
-
routes.
|
124
|
+
routes.each { |r|
|
124
125
|
match_data = r.path.match(path_info)
|
125
126
|
path_parameters = {}
|
126
127
|
match_data.names.each_with_index { |name, i|
|
127
128
|
val = match_data[i + 1]
|
128
129
|
path_parameters[name.to_sym] = Utils.unescape_uri(val) if val
|
129
130
|
}
|
130
|
-
[match_data, path_parameters, r]
|
131
|
+
yield [match_data, path_parameters, r]
|
131
132
|
}
|
132
133
|
end
|
133
134
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionDispatch
|
4
|
+
class LogSubscriber < ActiveSupport::LogSubscriber
|
5
|
+
def redirect(event)
|
6
|
+
payload = event.payload
|
7
|
+
|
8
|
+
info { "Redirected to #{payload[:location]}" }
|
9
|
+
|
10
|
+
info do
|
11
|
+
status = payload[:status]
|
12
|
+
|
13
|
+
message = +"Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in #{event.duration.round}ms"
|
14
|
+
message << "\n\n" if defined?(Rails.env) && Rails.env.development?
|
15
|
+
|
16
|
+
message
|
17
|
+
end
|
18
|
+
end
|
19
|
+
subscribe_log_level :redirect, :info
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
ActionDispatch::LogSubscriber.attach_to :action_dispatch
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "erb"
|
4
3
|
require "uri"
|
5
4
|
require "active_support/actionable_error"
|
6
5
|
|
@@ -30,15 +29,15 @@ module ActionDispatch
|
|
30
29
|
uri = URI.parse location
|
31
30
|
|
32
31
|
if uri.relative? || uri.scheme == "http" || uri.scheme == "https"
|
33
|
-
body = "
|
32
|
+
body = ""
|
34
33
|
else
|
35
|
-
return [400, {
|
34
|
+
return [400, { Rack::CONTENT_TYPE => "text/plain; charset=utf-8" }, ["Invalid redirection URI"]]
|
36
35
|
end
|
37
36
|
|
38
37
|
[302, {
|
39
|
-
|
40
|
-
|
41
|
-
|
38
|
+
Rack::CONTENT_TYPE => "text/html; charset=#{Response.default_charset}",
|
39
|
+
Rack::CONTENT_LENGTH => body.bytesize.to_s,
|
40
|
+
ActionDispatch::Constants::LOCATION => location,
|
42
41
|
}, [body]]
|
43
42
|
end
|
44
43
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionDispatch
|
4
|
+
# = Action Dispatch \AssumeSSL
|
5
|
+
#
|
6
|
+
# When proxying through a load balancer that terminates SSL, the forwarded request will appear
|
7
|
+
# as though it's HTTP instead of HTTPS to the application. This makes redirects and cookie
|
8
|
+
# security target HTTP instead of HTTPS. This middleware makes the server assume that the
|
9
|
+
# proxy already terminated SSL, and that the request really is HTTPS.
|
10
|
+
class AssumeSSL
|
11
|
+
def initialize(app)
|
12
|
+
@app = app
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
env["HTTPS"] = "on"
|
17
|
+
env["HTTP_X_FORWARDED_PORT"] = "443"
|
18
|
+
env["HTTP_X_FORWARDED_PROTO"] = "https"
|
19
|
+
env["rack.url_scheme"] = "https"
|
20
|
+
|
21
|
+
@app.call(env)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -70,7 +70,7 @@ module ActionDispatch
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def cookies_same_site_protection
|
73
|
-
get_header(Cookies::COOKIES_SAME_SITE_PROTECTION)
|
73
|
+
get_header(Cookies::COOKIES_SAME_SITE_PROTECTION)&.call(self)
|
74
74
|
end
|
75
75
|
|
76
76
|
def cookies_digest
|
@@ -92,7 +92,7 @@ module ActionDispatch
|
|
92
92
|
include RequestCookieMethods
|
93
93
|
end
|
94
94
|
|
95
|
-
# Read and write data to cookies through ActionController::
|
95
|
+
# Read and write data to cookies through ActionController::Cookies#cookies.
|
96
96
|
#
|
97
97
|
# When reading cookie data, the data is read from the HTTP request header, Cookie.
|
98
98
|
# When writing cookie data, the data is sent out in the HTTP response header, +Set-Cookie+.
|
@@ -160,13 +160,18 @@ module ActionDispatch
|
|
160
160
|
# to <tt>:all</tt>. To support multiple domains, provide an array, and
|
161
161
|
# the first domain matching <tt>request.host</tt> will be used. Make
|
162
162
|
# sure to specify the <tt>:domain</tt> option with <tt>:all</tt> or
|
163
|
-
# <tt>Array</tt> again when deleting cookies.
|
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.
|
164
166
|
#
|
165
167
|
# domain: nil # Does not set cookie domain. (default)
|
166
168
|
# domain: :all # Allow the cookie for the top most level
|
167
169
|
# # domain and subdomains.
|
168
170
|
# domain: %w(.example.com .example.org) # Allow the cookie
|
169
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
|
174
|
+
#
|
170
175
|
#
|
171
176
|
# * <tt>:tld_length</tt> - When using <tt>:domain => :all</tt>, this option can be used to explicitly
|
172
177
|
# set the TLD length when using a short (<= 3 character) domain that is being interpreted as part of a TLD.
|
@@ -178,7 +183,8 @@ module ActionDispatch
|
|
178
183
|
# only HTTP. Defaults to +false+.
|
179
184
|
# * <tt>:same_site</tt> - The value of the +SameSite+ cookie attribute, which
|
180
185
|
# determines how this cookie should be restricted in cross-site contexts.
|
181
|
-
# Possible values are +:none+, +:lax+, and +:strict+. Defaults to
|
186
|
+
# Possible values are +nil+, +:none+, +:lax+, and +:strict+. Defaults to
|
187
|
+
# +:lax+.
|
182
188
|
class Cookies
|
183
189
|
HTTP_HEADER = "Set-Cookie"
|
184
190
|
GENERATOR_KEY = "action_dispatch.key_generator"
|
@@ -376,6 +382,8 @@ module ActionDispatch
|
|
376
382
|
# Removes the cookie on the client machine by setting the value to an empty string
|
377
383
|
# and the expiration date in the past. Like <tt>[]=</tt>, you can pass in
|
378
384
|
# an options hash to delete cookies with extra data such as a <tt>:path</tt>.
|
385
|
+
#
|
386
|
+
# Returns the value of the cookie, or +nil+ if the cookie does not exist.
|
379
387
|
def delete(name, options = {})
|
380
388
|
return unless @cookies.has_key? name.to_s
|
381
389
|
|
@@ -401,9 +409,15 @@ module ActionDispatch
|
|
401
409
|
@cookies.each_key { |k| delete(k, options) }
|
402
410
|
end
|
403
411
|
|
404
|
-
def write(
|
405
|
-
|
406
|
-
|
412
|
+
def write(response)
|
413
|
+
@set_cookies.each do |name, value|
|
414
|
+
if write_cookie?(value)
|
415
|
+
response.set_cookie(name, value)
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
@delete_cookies.each do |name, value|
|
420
|
+
response.delete_cookie(name, value)
|
407
421
|
end
|
408
422
|
end
|
409
423
|
|
@@ -414,19 +428,6 @@ module ActionDispatch
|
|
414
428
|
::Rack::Utils.escape(string)
|
415
429
|
end
|
416
430
|
|
417
|
-
def make_set_cookie_header(header)
|
418
|
-
header = @set_cookies.inject(header) { |m, (k, v)|
|
419
|
-
if write_cookie?(v)
|
420
|
-
::Rack::Utils.add_cookie_to_header(m, k, v)
|
421
|
-
else
|
422
|
-
m
|
423
|
-
end
|
424
|
-
}
|
425
|
-
@delete_cookies.inject(header) { |m, (k, v)|
|
426
|
-
::Rack::Utils.add_remove_cookie_to_header(m, k, v)
|
427
|
-
}
|
428
|
-
end
|
429
|
-
|
430
431
|
def write_cookie?(cookie)
|
431
432
|
request.ssl? || !cookie[:secure] || always_write_cookie || request.host.end_with?(".onion")
|
432
433
|
end
|
@@ -438,8 +439,9 @@ module ActionDispatch
|
|
438
439
|
|
439
440
|
options[:path] ||= "/"
|
440
441
|
|
441
|
-
|
442
|
-
|
442
|
+
unless options.key?(:same_site)
|
443
|
+
options[:same_site] = request.cookies_same_site_protection
|
444
|
+
end
|
443
445
|
|
444
446
|
if options[:domain] == :all || options[:domain] == "all"
|
445
447
|
cookie_domain = ""
|
@@ -470,7 +472,7 @@ module ActionDispatch
|
|
470
472
|
end
|
471
473
|
|
472
474
|
options[:domain] = if cookie_domain.present?
|
473
|
-
|
475
|
+
cookie_domain
|
474
476
|
end
|
475
477
|
elsif options[:domain].is_a? Array
|
476
478
|
# If host matches one of the supplied domains.
|
@@ -478,6 +480,8 @@ module ActionDispatch
|
|
478
480
|
domain = domain.delete_prefix(".")
|
479
481
|
request.host == domain || request.host.end_with?(".#{domain}")
|
480
482
|
end
|
483
|
+
elsif options[:domain].respond_to?(:call)
|
484
|
+
options[:domain] = options[:domain].call(request)
|
481
485
|
end
|
482
486
|
end
|
483
487
|
end
|
@@ -541,75 +545,57 @@ module ActionDispatch
|
|
541
545
|
end
|
542
546
|
end
|
543
547
|
|
544
|
-
class MarshalWithJsonFallback # :nodoc:
|
545
|
-
def self.load(value)
|
546
|
-
Marshal.load(value)
|
547
|
-
rescue TypeError => e
|
548
|
-
ActiveSupport::JSON.decode(value) rescue raise e
|
549
|
-
end
|
550
|
-
|
551
|
-
def self.dump(value)
|
552
|
-
Marshal.dump(value)
|
553
|
-
end
|
554
|
-
end
|
555
|
-
|
556
|
-
class JsonSerializer # :nodoc:
|
557
|
-
def self.load(value)
|
558
|
-
ActiveSupport::JSON.decode(value)
|
559
|
-
end
|
560
|
-
|
561
|
-
def self.dump(value)
|
562
|
-
ActiveSupport::JSON.encode(value)
|
563
|
-
end
|
564
|
-
end
|
565
|
-
|
566
548
|
module SerializedCookieJars # :nodoc:
|
567
|
-
MARSHAL_SIGNATURE = "\x04\x08"
|
568
549
|
SERIALIZER = ActiveSupport::MessageEncryptor::NullSerializer
|
569
550
|
|
570
551
|
protected
|
571
|
-
def
|
572
|
-
request.
|
552
|
+
def digest
|
553
|
+
request.cookies_digest || "SHA1"
|
573
554
|
end
|
574
555
|
|
575
|
-
|
576
|
-
|
556
|
+
private
|
557
|
+
def serializer
|
558
|
+
@serializer ||=
|
559
|
+
case request.cookies_serializer
|
560
|
+
when nil
|
561
|
+
ActiveSupport::Messages::SerializerWithFallback[:marshal]
|
562
|
+
when :hybrid
|
563
|
+
ActiveSupport::Messages::SerializerWithFallback[:json_allow_marshal]
|
564
|
+
when Symbol
|
565
|
+
ActiveSupport::Messages::SerializerWithFallback[request.cookies_serializer]
|
566
|
+
else
|
567
|
+
request.cookies_serializer
|
568
|
+
end
|
577
569
|
end
|
578
570
|
|
579
|
-
def
|
580
|
-
|
581
|
-
|
571
|
+
def reserialize?(dumped)
|
572
|
+
serializer.is_a?(ActiveSupport::Messages::SerializerWithFallback) &&
|
573
|
+
serializer != ActiveSupport::Messages::SerializerWithFallback[:marshal] &&
|
574
|
+
!serializer.dumped?(dumped)
|
575
|
+
end
|
582
576
|
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
when rotate
|
590
|
-
serializer.load(value).tap do |v|
|
591
|
-
self[name] = { value: v }
|
592
|
-
end
|
593
|
-
else
|
594
|
-
serializer.load(value)
|
577
|
+
def parse(name, dumped, force_reserialize: false, **)
|
578
|
+
if dumped
|
579
|
+
begin
|
580
|
+
value = serializer.load(dumped)
|
581
|
+
rescue StandardError
|
582
|
+
return
|
595
583
|
end
|
584
|
+
|
585
|
+
self[name] = { value: value } if force_reserialize || reserialize?(dumped)
|
586
|
+
|
587
|
+
value
|
596
588
|
end
|
597
589
|
end
|
598
590
|
|
599
|
-
def
|
600
|
-
|
601
|
-
case serializer
|
602
|
-
when :marshal
|
603
|
-
MarshalWithJsonFallback
|
604
|
-
when :json, :hybrid
|
605
|
-
JsonSerializer
|
606
|
-
else
|
607
|
-
serializer
|
608
|
-
end
|
591
|
+
def commit(name, options)
|
592
|
+
options[:value] = serializer.dump(options[:value])
|
609
593
|
end
|
610
594
|
|
611
|
-
def
|
612
|
-
|
595
|
+
def check_for_overflow!(name, options)
|
596
|
+
if options[:value].bytesize > MAX_COOKIE_SIZE
|
597
|
+
raise CookieOverflow, "#{name} cookie overflowed with size #{options[:value].bytesize} bytes"
|
598
|
+
end
|
613
599
|
end
|
614
600
|
end
|
615
601
|
|
@@ -630,15 +616,15 @@ module ActionDispatch
|
|
630
616
|
|
631
617
|
private
|
632
618
|
def parse(name, signed_message, purpose: nil)
|
633
|
-
|
634
|
-
|
635
|
-
|
619
|
+
rotated = false
|
620
|
+
data = @verifier.verified(signed_message, purpose: purpose, on_rotation: -> { rotated = true })
|
621
|
+
super(name, data, force_reserialize: rotated)
|
636
622
|
end
|
637
623
|
|
638
624
|
def commit(name, options)
|
639
|
-
|
640
|
-
|
641
|
-
|
625
|
+
super
|
626
|
+
options[:value] = @verifier.generate(options[:value], **cookie_metadata(name, options))
|
627
|
+
check_for_overflow!(name, options)
|
642
628
|
end
|
643
629
|
end
|
644
630
|
|
@@ -680,17 +666,17 @@ module ActionDispatch
|
|
680
666
|
|
681
667
|
private
|
682
668
|
def parse(name, encrypted_message, purpose: nil)
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
rescue ActiveSupport::MessageEncryptor::InvalidMessage, ActiveSupport::MessageVerifier::InvalidSignature
|
669
|
+
rotated = false
|
670
|
+
data = @encryptor.decrypt_and_verify(encrypted_message, purpose: purpose, on_rotation: -> { rotated = true })
|
671
|
+
super(name, data, force_reserialize: rotated)
|
672
|
+
rescue ActiveSupport::MessageEncryptor::InvalidMessage, ActiveSupport::MessageVerifier::InvalidSignature
|
687
673
|
nil
|
688
674
|
end
|
689
675
|
|
690
676
|
def commit(name, options)
|
691
|
-
|
692
|
-
|
693
|
-
|
677
|
+
super
|
678
|
+
options[:value] = @encryptor.encrypt_and_sign(options[:value], **cookie_metadata(name, options))
|
679
|
+
check_for_overflow!(name, options)
|
694
680
|
end
|
695
681
|
end
|
696
682
|
|
@@ -699,21 +685,18 @@ module ActionDispatch
|
|
699
685
|
end
|
700
686
|
|
701
687
|
def call(env)
|
702
|
-
request = ActionDispatch::Request.new
|
703
|
-
|
704
|
-
status, headers, body = @app.call(env)
|
688
|
+
request = ActionDispatch::Request.new(env)
|
689
|
+
response = @app.call(env)
|
705
690
|
|
706
691
|
if request.have_cookie_jar?
|
707
692
|
cookie_jar = request.cookie_jar
|
708
693
|
unless cookie_jar.committed?
|
709
|
-
|
710
|
-
|
711
|
-
headers[HTTP_HEADER] = headers[HTTP_HEADER].join("\n")
|
712
|
-
end
|
694
|
+
response = Rack::Response[*response]
|
695
|
+
cookie_jar.write(response)
|
713
696
|
end
|
714
697
|
end
|
715
698
|
|
716
|
-
|
699
|
+
response.to_a
|
717
700
|
end
|
718
701
|
end
|
719
702
|
end
|