actionpack 5.2.8.1 → 6.1.6.1
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 +383 -346
- data/MIT-LICENSE +1 -2
- data/README.rdoc +4 -3
- data/lib/abstract_controller/base.rb +38 -4
- data/lib/abstract_controller/caching/fragments.rb +6 -22
- data/lib/abstract_controller/caching.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +14 -2
- data/lib/abstract_controller/collector.rb +5 -4
- data/lib/abstract_controller/helpers.rb +106 -90
- data/lib/abstract_controller/railties/routes_helpers.rb +17 -1
- data/lib/abstract_controller/rendering.rb +9 -9
- data/lib/abstract_controller/translation.rb +11 -5
- data/lib/abstract_controller.rb +1 -0
- data/lib/action_controller/api.rb +4 -3
- data/lib/action_controller/base.rb +6 -9
- data/lib/action_controller/caching.rb +1 -3
- data/lib/action_controller/log_subscriber.rb +10 -7
- data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
- data/lib/action_controller/metal/conditional_get.rb +19 -5
- data/lib/action_controller/metal/content_security_policy.rb +1 -2
- data/lib/action_controller/metal/cookies.rb +3 -1
- data/lib/action_controller/metal/data_streaming.rb +6 -7
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +4 -6
- data/lib/action_controller/metal/exceptions.rb +56 -2
- data/lib/action_controller/metal/flash.rb +5 -5
- data/lib/action_controller/metal/head.rb +7 -4
- data/lib/action_controller/metal/helpers.rb +14 -5
- data/lib/action_controller/metal/http_authentication.rb +25 -23
- data/lib/action_controller/metal/implicit_render.rb +5 -15
- data/lib/action_controller/metal/instrumentation.rb +13 -14
- data/lib/action_controller/metal/live.rb +39 -32
- data/lib/action_controller/metal/logging.rb +20 -0
- data/lib/action_controller/metal/mime_responds.rb +19 -4
- data/lib/action_controller/metal/parameter_encoding.rb +35 -4
- data/lib/action_controller/metal/params_wrapper.rb +32 -22
- data/lib/action_controller/metal/permissions_policy.rb +46 -0
- data/lib/action_controller/metal/redirecting.rb +6 -6
- data/lib/action_controller/metal/renderers.rb +4 -4
- data/lib/action_controller/metal/rendering.rb +8 -3
- data/lib/action_controller/metal/request_forgery_protection.rb +26 -49
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/streaming.rb +0 -1
- data/lib/action_controller/metal/strong_parameters.rb +168 -59
- data/lib/action_controller/metal/url_for.rb +1 -1
- data/lib/action_controller/metal.rb +10 -8
- data/lib/action_controller/railties/helpers.rb +1 -1
- data/lib/action_controller/renderer.rb +37 -13
- data/lib/action_controller/template_assertions.rb +1 -1
- data/lib/action_controller/test_case.rb +71 -63
- data/lib/action_controller.rb +7 -4
- data/lib/action_dispatch/http/cache.rb +31 -27
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +34 -18
- data/lib/action_dispatch/http/filter_parameters.rb +9 -8
- data/lib/action_dispatch/http/filter_redirect.rb +2 -3
- data/lib/action_dispatch/http/headers.rb +4 -4
- data/lib/action_dispatch/http/mime_negotiation.rb +26 -13
- data/lib/action_dispatch/http/mime_type.rb +43 -24
- data/lib/action_dispatch/http/parameters.rb +14 -23
- data/lib/action_dispatch/http/permissions_policy.rb +173 -0
- data/lib/action_dispatch/http/request.rb +45 -22
- data/lib/action_dispatch/http/response.rb +45 -25
- data/lib/action_dispatch/http/upload.rb +9 -1
- data/lib/action_dispatch/http/url.rb +82 -82
- data/lib/action_dispatch/journey/formatter.rb +55 -31
- data/lib/action_dispatch/journey/gtg/builder.rb +22 -37
- data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
- data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -5
- data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
- data/lib/action_dispatch/journey/nodes/node.rb +13 -11
- data/lib/action_dispatch/journey/parser.rb +13 -13
- data/lib/action_dispatch/journey/parser.y +1 -1
- data/lib/action_dispatch/journey/path/pattern.rb +19 -21
- data/lib/action_dispatch/journey/route.rb +10 -20
- data/lib/action_dispatch/journey/router/utils.rb +14 -12
- data/lib/action_dispatch/journey/router.rb +26 -34
- data/lib/action_dispatch/journey/routes.rb +0 -2
- data/lib/action_dispatch/journey/scanner.rb +10 -4
- data/lib/action_dispatch/journey/visitors.rb +1 -4
- data/lib/action_dispatch/journey.rb +0 -2
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/callbacks.rb +2 -4
- data/lib/action_dispatch/middleware/cookies.rb +128 -109
- data/lib/action_dispatch/middleware/debug_exceptions.rb +43 -66
- data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
- data/lib/action_dispatch/middleware/debug_view.rb +66 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -30
- data/lib/action_dispatch/middleware/flash.rb +1 -1
- data/lib/action_dispatch/middleware/host_authorization.rb +170 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +6 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +14 -16
- data/lib/action_dispatch/middleware/request_id.rb +5 -6
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -3
- data/lib/action_dispatch/middleware/session/cookie_store.rb +3 -9
- data/lib/action_dispatch/middleware/show_exceptions.rb +13 -2
- data/lib/action_dispatch/middleware/ssl.rb +20 -15
- data/lib/action_dispatch/middleware/stack.rb +56 -2
- data/lib/action_dispatch/middleware/static.rb +153 -93
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +23 -4
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +6 -3
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +4 -1
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +104 -8
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +24 -1
- data/lib/action_dispatch/railtie.rb +8 -2
- data/lib/action_dispatch/request/session.rb +11 -10
- data/lib/action_dispatch/request/utils.rb +26 -2
- data/lib/action_dispatch/routing/inspector.rb +100 -52
- data/lib/action_dispatch/routing/mapper.rb +155 -103
- data/lib/action_dispatch/routing/polymorphic_routes.rb +13 -15
- data/lib/action_dispatch/routing/redirection.rb +4 -4
- data/lib/action_dispatch/routing/route_set.rb +71 -69
- data/lib/action_dispatch/routing/url_for.rb +2 -2
- data/lib/action_dispatch/routing.rb +21 -20
- data/lib/action_dispatch/system_test_case.rb +60 -11
- data/lib/action_dispatch/system_testing/browser.rb +53 -16
- data/lib/action_dispatch/system_testing/driver.rb +11 -3
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +49 -7
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +8 -10
- data/lib/action_dispatch/testing/assertion_response.rb +0 -1
- data/lib/action_dispatch/testing/assertions/response.rb +4 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +20 -8
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/integration.rb +60 -28
- data/lib/action_dispatch/testing/request_encoder.rb +2 -2
- data/lib/action_dispatch/testing/test_process.rb +32 -4
- data/lib/action_dispatch/testing/test_request.rb +3 -3
- data/lib/action_dispatch/testing/test_response.rb +4 -32
- data/lib/action_dispatch.rb +9 -3
- data/lib/action_pack/gem_version.rb +3 -3
- data/lib/action_pack.rb +1 -1
- metadata +34 -21
- data/lib/action_controller/metal/force_ssl.rb +0 -99
- data/lib/action_dispatch/http/parameter_filter.rb +0 -86
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -49
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -120
- data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -15,12 +15,53 @@ module ActionDispatch
|
|
15
15
|
@cache = nil
|
16
16
|
end
|
17
17
|
|
18
|
-
|
18
|
+
class RouteWithParams
|
19
|
+
attr_reader :params
|
20
|
+
|
21
|
+
def initialize(route, parameterized_parts, params)
|
22
|
+
@route = route
|
23
|
+
@parameterized_parts = parameterized_parts
|
24
|
+
@params = params
|
25
|
+
end
|
26
|
+
|
27
|
+
def path(_)
|
28
|
+
@route.format(@parameterized_parts)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class MissingRoute
|
33
|
+
attr_reader :routes, :name, :constraints, :missing_keys, :unmatched_keys
|
34
|
+
|
35
|
+
def initialize(constraints, missing_keys, unmatched_keys, routes, name)
|
36
|
+
@constraints = constraints
|
37
|
+
@missing_keys = missing_keys
|
38
|
+
@unmatched_keys = unmatched_keys
|
39
|
+
@routes = routes
|
40
|
+
@name = name
|
41
|
+
end
|
42
|
+
|
43
|
+
def path(method_name)
|
44
|
+
raise ActionController::UrlGenerationError.new(message, routes, name, method_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def params
|
48
|
+
path("unknown")
|
49
|
+
end
|
50
|
+
|
51
|
+
def message
|
52
|
+
message = +"No route matches #{Hash[constraints.sort_by { |k, v| k.to_s }].inspect}"
|
53
|
+
message << ", missing required keys: #{missing_keys.sort.inspect}" if missing_keys && !missing_keys.empty?
|
54
|
+
message << ", possible unmatched constraints: #{unmatched_keys.sort.inspect}" if unmatched_keys && !unmatched_keys.empty?
|
55
|
+
message
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def generate(name, options, path_parameters)
|
19
60
|
constraints = path_parameters.merge(options)
|
20
61
|
missing_keys = nil
|
21
62
|
|
22
63
|
match_route(name, constraints) do |route|
|
23
|
-
parameterized_parts = extract_parameterized_parts(route, options, path_parameters
|
64
|
+
parameterized_parts = extract_parameterized_parts(route, options, path_parameters)
|
24
65
|
|
25
66
|
# Skip this route unless a name has been provided or it is a
|
26
67
|
# standard Rails route since we can't determine whether an options
|
@@ -44,17 +85,13 @@ module ActionDispatch
|
|
44
85
|
parameterized_parts.delete(key)
|
45
86
|
end
|
46
87
|
|
47
|
-
return
|
88
|
+
return RouteWithParams.new(route, parameterized_parts, params)
|
48
89
|
end
|
49
90
|
|
50
91
|
unmatched_keys = (missing_keys || []) & constraints.keys
|
51
92
|
missing_keys = (missing_keys || []) - unmatched_keys
|
52
93
|
|
53
|
-
|
54
|
-
message << ", missing required keys: #{missing_keys.sort.inspect}" if missing_keys && !missing_keys.empty?
|
55
|
-
message << ", possible unmatched constraints: #{unmatched_keys.sort.inspect}" if unmatched_keys && !unmatched_keys.empty?
|
56
|
-
|
57
|
-
raise ActionController::UrlGenerationError, message
|
94
|
+
MissingRoute.new(constraints, missing_keys, unmatched_keys, routes, name)
|
58
95
|
end
|
59
96
|
|
60
97
|
def clear
|
@@ -62,25 +99,26 @@ module ActionDispatch
|
|
62
99
|
end
|
63
100
|
|
64
101
|
private
|
65
|
-
|
66
|
-
def extract_parameterized_parts(route, options, recall, parameterize = nil)
|
102
|
+
def extract_parameterized_parts(route, options, recall)
|
67
103
|
parameterized_parts = recall.merge(options)
|
68
104
|
|
69
105
|
keys_to_keep = route.parts.reverse_each.drop_while { |part|
|
70
|
-
!options.key?(part) || (options[part]
|
106
|
+
!(options.key?(part) || route.scope_options.key?(part)) || (options[part].nil? && recall[part].nil?)
|
71
107
|
} | route.required_parts
|
72
108
|
|
73
109
|
parameterized_parts.delete_if do |bad_key, _|
|
74
110
|
!keys_to_keep.include?(bad_key)
|
75
111
|
end
|
76
112
|
|
77
|
-
|
78
|
-
|
79
|
-
parameterized_parts[k] =
|
113
|
+
parameterized_parts.each do |k, v|
|
114
|
+
if k == :controller
|
115
|
+
parameterized_parts[k] = v
|
116
|
+
else
|
117
|
+
parameterized_parts[k] = v.to_param
|
80
118
|
end
|
81
119
|
end
|
82
120
|
|
83
|
-
parameterized_parts.
|
121
|
+
parameterized_parts.compact!
|
84
122
|
parameterized_parts
|
85
123
|
end
|
86
124
|
|
@@ -126,19 +164,10 @@ module ActionDispatch
|
|
126
164
|
routes
|
127
165
|
end
|
128
166
|
|
129
|
-
module RegexCaseComparator
|
130
|
-
DEFAULT_INPUT = /[-_.a-zA-Z0-9]+\/[-_.a-zA-Z0-9]+/
|
131
|
-
DEFAULT_REGEX = /\A#{DEFAULT_INPUT}\Z/
|
132
|
-
|
133
|
-
def self.===(regex)
|
134
|
-
DEFAULT_INPUT == regex
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
167
|
# Returns an array populated with missing keys if any are present.
|
139
168
|
def missing_keys(route, parts)
|
140
169
|
missing_keys = nil
|
141
|
-
tests = route.path.
|
170
|
+
tests = route.path.requirements_for_missing_keys_check
|
142
171
|
route.required_parts.each { |key|
|
143
172
|
case tests[key]
|
144
173
|
when nil
|
@@ -146,13 +175,8 @@ module ActionDispatch
|
|
146
175
|
missing_keys ||= []
|
147
176
|
missing_keys << key
|
148
177
|
end
|
149
|
-
when RegexCaseComparator
|
150
|
-
unless RegexCaseComparator::DEFAULT_REGEX === parts[key]
|
151
|
-
missing_keys ||= []
|
152
|
-
missing_keys << key
|
153
|
-
end
|
154
178
|
else
|
155
|
-
unless
|
179
|
+
unless tests[key].match?(parts[key])
|
156
180
|
missing_keys ||= []
|
157
181
|
missing_keys << key
|
158
182
|
end
|
@@ -13,45 +13,44 @@ module ActionDispatch
|
|
13
13
|
def initialize(root)
|
14
14
|
@root = root
|
15
15
|
@ast = Nodes::Cat.new root, DUMMY
|
16
|
-
@followpos =
|
16
|
+
@followpos = build_followpos
|
17
17
|
end
|
18
18
|
|
19
19
|
def transition_table
|
20
20
|
dtrans = TransitionTable.new
|
21
|
-
marked = {}
|
22
|
-
state_id = Hash.new { |h, k| h[k] = h.length }
|
21
|
+
marked = {}.compare_by_identity
|
22
|
+
state_id = Hash.new { |h, k| h[k] = h.length }.compare_by_identity
|
23
|
+
dstates = [firstpos(root)]
|
23
24
|
|
24
|
-
start = firstpos(root)
|
25
|
-
dstates = [start]
|
26
25
|
until dstates.empty?
|
27
26
|
s = dstates.shift
|
28
27
|
next if marked[s]
|
29
28
|
marked[s] = true # mark s
|
30
29
|
|
31
30
|
s.group_by { |state| symbol(state) }.each do |sym, ps|
|
32
|
-
u = ps.flat_map { |l| followpos
|
31
|
+
u = ps.flat_map { |l| @followpos[l] }
|
33
32
|
next if u.empty?
|
34
33
|
|
35
|
-
|
36
|
-
from = state_id[s]
|
37
|
-
to = state_id[Object.new]
|
38
|
-
dtrans[from, to] = sym
|
34
|
+
from = state_id[s]
|
39
35
|
|
36
|
+
if u.all? { |pos| pos == DUMMY }
|
37
|
+
to = state_id[Object.new]
|
38
|
+
dtrans[from, to] = sym
|
40
39
|
dtrans.add_accepting(to)
|
40
|
+
|
41
41
|
ps.each { |state| dtrans.add_memo(to, state.memo) }
|
42
42
|
else
|
43
|
-
|
43
|
+
to = state_id[u]
|
44
|
+
dtrans[from, to] = sym
|
44
45
|
|
45
46
|
if u.include?(DUMMY)
|
46
|
-
|
47
|
+
ps.each do |state|
|
48
|
+
if @followpos[state].include?(DUMMY)
|
49
|
+
dtrans.add_memo(to, state.memo)
|
50
|
+
end
|
51
|
+
end
|
47
52
|
|
48
|
-
|
49
|
-
|
50
|
-
accepting.each { |accepting_state|
|
51
|
-
dtrans.add_memo(to, accepting_state.memo)
|
52
|
-
}
|
53
|
-
|
54
|
-
dtrans.add_accepting(state_id[u])
|
53
|
+
dtrans.add_accepting(to)
|
55
54
|
end
|
56
55
|
end
|
57
56
|
|
@@ -92,7 +91,7 @@ module ActionDispatch
|
|
92
91
|
firstpos(node.left)
|
93
92
|
end
|
94
93
|
when Nodes::Or
|
95
|
-
node.children.flat_map { |c| firstpos(c) }.uniq
|
94
|
+
node.children.flat_map { |c| firstpos(c) }.tap(&:uniq!)
|
96
95
|
when Nodes::Unary
|
97
96
|
firstpos(node.left)
|
98
97
|
when Nodes::Terminal
|
@@ -107,7 +106,7 @@ module ActionDispatch
|
|
107
106
|
when Nodes::Star
|
108
107
|
firstpos(node.left)
|
109
108
|
when Nodes::Or
|
110
|
-
node.children.flat_map { |c| lastpos(c) }.uniq
|
109
|
+
node.children.flat_map { |c| lastpos(c) }.tap(&:uniq!)
|
111
110
|
when Nodes::Cat
|
112
111
|
if nullable?(node.right)
|
113
112
|
lastpos(node.left) | lastpos(node.right)
|
@@ -123,18 +122,9 @@ module ActionDispatch
|
|
123
122
|
end
|
124
123
|
end
|
125
124
|
|
126
|
-
def followpos(node)
|
127
|
-
followpos_table[node]
|
128
|
-
end
|
129
|
-
|
130
125
|
private
|
131
|
-
|
132
|
-
def followpos_table
|
133
|
-
@followpos ||= build_followpos
|
134
|
-
end
|
135
|
-
|
136
126
|
def build_followpos
|
137
|
-
table = Hash.new { |h, k| h[k] = [] }
|
127
|
+
table = Hash.new { |h, k| h[k] = [] }.compare_by_identity
|
138
128
|
@ast.each do |n|
|
139
129
|
case n
|
140
130
|
when Nodes::Cat
|
@@ -151,12 +141,7 @@ module ActionDispatch
|
|
151
141
|
end
|
152
142
|
|
153
143
|
def symbol(edge)
|
154
|
-
|
155
|
-
when Journey::Nodes::Symbol
|
156
|
-
edge.regexp
|
157
|
-
else
|
158
|
-
edge.left
|
159
|
-
end
|
144
|
+
edge.symbol? ? edge.regexp : edge.left
|
160
145
|
end
|
161
146
|
end
|
162
147
|
end
|
@@ -14,6 +14,8 @@ module ActionDispatch
|
|
14
14
|
end
|
15
15
|
|
16
16
|
class Simulator # :nodoc:
|
17
|
+
INITIAL_STATE = [0].freeze
|
18
|
+
|
17
19
|
attr_reader :tt
|
18
20
|
|
19
21
|
def initialize(transition_table)
|
@@ -22,18 +24,17 @@ module ActionDispatch
|
|
22
24
|
|
23
25
|
def memos(string)
|
24
26
|
input = StringScanner.new(string)
|
25
|
-
state =
|
27
|
+
state = INITIAL_STATE
|
28
|
+
|
26
29
|
while sym = input.scan(%r([/.?]|[^/.?]+))
|
27
30
|
state = tt.move(state, sym)
|
28
31
|
end
|
29
32
|
|
30
|
-
acceptance_states = state.
|
31
|
-
tt.accepting?
|
32
|
-
|
33
|
-
|
34
|
-
return yield if acceptance_states.empty?
|
33
|
+
acceptance_states = state.each_with_object([]) do |s, memos|
|
34
|
+
memos.concat(tt.memo(s)) if tt.accepting?(s)
|
35
|
+
end
|
35
36
|
|
36
|
-
acceptance_states.
|
37
|
+
acceptance_states.empty? ? yield : acceptance_states
|
37
38
|
end
|
38
39
|
end
|
39
40
|
end
|
@@ -45,16 +45,18 @@ module ActionDispatch
|
|
45
45
|
return [] if t.empty?
|
46
46
|
|
47
47
|
regexps = []
|
48
|
+
strings = []
|
48
49
|
|
49
|
-
t.
|
50
|
+
t.each { |s|
|
50
51
|
if states = @regexp_states[s]
|
51
|
-
|
52
|
+
states.each { |re, v| regexps << v if re.match?(a) && !v.nil? }
|
52
53
|
end
|
53
54
|
|
54
55
|
if states = @string_states[s]
|
55
|
-
states[a]
|
56
|
+
strings << states[a] unless states[a].nil?
|
56
57
|
end
|
57
|
-
}
|
58
|
+
}
|
59
|
+
strings.concat regexps
|
58
60
|
end
|
59
61
|
|
60
62
|
def as_json(options = nil)
|
@@ -141,7 +143,6 @@ module ActionDispatch
|
|
141
143
|
end
|
142
144
|
|
143
145
|
private
|
144
|
-
|
145
146
|
def states_hash_for(sym)
|
146
147
|
case sym
|
147
148
|
when String
|
@@ -9,17 +9,6 @@ module ActionDispatch
|
|
9
9
|
" #{from} -> #{to} [label=\"#{sym || 'ε'}\"];"
|
10
10
|
}
|
11
11
|
|
12
|
-
# memo_nodes = memos.values.flatten.map { |n|
|
13
|
-
# label = n
|
14
|
-
# if Journey::Route === n
|
15
|
-
# label = "#{n.verb.source} #{n.path.spec}"
|
16
|
-
# end
|
17
|
-
# " #{n.object_id} [label=\"#{label}\", shape=box];"
|
18
|
-
# }
|
19
|
-
# memo_edges = memos.flat_map { |k, memos|
|
20
|
-
# (memos || []).map { |v| " #{k} -> #{v.object_id};" }
|
21
|
-
# }.uniq
|
22
|
-
|
23
12
|
<<-eodot
|
24
13
|
digraph nfa {
|
25
14
|
rankdir=LR;
|
@@ -32,7 +32,7 @@ module ActionDispatch
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def name
|
35
|
-
left.tr
|
35
|
+
-left.tr("*:", "")
|
36
36
|
end
|
37
37
|
|
38
38
|
def type
|
@@ -65,12 +65,12 @@ module ActionDispatch
|
|
65
65
|
def literal?; false; end
|
66
66
|
end
|
67
67
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
68
|
+
class Slash < Terminal # :nodoc:
|
69
|
+
def type; :SLASH; end
|
70
|
+
end
|
71
|
+
|
72
|
+
class Dot < Terminal # :nodoc:
|
73
|
+
def type; :DOT; end
|
74
74
|
end
|
75
75
|
|
76
76
|
class Symbol < Terminal # :nodoc:
|
@@ -79,16 +79,18 @@ module ActionDispatch
|
|
79
79
|
attr_reader :name
|
80
80
|
|
81
81
|
DEFAULT_EXP = /[^\.\/\?]+/
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
@
|
82
|
+
GREEDY_EXP = /(.+)/
|
83
|
+
def initialize(left, regexp = DEFAULT_EXP)
|
84
|
+
super(left)
|
85
|
+
@regexp = regexp
|
86
|
+
@name = -left.tr("*:", "")
|
86
87
|
end
|
87
88
|
|
88
89
|
def default_regexp?
|
89
90
|
regexp == DEFAULT_EXP
|
90
91
|
end
|
91
92
|
|
93
|
+
def type; :SYMBOL; end
|
92
94
|
def symbol?; true; end
|
93
95
|
end
|
94
96
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# DO NOT MODIFY!!!!
|
3
|
-
# This file is automatically generated by Racc 1.4.
|
3
|
+
# This file is automatically generated by Racc 1.4.16
|
4
4
|
# from Racc grammar file "".
|
5
5
|
#
|
6
6
|
|
@@ -135,11 +135,11 @@ Racc_debug_parser = false
|
|
135
135
|
# reduce 0 omitted
|
136
136
|
|
137
137
|
def _reduce_1(val, _values)
|
138
|
-
Cat.new(val.first, val.last)
|
138
|
+
Cat.new(val.first, val.last)
|
139
139
|
end
|
140
140
|
|
141
141
|
def _reduce_2(val, _values)
|
142
|
-
val.first
|
142
|
+
val.first
|
143
143
|
end
|
144
144
|
|
145
145
|
# reduce 3 omitted
|
@@ -151,19 +151,19 @@ end
|
|
151
151
|
# reduce 6 omitted
|
152
152
|
|
153
153
|
def _reduce_7(val, _values)
|
154
|
-
Group.new(val[1])
|
154
|
+
Group.new(val[1])
|
155
155
|
end
|
156
156
|
|
157
157
|
def _reduce_8(val, _values)
|
158
|
-
Or.new([val.first, val.last])
|
158
|
+
Or.new([val.first, val.last])
|
159
159
|
end
|
160
160
|
|
161
161
|
def _reduce_9(val, _values)
|
162
|
-
Or.new([val.first, val.last])
|
162
|
+
Or.new([val.first, val.last])
|
163
163
|
end
|
164
164
|
|
165
165
|
def _reduce_10(val, _values)
|
166
|
-
Star.new(Symbol.new(val.last))
|
166
|
+
Star.new(Symbol.new(val.last, Symbol::GREEDY_EXP))
|
167
167
|
end
|
168
168
|
|
169
169
|
# reduce 11 omitted
|
@@ -175,19 +175,19 @@ end
|
|
175
175
|
# reduce 14 omitted
|
176
176
|
|
177
177
|
def _reduce_15(val, _values)
|
178
|
-
Slash.new(val.first)
|
178
|
+
Slash.new(val.first)
|
179
179
|
end
|
180
180
|
|
181
181
|
def _reduce_16(val, _values)
|
182
|
-
Symbol.new(val.first)
|
182
|
+
Symbol.new(val.first)
|
183
183
|
end
|
184
184
|
|
185
185
|
def _reduce_17(val, _values)
|
186
|
-
Literal.new(val.first)
|
186
|
+
Literal.new(val.first)
|
187
187
|
end
|
188
188
|
|
189
189
|
def _reduce_18(val, _values)
|
190
|
-
Dot.new(val.first)
|
190
|
+
Dot.new(val.first)
|
191
191
|
end
|
192
192
|
|
193
193
|
def _reduce_none(val, _values)
|
@@ -195,5 +195,5 @@ def _reduce_none(val, _values)
|
|
195
195
|
end
|
196
196
|
|
197
197
|
end # class Parser
|
198
|
-
|
199
|
-
|
198
|
+
end # module Journey
|
199
|
+
end # module ActionDispatch
|
@@ -6,16 +6,6 @@ module ActionDispatch
|
|
6
6
|
class Pattern # :nodoc:
|
7
7
|
attr_reader :spec, :requirements, :anchored
|
8
8
|
|
9
|
-
def self.from_string(string)
|
10
|
-
build(string, {}, "/.?", true)
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.build(path, requirements, separators, anchored)
|
14
|
-
parser = Journey::Parser.new
|
15
|
-
ast = parser.parse path
|
16
|
-
new ast, requirements, separators, anchored
|
17
|
-
end
|
18
|
-
|
19
9
|
def initialize(ast, requirements, separators, anchored)
|
20
10
|
@spec = ast
|
21
11
|
@requirements = requirements
|
@@ -46,11 +36,6 @@ module ActionDispatch
|
|
46
36
|
node.regexp = re if re
|
47
37
|
end
|
48
38
|
|
49
|
-
@spec.find_all(&:star?).each do |node|
|
50
|
-
node = node.left
|
51
|
-
node.regexp = @requirements[node.to_sym] || /(.+)/
|
52
|
-
end
|
53
|
-
|
54
39
|
@spec
|
55
40
|
end
|
56
41
|
|
@@ -81,7 +66,7 @@ module ActionDispatch
|
|
81
66
|
end
|
82
67
|
|
83
68
|
def visit_CAT(node)
|
84
|
-
|
69
|
+
"#{visit(node.left)}#{visit(node.right)}"
|
85
70
|
end
|
86
71
|
|
87
72
|
def visit_SYMBOL(node)
|
@@ -90,7 +75,7 @@ module ActionDispatch
|
|
90
75
|
return @separator_re unless @matchers.key?(node)
|
91
76
|
|
92
77
|
re = @matchers[node]
|
93
|
-
"(#{re})"
|
78
|
+
"(#{Regexp.union(re)})"
|
94
79
|
end
|
95
80
|
|
96
81
|
def visit_GROUP(node)
|
@@ -107,8 +92,8 @@ module ActionDispatch
|
|
107
92
|
end
|
108
93
|
|
109
94
|
def visit_STAR(node)
|
110
|
-
re = @matchers[node.left.to_sym]
|
111
|
-
"(#{re})"
|
95
|
+
re = @matchers[node.left.to_sym]
|
96
|
+
re ? "(#{re})" : "(.+)"
|
112
97
|
end
|
113
98
|
|
114
99
|
def visit_OR(node)
|
@@ -137,6 +122,10 @@ module ActionDispatch
|
|
137
122
|
Array.new(length - 1) { |i| self[i + 1] }
|
138
123
|
end
|
139
124
|
|
125
|
+
def named_captures
|
126
|
+
@names.zip(captures).to_h
|
127
|
+
end
|
128
|
+
|
140
129
|
def [](x)
|
141
130
|
idx = @offsets[x - 1] + x
|
142
131
|
@match[idx]
|
@@ -161,6 +150,10 @@ module ActionDispatch
|
|
161
150
|
end
|
162
151
|
alias :=~ :match
|
163
152
|
|
153
|
+
def match?(other)
|
154
|
+
to_regexp.match?(other)
|
155
|
+
end
|
156
|
+
|
164
157
|
def source
|
165
158
|
to_regexp.source
|
166
159
|
end
|
@@ -169,8 +162,13 @@ module ActionDispatch
|
|
169
162
|
@re ||= regexp_visitor.new(@separators, @requirements).accept spec
|
170
163
|
end
|
171
164
|
|
172
|
-
|
165
|
+
def requirements_for_missing_keys_check
|
166
|
+
@requirements_for_missing_keys_check ||= requirements.transform_values do |regex|
|
167
|
+
/\A#{regex}\Z/
|
168
|
+
end
|
169
|
+
end
|
173
170
|
|
171
|
+
private
|
174
172
|
def regexp_visitor
|
175
173
|
@anchored ? AnchoredRegexp : UnanchoredRegexp
|
176
174
|
end
|
@@ -184,7 +182,7 @@ module ActionDispatch
|
|
184
182
|
node = node.to_sym
|
185
183
|
|
186
184
|
if @requirements.key?(node)
|
187
|
-
re = /#{@requirements[node]}|/
|
185
|
+
re = /#{Regexp.union(@requirements[node])}|/
|
188
186
|
@offsets.push((re.match("").length - 1) + @offsets.last)
|
189
187
|
else
|
190
188
|
@offsets << @offsets.last
|
@@ -4,15 +4,16 @@ module ActionDispatch
|
|
4
4
|
# :stopdoc:
|
5
5
|
module Journey
|
6
6
|
class Route
|
7
|
-
attr_reader :app, :path, :defaults, :name, :precedence
|
7
|
+
attr_reader :app, :path, :defaults, :name, :precedence, :constraints,
|
8
|
+
:internal, :scope_options
|
8
9
|
|
9
|
-
attr_reader :constraints, :internal
|
10
10
|
alias :conditions :constraints
|
11
11
|
|
12
12
|
module VerbMatchers
|
13
13
|
VERBS = %w{ DELETE GET HEAD OPTIONS LINK PATCH POST PUT TRACE UNLINK }
|
14
14
|
VERBS.each do |v|
|
15
15
|
class_eval <<-eoc, __FILE__, __LINE__ + 1
|
16
|
+
# frozen_string_literal: true
|
16
17
|
class #{v}
|
17
18
|
def self.verb; name.split("::").last; end
|
18
19
|
def self.call(req); req.#{v.downcase}?; end
|
@@ -27,7 +28,7 @@ module ActionDispatch
|
|
27
28
|
@verb = verb
|
28
29
|
end
|
29
30
|
|
30
|
-
def call(request); @verb
|
31
|
+
def call(request); @verb == request.request_method; end
|
31
32
|
end
|
32
33
|
|
33
34
|
class All
|
@@ -49,15 +50,10 @@ module ActionDispatch
|
|
49
50
|
end
|
50
51
|
end
|
51
52
|
|
52
|
-
def self.build(name, app, path, constraints, required_defaults, defaults)
|
53
|
-
request_method_match = verb_matcher(constraints.delete(:request_method))
|
54
|
-
new name, app, path, constraints, required_defaults, defaults, request_method_match, 0
|
55
|
-
end
|
56
|
-
|
57
53
|
##
|
58
54
|
# +path+ is a path constraint.
|
59
55
|
# +constraints+ is a hash of constraints to be applied to this route.
|
60
|
-
def initialize(name
|
56
|
+
def initialize(name:, app: nil, path:, constraints: {}, required_defaults: [], defaults: {}, request_method_match: nil, precedence: 0, scope_options: {}, internal: false)
|
61
57
|
@name = name
|
62
58
|
@app = app
|
63
59
|
@path = path
|
@@ -72,6 +68,7 @@ module ActionDispatch
|
|
72
68
|
@decorated_ast = nil
|
73
69
|
@precedence = precedence
|
74
70
|
@path_formatter = @path.build_formatter
|
71
|
+
@scope_options = scope_options
|
75
72
|
@internal = internal
|
76
73
|
end
|
77
74
|
|
@@ -91,7 +88,7 @@ module ActionDispatch
|
|
91
88
|
end
|
92
89
|
end
|
93
90
|
|
94
|
-
# Needed for `rails routes`. Picks up succinctly defined requirements
|
91
|
+
# Needed for `bin/rails routes`. Picks up succinctly defined requirements
|
95
92
|
# for a route, for example route
|
96
93
|
#
|
97
94
|
# get 'photo/:id', :controller => 'photos', :action => 'show',
|
@@ -114,18 +111,11 @@ module ActionDispatch
|
|
114
111
|
end
|
115
112
|
|
116
113
|
def score(supplied_keys)
|
117
|
-
|
118
|
-
|
119
|
-
required_keys.each do |k|
|
114
|
+
path.required_names.each do |k|
|
120
115
|
return -1 unless supplied_keys.include?(k)
|
121
116
|
end
|
122
117
|
|
123
|
-
|
124
|
-
path.names.each do |k|
|
125
|
-
score += 1 if supplied_keys.include?(k)
|
126
|
-
end
|
127
|
-
|
128
|
-
score + (required_defaults.length * 2)
|
118
|
+
(required_defaults.length * 2) + path.names.count { |k| supplied_keys.include?(k) }
|
129
119
|
end
|
130
120
|
|
131
121
|
def parts
|
@@ -152,7 +142,7 @@ module ActionDispatch
|
|
152
142
|
end
|
153
143
|
|
154
144
|
def glob?
|
155
|
-
|
145
|
+
path.spec.any?(Nodes::Star)
|
156
146
|
end
|
157
147
|
|
158
148
|
def dispatcher?
|