actionpack 4.2.8 → 5.2.4.2
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 +5 -5
- data/CHANGELOG.md +285 -444
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -7
- data/lib/abstract_controller.rb +12 -5
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +45 -49
- data/lib/abstract_controller/caching.rb +66 -0
- data/lib/{action_controller → abstract_controller}/caching/fragments.rb +78 -15
- data/lib/abstract_controller/callbacks.rb +47 -31
- data/lib/abstract_controller/collector.rb +8 -11
- data/lib/abstract_controller/error.rb +6 -0
- data/lib/abstract_controller/helpers.rb +25 -25
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +4 -2
- data/lib/abstract_controller/rendering.rb +42 -41
- data/lib/abstract_controller/translation.rb +10 -7
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/action_controller.rb +29 -21
- data/lib/action_controller/api.rb +149 -0
- data/lib/action_controller/api/api_rendering.rb +16 -0
- data/lib/action_controller/base.rb +27 -19
- data/lib/action_controller/caching.rb +14 -57
- data/lib/action_controller/form_builder.rb +50 -0
- data/lib/action_controller/log_subscriber.rb +10 -15
- data/lib/action_controller/metal.rb +98 -83
- data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
- data/lib/action_controller/metal/conditional_get.rb +118 -44
- data/lib/action_controller/metal/content_security_policy.rb +52 -0
- data/lib/action_controller/metal/cookies.rb +3 -3
- data/lib/action_controller/metal/data_streaming.rb +27 -46
- data/lib/action_controller/metal/etag_with_flash.rb +18 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +20 -13
- data/lib/action_controller/metal/exceptions.rb +8 -14
- data/lib/action_controller/metal/flash.rb +4 -3
- data/lib/action_controller/metal/force_ssl.rb +23 -21
- data/lib/action_controller/metal/head.rb +21 -19
- data/lib/action_controller/metal/helpers.rb +24 -14
- data/lib/action_controller/metal/http_authentication.rb +64 -57
- data/lib/action_controller/metal/implicit_render.rb +62 -8
- data/lib/action_controller/metal/instrumentation.rb +19 -21
- data/lib/action_controller/metal/live.rb +90 -106
- data/lib/action_controller/metal/mime_responds.rb +33 -46
- data/lib/action_controller/metal/parameter_encoding.rb +51 -0
- data/lib/action_controller/metal/params_wrapper.rb +61 -53
- data/lib/action_controller/metal/redirecting.rb +49 -28
- data/lib/action_controller/metal/renderers.rb +87 -44
- data/lib/action_controller/metal/rendering.rb +72 -50
- data/lib/action_controller/metal/request_forgery_protection.rb +203 -92
- data/lib/action_controller/metal/rescue.rb +9 -16
- data/lib/action_controller/metal/streaming.rb +12 -10
- data/lib/action_controller/metal/strong_parameters.rb +582 -165
- data/lib/action_controller/metal/testing.rb +2 -17
- data/lib/action_controller/metal/url_for.rb +19 -10
- data/lib/action_controller/railtie.rb +28 -10
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +117 -0
- data/lib/action_controller/template_assertions.rb +11 -0
- data/lib/action_controller/test_case.rb +280 -411
- data/lib/action_dispatch.rb +27 -19
- data/lib/action_dispatch/http/cache.rb +93 -47
- data/lib/action_dispatch/http/content_security_policy.rb +272 -0
- data/lib/action_dispatch/http/filter_parameters.rb +26 -20
- data/lib/action_dispatch/http/filter_redirect.rb +10 -11
- data/lib/action_dispatch/http/headers.rb +55 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +60 -41
- data/lib/action_dispatch/http/mime_type.rb +134 -121
- data/lib/action_dispatch/http/mime_types.rb +20 -6
- data/lib/action_dispatch/http/parameter_filter.rb +25 -11
- data/lib/action_dispatch/http/parameters.rb +98 -39
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +200 -118
- data/lib/action_dispatch/http/response.rb +225 -110
- data/lib/action_dispatch/http/upload.rb +12 -6
- data/lib/action_dispatch/http/url.rb +110 -28
- data/lib/action_dispatch/journey.rb +7 -5
- data/lib/action_dispatch/journey/formatter.rb +55 -32
- data/lib/action_dispatch/journey/gtg/builder.rb +7 -5
- data/lib/action_dispatch/journey/gtg/simulator.rb +3 -9
- data/lib/action_dispatch/journey/gtg/transition_table.rb +17 -16
- data/lib/action_dispatch/journey/nfa/builder.rb +5 -3
- data/lib/action_dispatch/journey/nfa/dot.rb +13 -13
- data/lib/action_dispatch/journey/nfa/simulator.rb +3 -1
- data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -48
- data/lib/action_dispatch/journey/nodes/node.rb +18 -6
- data/lib/action_dispatch/journey/parser.rb +23 -22
- data/lib/action_dispatch/journey/parser.y +3 -2
- data/lib/action_dispatch/journey/parser_extras.rb +12 -4
- data/lib/action_dispatch/journey/path/pattern.rb +50 -44
- data/lib/action_dispatch/journey/route.rb +106 -28
- data/lib/action_dispatch/journey/router.rb +35 -23
- data/lib/action_dispatch/journey/router/utils.rb +20 -11
- data/lib/action_dispatch/journey/routes.rb +18 -16
- data/lib/action_dispatch/journey/scanner.rb +18 -15
- data/lib/action_dispatch/journey/visitors.rb +99 -52
- data/lib/action_dispatch/middleware/callbacks.rb +1 -2
- data/lib/action_dispatch/middleware/cookies.rb +304 -193
- data/lib/action_dispatch/middleware/debug_exceptions.rb +152 -57
- data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +68 -69
- data/lib/action_dispatch/middleware/executor.rb +21 -0
- data/lib/action_dispatch/middleware/flash.rb +78 -54
- data/lib/action_dispatch/middleware/public_exceptions.rb +27 -25
- data/lib/action_dispatch/middleware/reloader.rb +5 -91
- data/lib/action_dispatch/middleware/remote_ip.rb +41 -31
- data/lib/action_dispatch/middleware/request_id.rb +17 -9
- data/lib/action_dispatch/middleware/session/abstract_store.rb +41 -25
- data/lib/action_dispatch/middleware/session/cache_store.rb +24 -14
- data/lib/action_dispatch/middleware/session/cookie_store.rb +72 -67
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -2
- data/lib/action_dispatch/middleware/show_exceptions.rb +26 -22
- data/lib/action_dispatch/middleware/ssl.rb +114 -36
- data/lib/action_dispatch/middleware/stack.rb +31 -44
- data/lib/action_dispatch/middleware/static.rb +57 -50
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
- data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +64 -64
- data/lib/action_dispatch/railtie.rb +19 -11
- data/lib/action_dispatch/request/session.rb +106 -59
- data/lib/action_dispatch/request/utils.rb +67 -24
- data/lib/action_dispatch/routing.rb +17 -18
- data/lib/action_dispatch/routing/endpoint.rb +9 -2
- data/lib/action_dispatch/routing/inspector.rb +58 -67
- data/lib/action_dispatch/routing/mapper.rb +734 -447
- data/lib/action_dispatch/routing/polymorphic_routes.rb +161 -139
- data/lib/action_dispatch/routing/redirection.rb +36 -26
- data/lib/action_dispatch/routing/route_set.rb +321 -291
- data/lib/action_dispatch/routing/routes_proxy.rb +32 -5
- data/lib/action_dispatch/routing/url_for.rb +65 -25
- data/lib/action_dispatch/system_test_case.rb +147 -0
- data/lib/action_dispatch/system_testing/browser.rb +49 -0
- data/lib/action_dispatch/system_testing/driver.rb +59 -0
- data/lib/action_dispatch/system_testing/server.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
- data/lib/action_dispatch/testing/assertion_response.rb +47 -0
- data/lib/action_dispatch/testing/assertions.rb +6 -4
- data/lib/action_dispatch/testing/assertions/response.rb +45 -20
- data/lib/action_dispatch/testing/assertions/routing.rb +30 -26
- data/lib/action_dispatch/testing/integration.rb +347 -209
- data/lib/action_dispatch/testing/request_encoder.rb +55 -0
- data/lib/action_dispatch/testing/test_process.rb +28 -22
- data/lib/action_dispatch/testing/test_request.rb +27 -34
- data/lib/action_dispatch/testing/test_response.rb +35 -7
- data/lib/action_pack.rb +4 -2
- data/lib/action_pack/gem_version.rb +5 -3
- data/lib/action_pack/version.rb +3 -1
- metadata +56 -39
- data/lib/action_controller/metal/hide_actions.rb +0 -40
- data/lib/action_controller/metal/rack_delegation.rb +0 -32
- data/lib/action_controller/middleware.rb +0 -39
- data/lib/action_controller/model_naming.rb +0 -12
- data/lib/action_dispatch/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/router/strexp.rb +0 -27
- data/lib/action_dispatch/middleware/params_parser.rb +0 -60
- data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
- data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
- data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -30,7 +30,7 @@ rule
|
|
30
30
|
| dot
|
31
31
|
;
|
32
32
|
slash
|
33
|
-
: SLASH { Slash.new(
|
33
|
+
: SLASH { Slash.new(val.first) }
|
34
34
|
;
|
35
35
|
symbol
|
36
36
|
: SYMBOL { Symbol.new(val.first) }
|
@@ -45,5 +45,6 @@ rule
|
|
45
45
|
end
|
46
46
|
|
47
47
|
---- header
|
48
|
+
# :stopdoc:
|
48
49
|
|
49
|
-
require
|
50
|
+
require "action_dispatch/journey/parser_extras"
|
@@ -1,11 +1,18 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "action_dispatch/journey/scanner"
|
4
|
+
require "action_dispatch/journey/nodes/node"
|
3
5
|
|
4
6
|
module ActionDispatch
|
5
|
-
|
6
|
-
|
7
|
+
# :stopdoc:
|
8
|
+
module Journey
|
9
|
+
class Parser < Racc::Parser
|
7
10
|
include Journey::Nodes
|
8
11
|
|
12
|
+
def self.parse(string)
|
13
|
+
new.parse string
|
14
|
+
end
|
15
|
+
|
9
16
|
def initialize
|
10
17
|
@scanner = Scanner.new
|
11
18
|
end
|
@@ -20,4 +27,5 @@ module ActionDispatch
|
|
20
27
|
end
|
21
28
|
end
|
22
29
|
end
|
30
|
+
# :startdoc:
|
23
31
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionDispatch
|
4
4
|
module Journey # :nodoc:
|
@@ -6,15 +6,21 @@ module ActionDispatch
|
|
6
6
|
class Pattern # :nodoc:
|
7
7
|
attr_reader :spec, :requirements, :anchored
|
8
8
|
|
9
|
-
def self.from_string
|
10
|
-
|
9
|
+
def self.from_string(string)
|
10
|
+
build(string, {}, "/.?", true)
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
+
def initialize(ast, requirements, separators, anchored)
|
20
|
+
@spec = ast
|
21
|
+
@requirements = requirements
|
22
|
+
@separators = separators
|
23
|
+
@anchored = anchored
|
18
24
|
|
19
25
|
@names = nil
|
20
26
|
@optional_names = nil
|
@@ -27,13 +33,20 @@ module ActionDispatch
|
|
27
33
|
Visitors::FormatBuilder.new.accept(spec)
|
28
34
|
end
|
29
35
|
|
36
|
+
def eager_load!
|
37
|
+
required_names
|
38
|
+
offsets
|
39
|
+
to_regexp
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
30
43
|
def ast
|
31
|
-
@spec.
|
44
|
+
@spec.find_all(&:symbol?).each do |node|
|
32
45
|
re = @requirements[node.to_sym]
|
33
46
|
node.regexp = re if re
|
34
47
|
end
|
35
48
|
|
36
|
-
@spec.
|
49
|
+
@spec.find_all(&:star?).each do |node|
|
37
50
|
node = node.left
|
38
51
|
node.regexp = @requirements[node.to_sym] || /(.+)/
|
39
52
|
end
|
@@ -42,7 +55,7 @@ module ActionDispatch
|
|
42
55
|
end
|
43
56
|
|
44
57
|
def names
|
45
|
-
@names ||= spec.
|
58
|
+
@names ||= spec.find_all(&:symbol?).map(&:name)
|
46
59
|
end
|
47
60
|
|
48
61
|
def required_names
|
@@ -50,34 +63,9 @@ module ActionDispatch
|
|
50
63
|
end
|
51
64
|
|
52
65
|
def optional_names
|
53
|
-
@optional_names ||= spec.
|
54
|
-
group.
|
55
|
-
}.map
|
56
|
-
end
|
57
|
-
|
58
|
-
class RegexpOffsets < Journey::Visitors::Visitor # :nodoc:
|
59
|
-
attr_reader :offsets
|
60
|
-
|
61
|
-
def initialize(matchers)
|
62
|
-
@matchers = matchers
|
63
|
-
@capture_count = [0]
|
64
|
-
end
|
65
|
-
|
66
|
-
def visit(node)
|
67
|
-
super
|
68
|
-
@capture_count
|
69
|
-
end
|
70
|
-
|
71
|
-
def visit_SYMBOL(node)
|
72
|
-
node = node.to_sym
|
73
|
-
|
74
|
-
if @matchers.key?(node)
|
75
|
-
re = /#{@matchers[node]}|/
|
76
|
-
@capture_count.push((re.match('').length - 1) + (@capture_count.last || 0))
|
77
|
-
else
|
78
|
-
@capture_count << (@capture_count.last || 0)
|
79
|
-
end
|
80
|
-
end
|
66
|
+
@optional_names ||= spec.find_all(&:group?).flat_map { |group|
|
67
|
+
group.find_all(&:symbol?)
|
68
|
+
}.map(&:name).uniq
|
81
69
|
end
|
82
70
|
|
83
71
|
class AnchoredRegexp < Journey::Visitors::Visitor # :nodoc:
|
@@ -119,14 +107,20 @@ module ActionDispatch
|
|
119
107
|
end
|
120
108
|
|
121
109
|
def visit_STAR(node)
|
122
|
-
re = @matchers[node.left.to_sym] ||
|
110
|
+
re = @matchers[node.left.to_sym] || ".+"
|
123
111
|
"(#{re})"
|
124
112
|
end
|
113
|
+
|
114
|
+
def visit_OR(node)
|
115
|
+
children = node.children.map { |n| visit n }
|
116
|
+
"(?:#{children.join(?|)})"
|
117
|
+
end
|
125
118
|
end
|
126
119
|
|
127
120
|
class UnanchoredRegexp < AnchoredRegexp # :nodoc:
|
128
121
|
def accept(node)
|
129
|
-
|
122
|
+
path = visit node
|
123
|
+
path == "/" ? %r{\A/} : %r{\A#{path}(?:\b|\Z|/)}
|
130
124
|
end
|
131
125
|
end
|
132
126
|
|
@@ -140,7 +134,7 @@ module ActionDispatch
|
|
140
134
|
end
|
141
135
|
|
142
136
|
def captures
|
143
|
-
(length - 1)
|
137
|
+
Array.new(length - 1) { |i| self[i + 1] }
|
144
138
|
end
|
145
139
|
|
146
140
|
def [](x)
|
@@ -184,8 +178,20 @@ module ActionDispatch
|
|
184
178
|
def offsets
|
185
179
|
return @offsets if @offsets
|
186
180
|
|
187
|
-
|
188
|
-
|
181
|
+
@offsets = [0]
|
182
|
+
|
183
|
+
spec.find_all(&:symbol?).each do |node|
|
184
|
+
node = node.to_sym
|
185
|
+
|
186
|
+
if @requirements.key?(node)
|
187
|
+
re = /#{@requirements[node]}|/
|
188
|
+
@offsets.push((re.match("").length - 1) + @offsets.last)
|
189
|
+
else
|
190
|
+
@offsets << @offsets.last
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
@offsets
|
189
195
|
end
|
190
196
|
end
|
191
197
|
end
|
@@ -1,42 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionDispatch
|
2
|
-
|
3
|
-
|
4
|
-
|
4
|
+
# :stopdoc:
|
5
|
+
module Journey
|
6
|
+
class Route
|
7
|
+
attr_reader :app, :path, :defaults, :name, :precedence
|
5
8
|
|
6
|
-
attr_reader :constraints
|
9
|
+
attr_reader :constraints, :internal
|
7
10
|
alias :conditions :constraints
|
8
11
|
|
9
|
-
|
12
|
+
module VerbMatchers
|
13
|
+
VERBS = %w{ DELETE GET HEAD OPTIONS LINK PATCH POST PUT TRACE UNLINK }
|
14
|
+
VERBS.each do |v|
|
15
|
+
class_eval <<-eoc, __FILE__, __LINE__ + 1
|
16
|
+
class #{v}
|
17
|
+
def self.verb; name.split("::").last; end
|
18
|
+
def self.call(req); req.#{v.downcase}?; end
|
19
|
+
end
|
20
|
+
eoc
|
21
|
+
end
|
22
|
+
|
23
|
+
class Unknown
|
24
|
+
attr_reader :verb
|
25
|
+
|
26
|
+
def initialize(verb)
|
27
|
+
@verb = verb
|
28
|
+
end
|
29
|
+
|
30
|
+
def call(request); @verb === request.request_method; end
|
31
|
+
end
|
32
|
+
|
33
|
+
class All
|
34
|
+
def self.call(_); true; end
|
35
|
+
def self.verb; ""; end
|
36
|
+
end
|
37
|
+
|
38
|
+
VERB_TO_CLASS = VERBS.each_with_object(all: All) do |verb, hash|
|
39
|
+
klass = const_get verb
|
40
|
+
hash[verb] = klass
|
41
|
+
hash[verb.downcase] = klass
|
42
|
+
hash[verb.downcase.to_sym] = klass
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.verb_matcher(verb)
|
47
|
+
VerbMatchers::VERB_TO_CLASS.fetch(verb) do
|
48
|
+
VerbMatchers::Unknown.new verb.to_s.dasherize.upcase
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
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
|
10
56
|
|
11
57
|
##
|
12
58
|
# +path+ is a path constraint.
|
13
59
|
# +constraints+ is a hash of constraints to be applied to this route.
|
14
|
-
def initialize(name, app, path, constraints, defaults =
|
60
|
+
def initialize(name, app, path, constraints, required_defaults, defaults, request_method_match, precedence, internal = false)
|
15
61
|
@name = name
|
16
62
|
@app = app
|
17
63
|
@path = path
|
18
64
|
|
65
|
+
@request_method_match = request_method_match
|
19
66
|
@constraints = constraints
|
20
67
|
@defaults = defaults
|
21
68
|
@required_defaults = nil
|
69
|
+
@_required_defaults = required_defaults
|
22
70
|
@required_parts = nil
|
23
71
|
@parts = nil
|
24
72
|
@decorated_ast = nil
|
25
|
-
@precedence =
|
73
|
+
@precedence = precedence
|
26
74
|
@path_formatter = @path.build_formatter
|
75
|
+
@internal = internal
|
76
|
+
end
|
77
|
+
|
78
|
+
def eager_load!
|
79
|
+
path.eager_load!
|
80
|
+
ast
|
81
|
+
parts
|
82
|
+
required_defaults
|
83
|
+
nil
|
27
84
|
end
|
28
85
|
|
29
86
|
def ast
|
30
87
|
@decorated_ast ||= begin
|
31
88
|
decorated_ast = path.ast
|
32
|
-
decorated_ast.
|
89
|
+
decorated_ast.find_all(&:terminal?).each { |n| n.memo = self }
|
33
90
|
decorated_ast
|
34
91
|
end
|
35
92
|
end
|
36
93
|
|
37
|
-
|
38
|
-
|
39
|
-
|
94
|
+
# Needed for `rails routes`. Picks up succinctly defined requirements
|
95
|
+
# for a route, for example route
|
96
|
+
#
|
97
|
+
# get 'photo/:id', :controller => 'photos', :action => 'show',
|
98
|
+
# :id => /[A-Z]\d{5}/
|
99
|
+
#
|
100
|
+
# will have {:controller=>"photos", :action=>"show", :id=>/[A-Z]\d{5}/}
|
101
|
+
# as requirements.
|
102
|
+
def requirements
|
103
|
+
@defaults.merge(path.requirements).delete_if { |_, v|
|
40
104
|
/.+?/ == v
|
41
105
|
}
|
42
106
|
end
|
@@ -49,18 +113,23 @@ module ActionDispatch
|
|
49
113
|
required_parts + required_defaults.keys
|
50
114
|
end
|
51
115
|
|
52
|
-
def score(
|
116
|
+
def score(supplied_keys)
|
53
117
|
required_keys = path.required_names
|
54
|
-
supplied_keys = constraints.map { |k,v| v && k.to_s }.compact
|
55
118
|
|
56
|
-
|
119
|
+
required_keys.each do |k|
|
120
|
+
return -1 unless supplied_keys.include?(k)
|
121
|
+
end
|
122
|
+
|
123
|
+
score = 0
|
124
|
+
path.names.each do |k|
|
125
|
+
score += 1 if supplied_keys.include?(k)
|
126
|
+
end
|
57
127
|
|
58
|
-
score = (supplied_keys & path.names).length
|
59
128
|
score + (required_defaults.length * 2)
|
60
129
|
end
|
61
130
|
|
62
131
|
def parts
|
63
|
-
@parts ||= segments.map
|
132
|
+
@parts ||= segments.map(&:to_sym)
|
64
133
|
end
|
65
134
|
alias :segment_keys :parts
|
66
135
|
|
@@ -68,20 +137,16 @@ module ActionDispatch
|
|
68
137
|
@path_formatter.evaluate path_options
|
69
138
|
end
|
70
139
|
|
71
|
-
def optional_parts
|
72
|
-
path.optional_names.map { |n| n.to_sym }
|
73
|
-
end
|
74
|
-
|
75
140
|
def required_parts
|
76
|
-
@required_parts ||= path.required_names.map
|
141
|
+
@required_parts ||= path.required_names.map(&:to_sym)
|
77
142
|
end
|
78
143
|
|
79
144
|
def required_default?(key)
|
80
|
-
|
145
|
+
@_required_defaults.include?(key)
|
81
146
|
end
|
82
147
|
|
83
148
|
def required_defaults
|
84
|
-
@required_defaults ||= @defaults.dup.delete_if do |k,_|
|
149
|
+
@required_defaults ||= @defaults.dup.delete_if do |k, _|
|
85
150
|
parts.include?(k) || !required_default?(k)
|
86
151
|
end
|
87
152
|
end
|
@@ -95,9 +160,8 @@ module ActionDispatch
|
|
95
160
|
end
|
96
161
|
|
97
162
|
def matches?(request)
|
98
|
-
|
99
|
-
|
100
|
-
|
163
|
+
match_verb(request) &&
|
164
|
+
constraints.all? { |method, value|
|
101
165
|
case value
|
102
166
|
when Regexp, String
|
103
167
|
value === request.send(method).to_s
|
@@ -110,16 +174,30 @@ module ActionDispatch
|
|
110
174
|
else
|
111
175
|
value === request.send(method)
|
112
176
|
end
|
113
|
-
|
177
|
+
}
|
114
178
|
end
|
115
179
|
|
116
180
|
def ip
|
117
181
|
constraints[:ip] || //
|
118
182
|
end
|
119
183
|
|
184
|
+
def requires_matching_verb?
|
185
|
+
!@request_method_match.all? { |x| x == VerbMatchers::All }
|
186
|
+
end
|
187
|
+
|
120
188
|
def verb
|
121
|
-
|
189
|
+
verbs.join("|")
|
122
190
|
end
|
191
|
+
|
192
|
+
private
|
193
|
+
def verbs
|
194
|
+
@request_method_match.map(&:verb)
|
195
|
+
end
|
196
|
+
|
197
|
+
def match_verb(request)
|
198
|
+
@request_method_match.any? { |m| m.call request }
|
199
|
+
end
|
123
200
|
end
|
124
201
|
end
|
202
|
+
# :startdoc:
|
125
203
|
end
|
@@ -1,15 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "action_dispatch/journey/router/utils"
|
4
|
+
require "action_dispatch/journey/routes"
|
5
|
+
require "action_dispatch/journey/formatter"
|
5
6
|
|
6
7
|
before = $-w
|
7
8
|
$-w = false
|
8
|
-
require
|
9
|
+
require "action_dispatch/journey/parser"
|
9
10
|
$-w = before
|
10
11
|
|
11
|
-
require
|
12
|
-
require
|
12
|
+
require "action_dispatch/journey/route"
|
13
|
+
require "action_dispatch/journey/path/pattern"
|
13
14
|
|
14
15
|
module ActionDispatch
|
15
16
|
module Journey # :nodoc:
|
@@ -17,15 +18,19 @@ module ActionDispatch
|
|
17
18
|
class RoutingError < ::StandardError # :nodoc:
|
18
19
|
end
|
19
20
|
|
20
|
-
# :nodoc:
|
21
|
-
VERSION = '2.0.0'
|
22
|
-
|
23
21
|
attr_accessor :routes
|
24
22
|
|
25
23
|
def initialize(routes)
|
26
24
|
@routes = routes
|
27
25
|
end
|
28
26
|
|
27
|
+
def eager_load!
|
28
|
+
# Eagerly trigger the simulator's initialization so
|
29
|
+
# it doesn't happen during a request cycle.
|
30
|
+
simulator
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
29
34
|
def serve(req)
|
30
35
|
find_routes(req).each do |match, parameters, route|
|
31
36
|
set_params = req.path_parameters
|
@@ -33,16 +38,20 @@ module ActionDispatch
|
|
33
38
|
script_name = req.script_name
|
34
39
|
|
35
40
|
unless route.path.anchored
|
36
|
-
req.script_name = (script_name.to_s + match.to_s).chomp(
|
41
|
+
req.script_name = (script_name.to_s + match.to_s).chomp("/")
|
37
42
|
req.path_info = match.post_match
|
38
43
|
req.path_info = "/" + req.path_info unless req.path_info.start_with? "/"
|
39
44
|
end
|
40
45
|
|
46
|
+
parameters = route.defaults.merge parameters.transform_values { |val|
|
47
|
+
val.dup.force_encoding(::Encoding::UTF_8)
|
48
|
+
}
|
49
|
+
|
41
50
|
req.path_parameters = set_params.merge parameters
|
42
51
|
|
43
52
|
status, headers, body = route.app.serve(req)
|
44
53
|
|
45
|
-
if
|
54
|
+
if "pass" == headers["X-Cascade"]
|
46
55
|
req.script_name = script_name
|
47
56
|
req.path_info = path_info
|
48
57
|
req.path_parameters = set_params
|
@@ -52,7 +61,7 @@ module ActionDispatch
|
|
52
61
|
return [status, headers, body]
|
53
62
|
end
|
54
63
|
|
55
|
-
|
64
|
+
[404, { "X-Cascade" => "pass" }, ["Not Found"]]
|
56
65
|
end
|
57
66
|
|
58
67
|
def recognize(rails_req)
|
@@ -62,21 +71,24 @@ module ActionDispatch
|
|
62
71
|
rails_req.path_info = match.post_match.sub(/^([^\/])/, '/\1')
|
63
72
|
end
|
64
73
|
|
74
|
+
parameters = route.defaults.merge parameters
|
65
75
|
yield(route, parameters)
|
66
76
|
end
|
67
77
|
end
|
68
78
|
|
69
79
|
def visualizer
|
70
80
|
tt = GTG::Builder.new(ast).transition_table
|
71
|
-
groups = partitioned_routes.first.map(&:ast).group_by
|
72
|
-
asts = groups.values.map
|
81
|
+
groups = partitioned_routes.first.map(&:ast).group_by(&:to_s)
|
82
|
+
asts = groups.values.map(&:first)
|
73
83
|
tt.visualizer(asts)
|
74
84
|
end
|
75
85
|
|
76
86
|
private
|
77
87
|
|
78
88
|
def partitioned_routes
|
79
|
-
routes.
|
89
|
+
routes.partition { |r|
|
90
|
+
r.path.anchored && r.ast.grep(Nodes::Symbol).all? { |n| n.default_regexp? }
|
91
|
+
}
|
80
92
|
end
|
81
93
|
|
82
94
|
def ast
|
@@ -88,7 +100,7 @@ module ActionDispatch
|
|
88
100
|
end
|
89
101
|
|
90
102
|
def custom_routes
|
91
|
-
|
103
|
+
routes.custom_routes
|
92
104
|
end
|
93
105
|
|
94
106
|
def filter_routes(path)
|
@@ -96,13 +108,13 @@ module ActionDispatch
|
|
96
108
|
simulator.memos(path) { [] }
|
97
109
|
end
|
98
110
|
|
99
|
-
def find_routes
|
111
|
+
def find_routes(req)
|
100
112
|
routes = filter_routes(req.path_info).concat custom_routes.find_all { |r|
|
101
113
|
r.path.match(req.path_info)
|
102
114
|
}
|
103
115
|
|
104
116
|
routes =
|
105
|
-
if req.
|
117
|
+
if req.head?
|
106
118
|
match_head_routes(routes, req)
|
107
119
|
else
|
108
120
|
match_routes(routes, req)
|
@@ -111,9 +123,9 @@ module ActionDispatch
|
|
111
123
|
routes.sort_by!(&:precedence)
|
112
124
|
|
113
125
|
routes.map! { |r|
|
114
|
-
match_data
|
115
|
-
path_parameters =
|
116
|
-
match_data.names.zip(match_data.captures) { |name,val|
|
126
|
+
match_data = r.path.match(req.path_info)
|
127
|
+
path_parameters = {}
|
128
|
+
match_data.names.zip(match_data.captures) { |name, val|
|
117
129
|
path_parameters[name.to_sym] = Utils.unescape_uri(val) if val
|
118
130
|
}
|
119
131
|
[match_data, path_parameters, r]
|
@@ -121,7 +133,7 @@ module ActionDispatch
|
|
121
133
|
end
|
122
134
|
|
123
135
|
def match_head_routes(routes, req)
|
124
|
-
verb_specific_routes = routes.
|
136
|
+
verb_specific_routes = routes.select(&:requires_matching_verb?)
|
125
137
|
head_routes = match_routes(verb_specific_routes, req)
|
126
138
|
|
127
139
|
if head_routes.empty?
|