actionpack 7.2.2.1 → 8.1.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +408 -95
- data/README.rdoc +1 -1
- data/lib/abstract_controller/asset_paths.rb +4 -2
- data/lib/abstract_controller/base.rb +12 -17
- data/lib/abstract_controller/caching.rb +6 -3
- data/lib/abstract_controller/callbacks.rb +6 -0
- data/lib/abstract_controller/collector.rb +1 -1
- data/lib/abstract_controller/helpers.rb +1 -1
- data/lib/abstract_controller/logger.rb +2 -1
- data/lib/abstract_controller/rendering.rb +0 -1
- data/lib/action_controller/api.rb +1 -0
- data/lib/action_controller/base.rb +3 -2
- data/lib/action_controller/caching.rb +1 -2
- data/lib/action_controller/form_builder.rb +4 -4
- data/lib/action_controller/log_subscriber.rb +22 -3
- data/lib/action_controller/metal/allow_browser.rb +12 -2
- data/lib/action_controller/metal/conditional_get.rb +30 -1
- data/lib/action_controller/metal/data_streaming.rb +5 -5
- data/lib/action_controller/metal/exceptions.rb +5 -0
- data/lib/action_controller/metal/flash.rb +1 -4
- data/lib/action_controller/metal/head.rb +3 -1
- data/lib/action_controller/metal/instrumentation.rb +1 -2
- data/lib/action_controller/metal/live.rb +66 -26
- data/lib/action_controller/metal/params_wrapper.rb +3 -3
- data/lib/action_controller/metal/permissions_policy.rb +9 -0
- data/lib/action_controller/metal/rate_limiting.rb +39 -9
- data/lib/action_controller/metal/redirecting.rb +109 -16
- data/lib/action_controller/metal/renderers.rb +29 -9
- data/lib/action_controller/metal/rendering.rb +8 -2
- data/lib/action_controller/metal/request_forgery_protection.rb +21 -11
- data/lib/action_controller/metal/rescue.rb +9 -0
- data/lib/action_controller/metal/streaming.rb +5 -84
- data/lib/action_controller/metal/strong_parameters.rb +277 -92
- data/lib/action_controller/railtie.rb +33 -15
- data/lib/action_controller/renderer.rb +0 -1
- data/lib/action_controller/structured_event_subscriber.rb +116 -0
- data/lib/action_controller/test_case.rb +12 -2
- data/lib/action_dispatch/constants.rb +6 -0
- data/lib/action_dispatch/http/cache.rb +138 -11
- data/lib/action_dispatch/http/content_security_policy.rb +14 -1
- data/lib/action_dispatch/http/filter_parameters.rb +5 -3
- data/lib/action_dispatch/http/mime_negotiation.rb +63 -4
- data/lib/action_dispatch/http/mime_types.rb +1 -0
- data/lib/action_dispatch/http/param_builder.rb +187 -0
- data/lib/action_dispatch/http/param_error.rb +26 -0
- data/lib/action_dispatch/http/parameters.rb +3 -3
- data/lib/action_dispatch/http/permissions_policy.rb +6 -0
- data/lib/action_dispatch/http/query_parser.rb +55 -0
- data/lib/action_dispatch/http/request.rb +73 -23
- data/lib/action_dispatch/http/response.rb +65 -17
- data/lib/action_dispatch/http/url.rb +112 -16
- data/lib/action_dispatch/journey/formatter.rb +8 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +33 -12
- data/lib/action_dispatch/journey/gtg/transition_table.rb +37 -45
- data/lib/action_dispatch/journey/nodes/node.rb +2 -1
- data/lib/action_dispatch/journey/parser.rb +99 -196
- data/lib/action_dispatch/journey/route.rb +45 -31
- data/lib/action_dispatch/journey/router/utils.rb +8 -14
- data/lib/action_dispatch/journey/router.rb +59 -81
- data/lib/action_dispatch/journey/routes.rb +7 -0
- data/lib/action_dispatch/journey/scanner.rb +44 -42
- data/lib/action_dispatch/journey/visitors.rb +55 -23
- data/lib/action_dispatch/journey/visualizer/fsm.js +4 -6
- data/lib/action_dispatch/log_subscriber.rb +7 -3
- data/lib/action_dispatch/middleware/cookies.rb +8 -4
- data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -5
- data/lib/action_dispatch/middleware/debug_view.rb +11 -5
- data/lib/action_dispatch/middleware/exception_wrapper.rb +14 -14
- data/lib/action_dispatch/middleware/executor.rb +17 -4
- data/lib/action_dispatch/middleware/public_exceptions.rb +6 -6
- data/lib/action_dispatch/middleware/remote_ip.rb +11 -5
- data/lib/action_dispatch/middleware/request_id.rb +2 -1
- data/lib/action_dispatch/middleware/session/cache_store.rb +17 -0
- data/lib/action_dispatch/middleware/ssl.rb +13 -3
- data/lib/action_dispatch/middleware/templates/rescues/_copy_button.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +3 -5
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +9 -5
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +50 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -0
- data/lib/action_dispatch/railtie.rb +21 -0
- data/lib/action_dispatch/request/session.rb +1 -0
- data/lib/action_dispatch/request/utils.rb +9 -3
- data/lib/action_dispatch/routing/inspector.rb +80 -57
- data/lib/action_dispatch/routing/mapper.rb +409 -228
- data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -2
- data/lib/action_dispatch/routing/redirection.rb +10 -7
- data/lib/action_dispatch/routing/route_set.rb +21 -12
- data/lib/action_dispatch/routing/routes_proxy.rb +1 -0
- data/lib/action_dispatch/structured_event_subscriber.rb +20 -0
- data/lib/action_dispatch/system_test_case.rb +3 -3
- data/lib/action_dispatch/system_testing/browser.rb +12 -21
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +2 -2
- data/lib/action_dispatch/testing/assertion_response.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +26 -2
- data/lib/action_dispatch/testing/assertions/routing.rb +27 -15
- data/lib/action_dispatch/testing/integration.rb +16 -7
- data/lib/action_dispatch/testing/request_encoder.rb +9 -9
- data/lib/action_dispatch/testing/test_process.rb +1 -2
- data/lib/action_dispatch.rb +14 -4
- data/lib/action_pack/gem_version.rb +3 -3
- metadata +19 -38
- data/lib/action_dispatch/journey/parser.y +0 -50
- data/lib/action_dispatch/journey/parser_extras.rb +0 -33
|
@@ -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
|
|
@@ -38,29 +38,50 @@ module ActionDispatch
|
|
|
38
38
|
def self.verb; ""; end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
class Or
|
|
42
|
+
attr_reader :verb
|
|
43
|
+
|
|
44
|
+
def initialize(verbs)
|
|
45
|
+
@verbs = verbs
|
|
46
|
+
@verb = @verbs.map(&:verb).join("|")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def call(req)
|
|
50
|
+
@verbs.any? { |v| v.call req }
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
41
54
|
VERB_TO_CLASS = VERBS.each_with_object(all: All) do |verb, hash|
|
|
42
55
|
klass = const_get verb
|
|
43
56
|
hash[verb] = klass
|
|
44
57
|
hash[verb.downcase] = klass
|
|
45
58
|
hash[verb.downcase.to_sym] = klass
|
|
46
59
|
end
|
|
47
|
-
end
|
|
48
60
|
|
|
49
|
-
|
|
50
|
-
VerbMatchers::VERB_TO_CLASS.fetch(verb) do
|
|
61
|
+
VERB_TO_CLASS.default_proc = proc do |_, verb|
|
|
51
62
|
VerbMatchers::Unknown.new verb.to_s.dasherize.upcase
|
|
52
63
|
end
|
|
64
|
+
|
|
65
|
+
def self.for(verbs)
|
|
66
|
+
if verbs.any? { |v| VERB_TO_CLASS[v] == All }
|
|
67
|
+
All
|
|
68
|
+
elsif verbs.one?
|
|
69
|
+
VERB_TO_CLASS[verbs.first]
|
|
70
|
+
else
|
|
71
|
+
Or.new(verbs.map { |v| VERB_TO_CLASS[v] })
|
|
72
|
+
end
|
|
73
|
+
end
|
|
53
74
|
end
|
|
54
75
|
|
|
55
76
|
##
|
|
56
77
|
# +path+ is a path constraint.
|
|
57
78
|
# `constraints` is a hash of constraints to be applied to this route.
|
|
58
|
-
def initialize(name:, app: nil, path:, constraints: {}, required_defaults: [], defaults: {},
|
|
79
|
+
def initialize(name:, app: nil, path:, constraints: {}, required_defaults: [], defaults: {}, via: nil, precedence: 0, scope_options: {}, internal: false, source_location: nil)
|
|
59
80
|
@name = name
|
|
60
81
|
@app = app
|
|
61
82
|
@path = path
|
|
62
83
|
|
|
63
|
-
@request_method_match =
|
|
84
|
+
@request_method_match = via && VerbMatchers.for(via)
|
|
64
85
|
@constraints = constraints
|
|
65
86
|
@defaults = defaults
|
|
66
87
|
@required_defaults = nil
|
|
@@ -146,21 +167,23 @@ module ActionDispatch
|
|
|
146
167
|
end
|
|
147
168
|
|
|
148
169
|
def matches?(request)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
170
|
+
@request_method_match.call(request) && (
|
|
171
|
+
constraints.empty? ||
|
|
172
|
+
constraints.all? { |method, value|
|
|
173
|
+
case value
|
|
174
|
+
when Regexp, String
|
|
175
|
+
value === request.send(method).to_s
|
|
176
|
+
when Array
|
|
177
|
+
value.include?(request.send(method))
|
|
178
|
+
when TrueClass
|
|
179
|
+
request.send(method).present?
|
|
180
|
+
when FalseClass
|
|
181
|
+
request.send(method).blank?
|
|
182
|
+
else
|
|
183
|
+
value === request.send(method)
|
|
184
|
+
end
|
|
185
|
+
}
|
|
186
|
+
)
|
|
164
187
|
end
|
|
165
188
|
|
|
166
189
|
def ip
|
|
@@ -168,21 +191,12 @@ module ActionDispatch
|
|
|
168
191
|
end
|
|
169
192
|
|
|
170
193
|
def requires_matching_verb?
|
|
171
|
-
|
|
194
|
+
@request_method_match != VerbMatchers::All
|
|
172
195
|
end
|
|
173
196
|
|
|
174
197
|
def verb
|
|
175
|
-
|
|
198
|
+
@request_method_match.verb
|
|
176
199
|
end
|
|
177
|
-
|
|
178
|
-
private
|
|
179
|
-
def verbs
|
|
180
|
-
@request_method_match.map(&:verb)
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
def match_verb(request)
|
|
184
|
-
@request_method_match.any? { |m| m.call request }
|
|
185
|
-
end
|
|
186
200
|
end
|
|
187
201
|
end
|
|
188
202
|
# :startdoc:
|
|
@@ -17,7 +17,14 @@ module ActionDispatch
|
|
|
17
17
|
# normalize_path("") # => "/"
|
|
18
18
|
# normalize_path("/%ab") # => "/%AB"
|
|
19
19
|
def self.normalize_path(path)
|
|
20
|
-
|
|
20
|
+
return "/".dup unless path
|
|
21
|
+
|
|
22
|
+
# Fast path for the overwhelming majority of paths that don't need to be normalized
|
|
23
|
+
if path == "/" || (path.start_with?("/") && !path.end_with?("/") && !path.match?(%r{%|//}))
|
|
24
|
+
return path.dup
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Slow path
|
|
21
28
|
encoding = path.encoding
|
|
22
29
|
path = +"/#{path}"
|
|
23
30
|
path.squeeze!("/")
|
|
@@ -61,11 +68,6 @@ module ActionDispatch
|
|
|
61
68
|
escape(segment, SEGMENT)
|
|
62
69
|
end
|
|
63
70
|
|
|
64
|
-
def unescape_uri(uri)
|
|
65
|
-
encoding = uri.encoding == US_ASCII ? UTF_8 : uri.encoding
|
|
66
|
-
uri.gsub(ESCAPED) { |match| [match[1, 2].hex].pack("C") }.force_encoding(encoding)
|
|
67
|
-
end
|
|
68
|
-
|
|
69
71
|
private
|
|
70
72
|
def escape(component, pattern)
|
|
71
73
|
component.gsub(pattern) { |unsafe| percent_encode(unsafe) }.force_encoding(US_ASCII)
|
|
@@ -91,14 +93,6 @@ module ActionDispatch
|
|
|
91
93
|
def self.escape_fragment(fragment)
|
|
92
94
|
ENCODER.escape_fragment(fragment.to_s)
|
|
93
95
|
end
|
|
94
|
-
|
|
95
|
-
# Replaces any escaped sequences with their unescaped representations.
|
|
96
|
-
#
|
|
97
|
-
# uri = "/topics?title=Ruby%20on%20Rails"
|
|
98
|
-
# unescape_uri(uri) #=> "/topics?title=Ruby on Rails"
|
|
99
|
-
def self.unescape_uri(uri)
|
|
100
|
-
ENCODER.unescape_uri(uri)
|
|
101
|
-
end
|
|
102
96
|
end
|
|
103
97
|
end
|
|
104
98
|
end
|
|
@@ -2,15 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
# :markup: markdown
|
|
4
4
|
|
|
5
|
+
require "cgi/escape"
|
|
6
|
+
require "cgi/util" if RUBY_VERSION < "3.5"
|
|
5
7
|
require "action_dispatch/journey/router/utils"
|
|
6
8
|
require "action_dispatch/journey/routes"
|
|
7
9
|
require "action_dispatch/journey/formatter"
|
|
8
|
-
|
|
9
|
-
before = $-w
|
|
10
|
-
$-w = false
|
|
11
10
|
require "action_dispatch/journey/parser"
|
|
12
|
-
$-w = before
|
|
13
|
-
|
|
14
11
|
require "action_dispatch/journey/route"
|
|
15
12
|
require "action_dispatch/journey/path/pattern"
|
|
16
13
|
|
|
@@ -31,71 +28,78 @@ module ActionDispatch
|
|
|
31
28
|
end
|
|
32
29
|
|
|
33
30
|
def serve(req)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
script_name = req.script_name
|
|
38
|
-
|
|
39
|
-
unless route.path.anchored
|
|
40
|
-
req.script_name = (script_name.to_s + match.to_s).chomp("/")
|
|
41
|
-
req.path_info = match.post_match
|
|
42
|
-
req.path_info = "/" + req.path_info unless req.path_info.start_with? "/"
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
tmp_params = set_params.merge route.defaults
|
|
46
|
-
parameters.each_pair { |key, val|
|
|
47
|
-
tmp_params[key] = val.force_encoding(::Encoding::UTF_8)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
req.path_parameters = tmp_params
|
|
51
|
-
req.route_uri_pattern = route.path.spec.to_s
|
|
31
|
+
recognize(req) do |route, parameters|
|
|
32
|
+
req.path_parameters = parameters
|
|
33
|
+
req.route = route
|
|
52
34
|
|
|
53
35
|
_, headers, _ = response = route.app.serve(req)
|
|
54
36
|
|
|
55
|
-
|
|
56
|
-
req.script_name = script_name
|
|
57
|
-
req.path_info = path_info
|
|
58
|
-
req.path_parameters = set_params
|
|
59
|
-
next
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
return response
|
|
37
|
+
return response unless headers[Constants::X_CASCADE] == "pass"
|
|
63
38
|
end
|
|
64
39
|
|
|
65
40
|
[404, { Constants::X_CASCADE => "pass" }, ["Not Found"]]
|
|
66
41
|
end
|
|
67
42
|
|
|
68
|
-
def recognize(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
rails_req.path_info = match.post_match
|
|
73
|
-
rails_req.path_info = "/" + rails_req.path_info unless rails_req.path_info.start_with? "/"
|
|
74
|
-
end
|
|
43
|
+
def recognize(req, &block)
|
|
44
|
+
req_params = req.path_parameters
|
|
45
|
+
path_info = req.path_info
|
|
46
|
+
script_name = req.script_name
|
|
75
47
|
|
|
76
|
-
|
|
77
|
-
yield(route, parameters)
|
|
78
|
-
end
|
|
79
|
-
end
|
|
48
|
+
routes = filter_routes(path_info)
|
|
80
49
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
asts = groups.values.map(&:first)
|
|
85
|
-
tt.visualizer(asts)
|
|
86
|
-
end
|
|
50
|
+
custom_routes.each { |r|
|
|
51
|
+
routes << r if r.path.match?(path_info)
|
|
52
|
+
}
|
|
87
53
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
54
|
+
if req.head?
|
|
55
|
+
routes = match_head_routes(routes, req)
|
|
56
|
+
else
|
|
57
|
+
routes.select! { |r| r.matches?(req) }
|
|
93
58
|
end
|
|
94
59
|
|
|
95
|
-
|
|
96
|
-
routes.
|
|
60
|
+
if routes.size > 1
|
|
61
|
+
routes.sort! do |a, b|
|
|
62
|
+
a.precedence <=> b.precedence
|
|
63
|
+
end
|
|
97
64
|
end
|
|
98
65
|
|
|
66
|
+
routes.each do |r|
|
|
67
|
+
match_data = r.path.match(path_info)
|
|
68
|
+
|
|
69
|
+
path_parameters = req_params.merge r.defaults
|
|
70
|
+
|
|
71
|
+
index = 1
|
|
72
|
+
match_data.names.each do |name|
|
|
73
|
+
if val = match_data[index]
|
|
74
|
+
val = if val.include?("%")
|
|
75
|
+
CGI.unescapeURIComponent(val)
|
|
76
|
+
else
|
|
77
|
+
val
|
|
78
|
+
end
|
|
79
|
+
val.force_encoding(::Encoding::UTF_8)
|
|
80
|
+
path_parameters[name.to_sym] = val
|
|
81
|
+
end
|
|
82
|
+
index += 1
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
if r.path.anchored
|
|
86
|
+
yield(r, path_parameters)
|
|
87
|
+
else
|
|
88
|
+
req.script_name = (script_name.to_s + match_data.to_s).chomp("/")
|
|
89
|
+
req.path_info = match_data.post_match
|
|
90
|
+
req.path_info = "/" + req.path_info unless req.path_info.start_with? "/"
|
|
91
|
+
|
|
92
|
+
yield(r, path_parameters)
|
|
93
|
+
|
|
94
|
+
req.script_name = script_name
|
|
95
|
+
req.path_info = path_info
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
req.path_parameters = req_params
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
private
|
|
99
103
|
def simulator
|
|
100
104
|
routes.simulator
|
|
101
105
|
end
|
|
@@ -105,35 +109,9 @@ module ActionDispatch
|
|
|
105
109
|
end
|
|
106
110
|
|
|
107
111
|
def filter_routes(path)
|
|
108
|
-
return [] unless ast
|
|
109
112
|
simulator.memos(path) { [] }
|
|
110
113
|
end
|
|
111
114
|
|
|
112
|
-
def find_routes(req)
|
|
113
|
-
path_info = req.path_info
|
|
114
|
-
routes = filter_routes(path_info).concat custom_routes.find_all { |r|
|
|
115
|
-
r.path.match?(path_info)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if req.head?
|
|
119
|
-
routes = match_head_routes(routes, req)
|
|
120
|
-
else
|
|
121
|
-
routes.select! { |r| r.matches?(req) }
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
routes.sort_by!(&:precedence)
|
|
125
|
-
|
|
126
|
-
routes.each { |r|
|
|
127
|
-
match_data = r.path.match(path_info)
|
|
128
|
-
path_parameters = {}
|
|
129
|
-
match_data.names.each_with_index { |name, i|
|
|
130
|
-
val = match_data[i + 1]
|
|
131
|
-
path_parameters[name.to_sym] = Utils.unescape_uri(val) if val
|
|
132
|
-
}
|
|
133
|
-
yield [match_data, path_parameters, r]
|
|
134
|
-
}
|
|
135
|
-
end
|
|
136
|
-
|
|
137
115
|
def match_head_routes(routes, req)
|
|
138
116
|
head_routes = routes.select { |r| r.requires_matching_verb? && r.matches?(req) }
|
|
139
117
|
return head_routes unless head_routes.empty?
|
|
@@ -72,6 +72,13 @@ module ActionDispatch
|
|
|
72
72
|
route
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
+
def visualizer
|
|
76
|
+
tt = GTG::Builder.new(ast).transition_table
|
|
77
|
+
groups = anchored_routes.map(&:ast).group_by(&:to_s)
|
|
78
|
+
asts = groups.values.map(&:first)
|
|
79
|
+
tt.visualizer(asts)
|
|
80
|
+
end
|
|
81
|
+
|
|
75
82
|
private
|
|
76
83
|
def clear_cache!
|
|
77
84
|
@ast = nil
|