actionpack 7.0.8 → 7.1.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +360 -353
- 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 +7 -4
- 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 +40 -18
- 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 +4 -4
- data/lib/action_pack/version.rb +1 -1
- data/lib/action_pack.rb +1 -1
- metadata +64 -28
@@ -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
|