actionpack 7.2.2.1 → 8.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +83 -139
- data/lib/abstract_controller/helpers.rb +0 -2
- data/lib/action_controller/metal/allow_browser.rb +1 -1
- data/lib/action_controller/metal/conditional_get.rb +5 -1
- data/lib/action_controller/metal/http_authentication.rb +4 -1
- data/lib/action_controller/metal/instrumentation.rb +1 -2
- data/lib/action_controller/metal/live.rb +10 -2
- data/lib/action_controller/metal/rate_limiting.rb +13 -4
- data/lib/action_controller/metal/renderers.rb +2 -1
- data/lib/action_controller/metal/streaming.rb +5 -84
- data/lib/action_controller/metal/strong_parameters.rb +274 -73
- data/lib/action_controller/railtie.rb +1 -1
- data/lib/action_controller/test_case.rb +2 -0
- data/lib/action_dispatch/http/cache.rb +27 -10
- data/lib/action_dispatch/http/content_security_policy.rb +13 -25
- data/lib/action_dispatch/http/filter_parameters.rb +4 -9
- data/lib/action_dispatch/http/filter_redirect.rb +2 -9
- data/lib/action_dispatch/http/permissions_policy.rb +2 -0
- data/lib/action_dispatch/http/request.rb +4 -2
- data/lib/action_dispatch/journey/parser.rb +99 -196
- data/lib/action_dispatch/journey/scanner.rb +40 -42
- data/lib/action_dispatch/middleware/cookies.rb +4 -2
- data/lib/action_dispatch/middleware/debug_exceptions.rb +16 -3
- data/lib/action_dispatch/middleware/request_id.rb +2 -1
- data/lib/action_dispatch/middleware/ssl.rb +13 -3
- data/lib/action_dispatch/railtie.rb +2 -0
- data/lib/action_dispatch/routing/inspector.rb +1 -1
- data/lib/action_dispatch/routing/mapper.rb +25 -17
- data/lib/action_dispatch/routing/route_set.rb +18 -6
- data/lib/action_dispatch/system_testing/browser.rb +12 -21
- data/lib/action_dispatch.rb +0 -4
- data/lib/action_pack/gem_version.rb +4 -4
- metadata +13 -35
- data/lib/action_dispatch/journey/parser.y +0 -50
- data/lib/action_dispatch/journey/parser_extras.rb +0 -33
@@ -8,7 +8,8 @@ require "active_support/core_ext/array/wrap"
|
|
8
8
|
module ActionDispatch # :nodoc:
|
9
9
|
# # Action Dispatch Content Security Policy
|
10
10
|
#
|
11
|
-
# Configures the HTTP [Content-Security-Policy]
|
11
|
+
# Configures the HTTP [Content-Security-Policy]
|
12
|
+
# (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy)
|
12
13
|
# response header to help protect against XSS and
|
13
14
|
# injection attacks.
|
14
15
|
#
|
@@ -26,9 +27,6 @@ module ActionDispatch # :nodoc:
|
|
26
27
|
# policy.report_uri "/csp-violation-report-endpoint"
|
27
28
|
# end
|
28
29
|
class ContentSecurityPolicy
|
29
|
-
class InvalidDirectiveError < StandardError
|
30
|
-
end
|
31
|
-
|
32
30
|
class Middleware
|
33
31
|
def initialize(app)
|
34
32
|
@app = app
|
@@ -128,6 +126,7 @@ module ActionDispatch # :nodoc:
|
|
128
126
|
MAPPINGS = {
|
129
127
|
self: "'self'",
|
130
128
|
unsafe_eval: "'unsafe-eval'",
|
129
|
+
wasm_unsafe_eval: "'wasm-unsafe-eval'",
|
131
130
|
unsafe_hashes: "'unsafe-hashes'",
|
132
131
|
unsafe_inline: "'unsafe-inline'",
|
133
132
|
none: "'none'",
|
@@ -228,7 +227,8 @@ module ActionDispatch # :nodoc:
|
|
228
227
|
end
|
229
228
|
end
|
230
229
|
|
231
|
-
# Enable the [report-uri]
|
230
|
+
# Enable the [report-uri]
|
231
|
+
# (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-uri)
|
232
232
|
# directive. Violation reports will be sent to the
|
233
233
|
# specified URI:
|
234
234
|
#
|
@@ -238,7 +238,8 @@ module ActionDispatch # :nodoc:
|
|
238
238
|
@directives["report-uri"] = [uri]
|
239
239
|
end
|
240
240
|
|
241
|
-
# Specify asset types for which [Subresource Integrity]
|
241
|
+
# Specify asset types for which [Subresource Integrity]
|
242
|
+
# (https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) is required:
|
242
243
|
#
|
243
244
|
# policy.require_sri_for :script, :style
|
244
245
|
#
|
@@ -254,7 +255,8 @@ module ActionDispatch # :nodoc:
|
|
254
255
|
end
|
255
256
|
end
|
256
257
|
|
257
|
-
# Specify whether a [sandbox]
|
258
|
+
# Specify whether a [sandbox]
|
259
|
+
# (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox)
|
258
260
|
# should be enabled for the requested resource:
|
259
261
|
#
|
260
262
|
# policy.sandbox
|
@@ -322,9 +324,9 @@ module ActionDispatch # :nodoc:
|
|
322
324
|
@directives.map do |directive, sources|
|
323
325
|
if sources.is_a?(Array)
|
324
326
|
if nonce && nonce_directive?(directive, nonce_directives)
|
325
|
-
"#{directive} #{build_directive(
|
327
|
+
"#{directive} #{build_directive(sources, context).join(' ')} 'nonce-#{nonce}'"
|
326
328
|
else
|
327
|
-
"#{directive} #{build_directive(
|
329
|
+
"#{directive} #{build_directive(sources, context).join(' ')}"
|
328
330
|
end
|
329
331
|
elsif sources
|
330
332
|
directive
|
@@ -334,22 +336,8 @@ module ActionDispatch # :nodoc:
|
|
334
336
|
end
|
335
337
|
end
|
336
338
|
|
337
|
-
def
|
338
|
-
sources.
|
339
|
-
if source.include?(";") || source != source.gsub(/[[:space:]]/, "")
|
340
|
-
raise InvalidDirectiveError, <<~MSG.squish
|
341
|
-
Invalid Content Security Policy #{directive}: "#{source}".
|
342
|
-
Directive values must not contain whitespace or semicolons.
|
343
|
-
Please use multiple arguments or other directive methods instead.
|
344
|
-
MSG
|
345
|
-
end
|
346
|
-
end
|
347
|
-
end
|
348
|
-
|
349
|
-
def build_directive(directive, sources, context)
|
350
|
-
resolved_sources = sources.map { |source| resolve_source(source, context) }
|
351
|
-
|
352
|
-
validate(directive, resolved_sources)
|
339
|
+
def build_directive(sources, context)
|
340
|
+
sources.map { |source| resolve_source(source, context) }
|
353
341
|
end
|
354
342
|
|
355
343
|
def resolve_source(source, context)
|
@@ -68,17 +68,12 @@ module ActionDispatch
|
|
68
68
|
ActiveSupport::ParameterFilter.new(filters)
|
69
69
|
end
|
70
70
|
|
71
|
+
KV_RE = "[^&;=]+"
|
72
|
+
PAIR_RE = %r{(#{KV_RE})=(#{KV_RE})}
|
71
73
|
def filtered_query_string # :doc:
|
72
|
-
|
73
|
-
|
74
|
-
if part.include?("=")
|
75
|
-
key, value = part.split("=", 2)
|
76
|
-
parameter_filter.filter(key => value).first.join("=")
|
77
|
-
else
|
78
|
-
part
|
79
|
-
end
|
74
|
+
query_string.gsub(PAIR_RE) do |_|
|
75
|
+
parameter_filter.filter($1 => $2).first.join("=")
|
80
76
|
end
|
81
|
-
filtered_parts.join("")
|
82
77
|
end
|
83
78
|
end
|
84
79
|
end
|
@@ -37,16 +37,9 @@ module ActionDispatch
|
|
37
37
|
def parameter_filtered_location
|
38
38
|
uri = URI.parse(location)
|
39
39
|
unless uri.query.nil? || uri.query.empty?
|
40
|
-
|
41
|
-
|
42
|
-
if part.include?("=")
|
43
|
-
key, value = part.split("=", 2)
|
44
|
-
request.parameter_filter.filter(key => value).first.join("=")
|
45
|
-
else
|
46
|
-
part
|
47
|
-
end
|
40
|
+
uri.query.gsub!(FilterParameters::PAIR_RE) do
|
41
|
+
request.parameter_filter.filter($1 => $2).first.join("=")
|
48
42
|
end
|
49
|
-
uri.query = filtered_parts.join("")
|
50
43
|
end
|
51
44
|
uri.to_s
|
52
45
|
rescue URI::Error
|
@@ -86,12 +86,14 @@ module ActionDispatch # :nodoc:
|
|
86
86
|
ambient_light_sensor: "ambient-light-sensor",
|
87
87
|
autoplay: "autoplay",
|
88
88
|
camera: "camera",
|
89
|
+
display_capture: "display-capture",
|
89
90
|
encrypted_media: "encrypted-media",
|
90
91
|
fullscreen: "fullscreen",
|
91
92
|
geolocation: "geolocation",
|
92
93
|
gyroscope: "gyroscope",
|
93
94
|
hid: "hid",
|
94
95
|
idle_detection: "idle-detection",
|
96
|
+
keyboard_map: "keyboard-map",
|
95
97
|
magnetometer: "magnetometer",
|
96
98
|
microphone: "microphone",
|
97
99
|
midi: "midi",
|
@@ -55,6 +55,8 @@ module ActionDispatch
|
|
55
55
|
METHOD
|
56
56
|
end
|
57
57
|
|
58
|
+
TRANSFER_ENCODING = "HTTP_TRANSFER_ENCODING" # :nodoc:
|
59
|
+
|
58
60
|
def self.empty
|
59
61
|
new({})
|
60
62
|
end
|
@@ -282,7 +284,7 @@ module ActionDispatch
|
|
282
284
|
|
283
285
|
# Returns the content length of the request as an integer.
|
284
286
|
def content_length
|
285
|
-
return raw_post.bytesize if
|
287
|
+
return raw_post.bytesize if has_header?(TRANSFER_ENCODING)
|
286
288
|
super.to_i
|
287
289
|
end
|
288
290
|
|
@@ -468,7 +470,7 @@ module ActionDispatch
|
|
468
470
|
def read_body_stream
|
469
471
|
if body_stream
|
470
472
|
reset_stream(body_stream) do
|
471
|
-
if
|
473
|
+
if has_header?(TRANSFER_ENCODING)
|
472
474
|
body_stream.read # Read body stream until EOF if "Transfer-Encoding" is present
|
473
475
|
else
|
474
476
|
body_stream.read(content_length)
|
@@ -1,200 +1,103 @@
|
|
1
|
-
#
|
2
|
-
# DO NOT MODIFY!!!!
|
3
|
-
# This file is automatically generated by Racc 1.4.16 from
|
4
|
-
# Racc grammar file "".
|
1
|
+
# frozen_string_literal: true
|
5
2
|
|
6
|
-
|
3
|
+
require "action_dispatch/journey/scanner"
|
4
|
+
require "action_dispatch/journey/nodes/node"
|
7
5
|
|
8
|
-
require 'racc/parser.rb'
|
9
|
-
|
10
|
-
# :stopdoc:
|
11
|
-
|
12
|
-
require "action_dispatch/journey/parser_extras"
|
13
6
|
module ActionDispatch
|
14
|
-
module Journey
|
15
|
-
class Parser
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
"$end",
|
111
|
-
"error",
|
112
|
-
"SLASH",
|
113
|
-
"LITERAL",
|
114
|
-
"SYMBOL",
|
115
|
-
"LPAREN",
|
116
|
-
"RPAREN",
|
117
|
-
"DOT",
|
118
|
-
"STAR",
|
119
|
-
"OR",
|
120
|
-
"$start",
|
121
|
-
"expressions",
|
122
|
-
"expression",
|
123
|
-
"or",
|
124
|
-
"terminal",
|
125
|
-
"group",
|
126
|
-
"star",
|
127
|
-
"symbol",
|
128
|
-
"literal",
|
129
|
-
"slash",
|
130
|
-
"dot" ]
|
131
|
-
|
132
|
-
Racc_debug_parser = false
|
133
|
-
|
134
|
-
##### State transition tables end #####
|
135
|
-
|
136
|
-
# reduce 0 omitted
|
137
|
-
|
138
|
-
def _reduce_1(val, _values)
|
139
|
-
Cat.new(val.first, val.last)
|
140
|
-
end
|
141
|
-
|
142
|
-
def _reduce_2(val, _values)
|
143
|
-
val.first
|
144
|
-
end
|
145
|
-
|
146
|
-
# reduce 3 omitted
|
147
|
-
|
148
|
-
# reduce 4 omitted
|
149
|
-
|
150
|
-
# reduce 5 omitted
|
151
|
-
|
152
|
-
# reduce 6 omitted
|
153
|
-
|
154
|
-
def _reduce_7(val, _values)
|
155
|
-
Group.new(val[1])
|
156
|
-
end
|
157
|
-
|
158
|
-
def _reduce_8(val, _values)
|
159
|
-
Or.new([val.first, val.last])
|
160
|
-
end
|
161
|
-
|
162
|
-
def _reduce_9(val, _values)
|
163
|
-
Or.new([val.first, val.last])
|
164
|
-
end
|
165
|
-
|
166
|
-
def _reduce_10(val, _values)
|
167
|
-
Star.new(Symbol.new(val.last, Symbol::GREEDY_EXP))
|
7
|
+
module Journey # :nodoc:
|
8
|
+
class Parser # :nodoc:
|
9
|
+
include Journey::Nodes
|
10
|
+
|
11
|
+
def self.parse(string)
|
12
|
+
new.parse string
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@scanner = Scanner.new
|
17
|
+
@next_token = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse(string)
|
21
|
+
@scanner.scan_setup(string)
|
22
|
+
advance_token
|
23
|
+
do_parse
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def advance_token
|
28
|
+
@next_token = @scanner.next_token
|
29
|
+
end
|
30
|
+
|
31
|
+
def do_parse
|
32
|
+
parse_expressions
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse_expressions
|
36
|
+
node = parse_expression
|
37
|
+
|
38
|
+
while @next_token
|
39
|
+
case @next_token
|
40
|
+
when :RPAREN
|
41
|
+
break
|
42
|
+
when :OR
|
43
|
+
node = parse_or(node)
|
44
|
+
else
|
45
|
+
node = Cat.new(node, parse_expressions)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
node
|
50
|
+
end
|
51
|
+
|
52
|
+
def parse_or(lhs)
|
53
|
+
advance_token
|
54
|
+
node = parse_expression
|
55
|
+
Or.new([lhs, node])
|
56
|
+
end
|
57
|
+
|
58
|
+
def parse_expression
|
59
|
+
if @next_token == :STAR
|
60
|
+
parse_star
|
61
|
+
elsif @next_token == :LPAREN
|
62
|
+
parse_group
|
63
|
+
else
|
64
|
+
parse_terminal
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def parse_star
|
69
|
+
node = Star.new(Symbol.new(@scanner.last_string, Symbol::GREEDY_EXP))
|
70
|
+
advance_token
|
71
|
+
node
|
72
|
+
end
|
73
|
+
|
74
|
+
def parse_group
|
75
|
+
advance_token
|
76
|
+
node = parse_expressions
|
77
|
+
if @next_token == :RPAREN
|
78
|
+
node = Group.new(node)
|
79
|
+
advance_token
|
80
|
+
node
|
81
|
+
else
|
82
|
+
raise ArgumentError, "missing right parenthesis."
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def parse_terminal
|
87
|
+
node = case @next_token
|
88
|
+
when :SYMBOL
|
89
|
+
Symbol.new(@scanner.last_string)
|
90
|
+
when :LITERAL
|
91
|
+
Literal.new(@scanner.last_literal)
|
92
|
+
when :SLASH
|
93
|
+
Slash.new("/")
|
94
|
+
when :DOT
|
95
|
+
Dot.new(".")
|
96
|
+
end
|
97
|
+
|
98
|
+
advance_token
|
99
|
+
node
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
168
103
|
end
|
169
|
-
|
170
|
-
# reduce 11 omitted
|
171
|
-
|
172
|
-
# reduce 12 omitted
|
173
|
-
|
174
|
-
# reduce 13 omitted
|
175
|
-
|
176
|
-
# reduce 14 omitted
|
177
|
-
|
178
|
-
def _reduce_15(val, _values)
|
179
|
-
Slash.new(val.first)
|
180
|
-
end
|
181
|
-
|
182
|
-
def _reduce_16(val, _values)
|
183
|
-
Symbol.new(val.first)
|
184
|
-
end
|
185
|
-
|
186
|
-
def _reduce_17(val, _values)
|
187
|
-
Literal.new(val.first)
|
188
|
-
end
|
189
|
-
|
190
|
-
def _reduce_18(val, _values)
|
191
|
-
Dot.new(val.first)
|
192
|
-
end
|
193
|
-
|
194
|
-
def _reduce_none(val, _values)
|
195
|
-
val[0]
|
196
|
-
end
|
197
|
-
|
198
|
-
end # class Parser
|
199
|
-
end # module Journey
|
200
|
-
end # module ActionDispatch
|
@@ -7,64 +7,62 @@ require "strscan"
|
|
7
7
|
module ActionDispatch
|
8
8
|
module Journey # :nodoc:
|
9
9
|
class Scanner # :nodoc:
|
10
|
+
STATIC_TOKENS = Array.new(150)
|
11
|
+
STATIC_TOKENS[".".ord] = :DOT
|
12
|
+
STATIC_TOKENS["/".ord] = :SLASH
|
13
|
+
STATIC_TOKENS["(".ord] = :LPAREN
|
14
|
+
STATIC_TOKENS[")".ord] = :RPAREN
|
15
|
+
STATIC_TOKENS["|".ord] = :OR
|
16
|
+
STATIC_TOKENS[":".ord] = :SYMBOL
|
17
|
+
STATIC_TOKENS["*".ord] = :STAR
|
18
|
+
STATIC_TOKENS.freeze
|
19
|
+
|
20
|
+
class Scanner < StringScanner
|
21
|
+
unless method_defined?(:peek_byte) # https://github.com/ruby/strscan/pull/89
|
22
|
+
def peek_byte
|
23
|
+
string.getbyte(pos)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
10
28
|
def initialize
|
11
|
-
@
|
29
|
+
@scanner = nil
|
30
|
+
@length = nil
|
12
31
|
end
|
13
32
|
|
14
33
|
def scan_setup(str)
|
15
|
-
@
|
34
|
+
@scanner = Scanner.new(str)
|
16
35
|
end
|
17
36
|
|
18
|
-
def
|
19
|
-
@
|
20
|
-
end
|
37
|
+
def next_token
|
38
|
+
return if @scanner.eos?
|
21
39
|
|
22
|
-
|
23
|
-
|
40
|
+
until token = scan || @scanner.eos?; end
|
41
|
+
token
|
24
42
|
end
|
25
43
|
|
26
|
-
def
|
27
|
-
@
|
44
|
+
def last_string
|
45
|
+
-@scanner.string.byteslice(@scanner.pos - @length, @length)
|
28
46
|
end
|
29
47
|
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
token
|
48
|
+
def last_literal
|
49
|
+
last_str = @scanner.string.byteslice(@scanner.pos - @length, @length)
|
50
|
+
last_str.tr! "\\", ""
|
51
|
+
-last_str
|
35
52
|
end
|
36
53
|
|
37
54
|
private
|
38
|
-
# takes advantage of String @- deduping capabilities in Ruby 2.5 upwards see:
|
39
|
-
# https://bugs.ruby-lang.org/issues/13077
|
40
|
-
def dedup_scan(regex)
|
41
|
-
r = @ss.scan(regex)
|
42
|
-
r ? -r : nil
|
43
|
-
end
|
44
|
-
|
45
55
|
def scan
|
56
|
+
next_byte = @scanner.peek_byte
|
46
57
|
case
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
[:OR, "|"]
|
56
|
-
when @ss.skip(/\./)
|
57
|
-
[:DOT, "."]
|
58
|
-
when text = dedup_scan(/:\w+/)
|
59
|
-
[:SYMBOL, text]
|
60
|
-
when text = dedup_scan(/\*\w+/)
|
61
|
-
[:STAR, text]
|
62
|
-
when text = @ss.scan(/(?:[\w%\-~!$&'*+,;=@]|\\[:()])+/)
|
63
|
-
text.tr! "\\", ""
|
64
|
-
[:LITERAL, -text]
|
65
|
-
# any char
|
66
|
-
when text = dedup_scan(/./)
|
67
|
-
[:LITERAL, text]
|
58
|
+
when (token = STATIC_TOKENS[next_byte])
|
59
|
+
@scanner.pos += 1
|
60
|
+
@length = @scanner.skip(/\w+/).to_i + 1 if token == :SYMBOL || token == :STAR
|
61
|
+
token
|
62
|
+
when @length = @scanner.skip(/(?:[\w%\-~!$&'*+,;=@]|\\[:()])+/)
|
63
|
+
:LITERAL
|
64
|
+
when @length = @scanner.skip(/./)
|
65
|
+
:LITERAL
|
68
66
|
end
|
69
67
|
end
|
70
68
|
end
|
@@ -116,13 +116,15 @@ module ActionDispatch
|
|
116
116
|
# cookies[:login] = { value: "XJ-122", expires: Time.utc(2020, 10, 15, 5) }
|
117
117
|
#
|
118
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
119
|
# cookies.signed[:user_id] = current_user.id
|
120
|
+
# # It can be read using the signed method.
|
121
|
+
# cookies.signed[:user_id] # => 123
|
121
122
|
#
|
122
123
|
# # Sets an encrypted cookie value before sending it to the client which
|
123
124
|
# # prevent users from reading and tampering with its value.
|
124
|
-
# # It can be read using the encrypted method `cookies.encrypted[:name]`
|
125
125
|
# cookies.encrypted[:discount] = 45
|
126
|
+
# # It can be read using the encrypted method.
|
127
|
+
# cookies.encrypted[:discount] # => 45
|
126
128
|
#
|
127
129
|
# # Sets a "permanent" cookie (which expires in 20 years from now).
|
128
130
|
# cookies.permanent[:login] = "XJ-122"
|
@@ -142,17 +142,30 @@ module ActionDispatch
|
|
142
142
|
|
143
143
|
message = []
|
144
144
|
message << " "
|
145
|
-
message << "#{wrapper.exception_class_name} (#{wrapper.message}):"
|
146
145
|
if wrapper.has_cause?
|
147
|
-
message << "
|
146
|
+
message << "#{wrapper.exception_class_name} (#{wrapper.message})"
|
148
147
|
wrapper.wrapped_causes.each do |wrapped_cause|
|
149
|
-
message << "#{wrapped_cause.exception_class_name} (#{wrapped_cause.message})"
|
148
|
+
message << "Caused by: #{wrapped_cause.exception_class_name} (#{wrapped_cause.message})"
|
150
149
|
end
|
150
|
+
|
151
|
+
message << "\nInformation for: #{wrapper.exception_class_name} (#{wrapper.message}):"
|
152
|
+
else
|
153
|
+
message << "#{wrapper.exception_class_name} (#{wrapper.message}):"
|
151
154
|
end
|
155
|
+
|
152
156
|
message.concat(wrapper.annotated_source_code)
|
153
157
|
message << " "
|
154
158
|
message.concat(trace)
|
155
159
|
|
160
|
+
if wrapper.has_cause?
|
161
|
+
wrapper.wrapped_causes.each do |wrapped_cause|
|
162
|
+
message << "\nInformation for cause: #{wrapped_cause.exception_class_name} (#{wrapped_cause.message}):"
|
163
|
+
message.concat(wrapped_cause.annotated_source_code)
|
164
|
+
message << " "
|
165
|
+
message.concat(wrapped_cause.exception_trace)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
156
169
|
log_array(logger, message, request)
|
157
170
|
end
|
158
171
|
|
@@ -25,11 +25,12 @@ module ActionDispatch
|
|
25
25
|
def initialize(app, header:)
|
26
26
|
@app = app
|
27
27
|
@header = header
|
28
|
+
@env_header = "HTTP_#{header.upcase.tr("-", "_")}"
|
28
29
|
end
|
29
30
|
|
30
31
|
def call(env)
|
31
32
|
req = ActionDispatch::Request.new env
|
32
|
-
req.request_id = make_request_id(req.
|
33
|
+
req.request_id = make_request_id(req.get_header(@env_header))
|
33
34
|
@app.call(env).tap { |_status, headers, _body| headers[@header] = req.request_id }
|
34
35
|
end
|
35
36
|
|