actionpack 4.2.10 → 7.2.0.rc1
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 +86 -600
- data/MIT-LICENSE +1 -1
- data/README.rdoc +13 -14
- data/lib/abstract_controller/asset_paths.rb +5 -1
- data/lib/abstract_controller/base.rb +166 -136
- data/lib/abstract_controller/caching/fragments.rb +149 -0
- data/lib/abstract_controller/caching.rb +68 -0
- data/lib/abstract_controller/callbacks.rb +126 -57
- data/lib/abstract_controller/collector.rb +13 -15
- data/lib/abstract_controller/deprecator.rb +9 -0
- data/lib/abstract_controller/error.rb +8 -0
- data/lib/abstract_controller/helpers.rb +181 -132
- data/lib/abstract_controller/logger.rb +5 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +10 -3
- data/lib/abstract_controller/rendering.rb +56 -56
- data/lib/abstract_controller/translation.rb +29 -15
- data/lib/abstract_controller/url_for.rb +15 -11
- data/lib/abstract_controller.rb +21 -5
- data/lib/action_controller/api/api_rendering.rb +18 -0
- data/lib/action_controller/api.rb +154 -0
- data/lib/action_controller/base.rb +219 -155
- data/lib/action_controller/caching.rb +28 -68
- data/lib/action_controller/deprecator.rb +9 -0
- data/lib/action_controller/form_builder.rb +55 -0
- data/lib/action_controller/log_subscriber.rb +35 -22
- data/lib/action_controller/metal/allow_browser.rb +119 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +17 -0
- data/lib/action_controller/metal/conditional_get.rb +259 -122
- data/lib/action_controller/metal/content_security_policy.rb +86 -0
- data/lib/action_controller/metal/cookies.rb +9 -5
- data/lib/action_controller/metal/data_streaming.rb +87 -104
- data/lib/action_controller/metal/default_headers.rb +21 -0
- data/lib/action_controller/metal/etag_with_flash.rb +22 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +35 -26
- data/lib/action_controller/metal/exceptions.rb +71 -24
- data/lib/action_controller/metal/flash.rb +26 -19
- data/lib/action_controller/metal/head.rb +45 -36
- data/lib/action_controller/metal/helpers.rb +80 -64
- data/lib/action_controller/metal/http_authentication.rb +297 -244
- data/lib/action_controller/metal/implicit_render.rb +57 -9
- data/lib/action_controller/metal/instrumentation.rb +76 -64
- data/lib/action_controller/metal/live.rb +238 -176
- data/lib/action_controller/metal/logging.rb +22 -0
- data/lib/action_controller/metal/mime_responds.rb +177 -166
- data/lib/action_controller/metal/parameter_encoding.rb +84 -0
- data/lib/action_controller/metal/params_wrapper.rb +145 -118
- data/lib/action_controller/metal/permissions_policy.rb +38 -0
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +203 -64
- data/lib/action_controller/metal/renderers.rb +108 -65
- data/lib/action_controller/metal/rendering.rb +216 -56
- data/lib/action_controller/metal/request_forgery_protection.rb +496 -163
- data/lib/action_controller/metal/rescue.rb +19 -21
- data/lib/action_controller/metal/streaming.rb +179 -138
- data/lib/action_controller/metal/strong_parameters.rb +1058 -382
- data/lib/action_controller/metal/testing.rb +11 -17
- data/lib/action_controller/metal/url_for.rb +37 -21
- data/lib/action_controller/metal.rb +236 -138
- data/lib/action_controller/railtie.rb +89 -11
- data/lib/action_controller/railties/helpers.rb +5 -1
- data/lib/action_controller/renderer.rb +161 -0
- data/lib/action_controller/template_assertions.rb +13 -0
- data/lib/action_controller/test_case.rb +425 -497
- data/lib/action_controller.rb +44 -22
- data/lib/action_dispatch/constants.rb +34 -0
- data/lib/action_dispatch/deprecator.rb +9 -0
- data/lib/action_dispatch/http/cache.rb +119 -63
- data/lib/action_dispatch/http/content_disposition.rb +47 -0
- data/lib/action_dispatch/http/content_security_policy.rb +364 -0
- data/lib/action_dispatch/http/filter_parameters.rb +36 -34
- data/lib/action_dispatch/http/filter_redirect.rb +24 -12
- data/lib/action_dispatch/http/headers.rb +66 -31
- data/lib/action_dispatch/http/mime_negotiation.rb +106 -75
- data/lib/action_dispatch/http/mime_type.rb +196 -136
- data/lib/action_dispatch/http/mime_types.rb +25 -7
- data/lib/action_dispatch/http/parameters.rb +97 -45
- data/lib/action_dispatch/http/permissions_policy.rb +187 -0
- data/lib/action_dispatch/http/rack_cache.rb +6 -0
- data/lib/action_dispatch/http/request.rb +299 -170
- data/lib/action_dispatch/http/response.rb +311 -160
- data/lib/action_dispatch/http/upload.rb +52 -23
- data/lib/action_dispatch/http/url.rb +201 -125
- data/lib/action_dispatch/journey/formatter.rb +110 -50
- data/lib/action_dispatch/journey/gtg/builder.rb +37 -50
- data/lib/action_dispatch/journey/gtg/simulator.rb +20 -17
- data/lib/action_dispatch/journey/gtg/transition_table.rb +96 -36
- data/lib/action_dispatch/journey/nfa/dot.rb +5 -14
- data/lib/action_dispatch/journey/nodes/node.rb +100 -20
- data/lib/action_dispatch/journey/parser.rb +19 -17
- data/lib/action_dispatch/journey/parser.y +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +14 -4
- data/lib/action_dispatch/journey/path/pattern.rb +79 -63
- data/lib/action_dispatch/journey/route.rb +108 -44
- data/lib/action_dispatch/journey/router/utils.rb +41 -29
- data/lib/action_dispatch/journey/router.rb +64 -57
- data/lib/action_dispatch/journey/routes.rb +23 -21
- data/lib/action_dispatch/journey/scanner.rb +28 -17
- data/lib/action_dispatch/journey/visitors.rb +100 -54
- data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
- data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
- data/lib/action_dispatch/journey.rb +7 -5
- data/lib/action_dispatch/log_subscriber.rb +25 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
- data/lib/action_dispatch/middleware/callbacks.rb +7 -6
- data/lib/action_dispatch/middleware/cookies.rb +471 -328
- data/lib/action_dispatch/middleware/debug_exceptions.rb +149 -66
- data/lib/action_dispatch/middleware/debug_locks.rb +129 -0
- data/lib/action_dispatch/middleware/debug_view.rb +73 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +275 -73
- data/lib/action_dispatch/middleware/executor.rb +32 -0
- data/lib/action_dispatch/middleware/flash.rb +143 -101
- data/lib/action_dispatch/middleware/host_authorization.rb +171 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +36 -27
- data/lib/action_dispatch/middleware/reloader.rb +10 -92
- data/lib/action_dispatch/middleware/remote_ip.rb +133 -107
- data/lib/action_dispatch/middleware/request_id.rb +29 -15
- data/lib/action_dispatch/middleware/server_timing.rb +78 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +49 -27
- data/lib/action_dispatch/middleware/session/cache_store.rb +33 -16
- data/lib/action_dispatch/middleware/session/cookie_store.rb +86 -80
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +66 -36
- data/lib/action_dispatch/middleware/ssl.rb +134 -36
- data/lib/action_dispatch/middleware/stack.rb +109 -44
- data/lib/action_dispatch/middleware/static.rb +159 -90
- 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 +7 -24
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +36 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +46 -36
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +12 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +26 -7
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +16 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +139 -15
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +23 -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 +6 -6
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +7 -7
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +9 -9
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +7 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +125 -93
- data/lib/action_dispatch/railtie.rb +44 -16
- data/lib/action_dispatch/request/session.rb +159 -69
- data/lib/action_dispatch/request/utils.rb +97 -23
- data/lib/action_dispatch/routing/endpoint.rb +11 -2
- data/lib/action_dispatch/routing/inspector.rb +195 -106
- data/lib/action_dispatch/routing/mapper.rb +1338 -955
- data/lib/action_dispatch/routing/polymorphic_routes.rb +234 -201
- data/lib/action_dispatch/routing/redirection.rb +78 -51
- data/lib/action_dispatch/routing/route_set.rb +460 -374
- data/lib/action_dispatch/routing/routes_proxy.rb +36 -12
- data/lib/action_dispatch/routing/url_for.rb +172 -124
- data/lib/action_dispatch/routing.rb +159 -158
- data/lib/action_dispatch/system_test_case.rb +206 -0
- data/lib/action_dispatch/system_testing/browser.rb +84 -0
- data/lib/action_dispatch/system_testing/driver.rb +85 -0
- data/lib/action_dispatch/system_testing/server.rb +33 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +164 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +23 -0
- data/lib/action_dispatch/testing/assertion_response.rb +48 -0
- data/lib/action_dispatch/testing/assertions/response.rb +71 -39
- data/lib/action_dispatch/testing/assertions/routing.rb +228 -103
- data/lib/action_dispatch/testing/assertions.rb +9 -6
- data/lib/action_dispatch/testing/integration.rb +486 -306
- data/lib/action_dispatch/testing/request_encoder.rb +60 -0
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +35 -22
- data/lib/action_dispatch/testing/test_request.rb +29 -34
- data/lib/action_dispatch/testing/test_response.rb +48 -15
- data/lib/action_dispatch.rb +82 -40
- data/lib/action_pack/gem_version.rb +8 -4
- data/lib/action_pack/version.rb +6 -2
- data/lib/action_pack.rb +21 -18
- metadata +146 -56
- data/lib/action_controller/caching/fragments.rb +0 -103
- data/lib/action_controller/metal/force_ssl.rb +0 -97
- 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/http/parameter_filter.rb +0 -72
- data/lib/action_dispatch/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -76
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -163
- data/lib/action_dispatch/journey/router/strexp.rb +0 -27
- data/lib/action_dispatch/middleware/params_parser.rb +0 -60
- data/lib/action_dispatch/middleware/templates/rescues/_source.erb +0 -27
- 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
@@ -1,22 +1,21 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :markup: markdown
|
2
4
|
|
3
5
|
module ActionDispatch
|
4
6
|
module Journey # :nodoc:
|
5
7
|
module Path # :nodoc:
|
6
8
|
class Pattern # :nodoc:
|
7
|
-
attr_reader :
|
8
|
-
|
9
|
-
def self.from_string string
|
10
|
-
new Journey::Router::Strexp.build(string, {}, ["/.?"], true)
|
11
|
-
end
|
9
|
+
attr_reader :ast, :names, :requirements, :anchored, :spec
|
12
10
|
|
13
|
-
def initialize(
|
14
|
-
@
|
15
|
-
@
|
16
|
-
@
|
17
|
-
@
|
11
|
+
def initialize(ast, requirements, separators, anchored)
|
12
|
+
@ast = ast
|
13
|
+
@spec = ast.root
|
14
|
+
@requirements = requirements
|
15
|
+
@separators = separators
|
16
|
+
@anchored = anchored
|
18
17
|
|
19
|
-
@names =
|
18
|
+
@names = ast.names
|
20
19
|
@optional_names = nil
|
21
20
|
@required_names = nil
|
22
21
|
@re = nil
|
@@ -27,22 +26,33 @@ module ActionDispatch
|
|
27
26
|
Visitors::FormatBuilder.new.accept(spec)
|
28
27
|
end
|
29
28
|
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
29
|
+
def eager_load!
|
30
|
+
required_names
|
31
|
+
offsets
|
32
|
+
to_regexp
|
33
|
+
@ast = nil
|
34
|
+
end
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
def requirements_anchored?
|
37
|
+
# each required param must not be surrounded by a literal, otherwise it isn't
|
38
|
+
# simple to chunk-match the url piecemeal
|
39
|
+
terminals = ast.terminals
|
40
40
|
|
41
|
-
|
42
|
-
|
41
|
+
terminals.each_with_index { |s, index|
|
42
|
+
next if index < 1
|
43
|
+
next if s.type == :DOT || s.type == :SLASH
|
44
|
+
|
45
|
+
back = terminals[index - 1]
|
46
|
+
fwd = terminals[index + 1]
|
47
|
+
|
48
|
+
# we also don't support this yet, constraints must be regexps
|
49
|
+
return false if s.symbol? && s.regexp.is_a?(Array)
|
43
50
|
|
44
|
-
|
45
|
-
|
51
|
+
return false if back.literal?
|
52
|
+
return false if !fwd.nil? && fwd.literal?
|
53
|
+
}
|
54
|
+
|
55
|
+
true
|
46
56
|
end
|
47
57
|
|
48
58
|
def required_names
|
@@ -50,34 +60,9 @@ module ActionDispatch
|
|
50
60
|
end
|
51
61
|
|
52
62
|
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
|
63
|
+
@optional_names ||= spec.find_all(&:group?).flat_map { |group|
|
64
|
+
group.find_all(&:symbol?)
|
65
|
+
}.map(&:name).uniq
|
81
66
|
end
|
82
67
|
|
83
68
|
class AnchoredRegexp < Journey::Visitors::Visitor # :nodoc:
|
@@ -93,7 +78,7 @@ module ActionDispatch
|
|
93
78
|
end
|
94
79
|
|
95
80
|
def visit_CAT(node)
|
96
|
-
|
81
|
+
"#{visit(node.left)}#{visit(node.right)}"
|
97
82
|
end
|
98
83
|
|
99
84
|
def visit_SYMBOL(node)
|
@@ -102,7 +87,7 @@ module ActionDispatch
|
|
102
87
|
return @separator_re unless @matchers.key?(node)
|
103
88
|
|
104
89
|
re = @matchers[node]
|
105
|
-
"(#{re})"
|
90
|
+
"(#{Regexp.union(re)})"
|
106
91
|
end
|
107
92
|
|
108
93
|
def visit_GROUP(node)
|
@@ -119,14 +104,20 @@ module ActionDispatch
|
|
119
104
|
end
|
120
105
|
|
121
106
|
def visit_STAR(node)
|
122
|
-
re = @matchers[node.left.to_sym]
|
123
|
-
"(#{re})"
|
107
|
+
re = @matchers[node.left.to_sym]
|
108
|
+
re ? "(#{re})" : "(.+)"
|
109
|
+
end
|
110
|
+
|
111
|
+
def visit_OR(node)
|
112
|
+
children = node.children.map { |n| visit n }
|
113
|
+
"(?:#{children.join(?|)})"
|
124
114
|
end
|
125
115
|
end
|
126
116
|
|
127
117
|
class UnanchoredRegexp < AnchoredRegexp # :nodoc:
|
128
118
|
def accept(node)
|
129
|
-
|
119
|
+
path = visit node
|
120
|
+
path == "/" ? %r{\A/} : %r{\A#{path}(?:\b|\Z|/)}
|
130
121
|
end
|
131
122
|
end
|
132
123
|
|
@@ -140,7 +131,11 @@ module ActionDispatch
|
|
140
131
|
end
|
141
132
|
|
142
133
|
def captures
|
143
|
-
(length - 1)
|
134
|
+
Array.new(length - 1) { |i| self[i + 1] }
|
135
|
+
end
|
136
|
+
|
137
|
+
def named_captures
|
138
|
+
@names.zip(captures).to_h
|
144
139
|
end
|
145
140
|
|
146
141
|
def [](x)
|
@@ -167,6 +162,10 @@ module ActionDispatch
|
|
167
162
|
end
|
168
163
|
alias :=~ :match
|
169
164
|
|
165
|
+
def match?(other)
|
166
|
+
to_regexp.match?(other)
|
167
|
+
end
|
168
|
+
|
170
169
|
def source
|
171
170
|
to_regexp.source
|
172
171
|
end
|
@@ -175,17 +174,34 @@ module ActionDispatch
|
|
175
174
|
@re ||= regexp_visitor.new(@separators, @requirements).accept spec
|
176
175
|
end
|
177
176
|
|
178
|
-
|
177
|
+
def requirements_for_missing_keys_check
|
178
|
+
@requirements_for_missing_keys_check ||= requirements.transform_values do |regex|
|
179
|
+
/\A#{regex}\Z/
|
180
|
+
end
|
181
|
+
end
|
179
182
|
|
183
|
+
private
|
180
184
|
def regexp_visitor
|
181
185
|
@anchored ? AnchoredRegexp : UnanchoredRegexp
|
182
186
|
end
|
183
187
|
|
184
188
|
def offsets
|
185
|
-
|
189
|
+
@offsets ||= begin
|
190
|
+
offsets = [0]
|
191
|
+
|
192
|
+
spec.find_all(&:symbol?).each do |node|
|
193
|
+
node = node.to_sym
|
186
194
|
|
187
|
-
|
188
|
-
|
195
|
+
if @requirements.key?(node)
|
196
|
+
re = /#{Regexp.union(@requirements[node])}|/
|
197
|
+
offsets.push((re.match("").length - 1) + offsets.last)
|
198
|
+
else
|
199
|
+
offsets << offsets.last
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
offsets
|
204
|
+
end
|
189
205
|
end
|
190
206
|
end
|
191
207
|
end
|
@@ -1,43 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :markup: markdown
|
4
|
+
|
1
5
|
module ActionDispatch
|
2
|
-
|
3
|
-
|
4
|
-
|
6
|
+
# :stopdoc:
|
7
|
+
module Journey
|
8
|
+
class Route
|
9
|
+
attr_reader :app, :path, :defaults, :name, :precedence, :constraints,
|
10
|
+
:internal, :scope_options, :ast, :source_location
|
5
11
|
|
6
|
-
attr_reader :constraints
|
7
12
|
alias :conditions :constraints
|
8
13
|
|
9
|
-
|
14
|
+
module VerbMatchers
|
15
|
+
VERBS = %w{ DELETE GET HEAD OPTIONS LINK PATCH POST PUT TRACE UNLINK }
|
16
|
+
VERBS.each do |v|
|
17
|
+
class_eval <<-eoc, __FILE__, __LINE__ + 1
|
18
|
+
# frozen_string_literal: true
|
19
|
+
class #{v}
|
20
|
+
def self.verb; name.split("::").last; end
|
21
|
+
def self.call(req); req.#{v.downcase}?; end
|
22
|
+
end
|
23
|
+
eoc
|
24
|
+
end
|
25
|
+
|
26
|
+
class Unknown
|
27
|
+
attr_reader :verb
|
28
|
+
|
29
|
+
def initialize(verb)
|
30
|
+
@verb = verb
|
31
|
+
end
|
32
|
+
|
33
|
+
def call(request); @verb == request.request_method; end
|
34
|
+
end
|
35
|
+
|
36
|
+
class All
|
37
|
+
def self.call(_); true; end
|
38
|
+
def self.verb; ""; end
|
39
|
+
end
|
40
|
+
|
41
|
+
VERB_TO_CLASS = VERBS.each_with_object(all: All) do |verb, hash|
|
42
|
+
klass = const_get verb
|
43
|
+
hash[verb] = klass
|
44
|
+
hash[verb.downcase] = klass
|
45
|
+
hash[verb.downcase.to_sym] = klass
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.verb_matcher(verb)
|
50
|
+
VerbMatchers::VERB_TO_CLASS.fetch(verb) do
|
51
|
+
VerbMatchers::Unknown.new verb.to_s.dasherize.upcase
|
52
|
+
end
|
53
|
+
end
|
10
54
|
|
11
55
|
##
|
12
56
|
# +path+ is a path constraint.
|
13
|
-
#
|
14
|
-
def initialize(name
|
57
|
+
# `constraints` is a hash of constraints to be applied to this route.
|
58
|
+
def initialize(name:, app: nil, path:, constraints: {}, required_defaults: [], defaults: {}, request_method_match: nil, precedence: 0, scope_options: {}, internal: false, source_location: nil)
|
15
59
|
@name = name
|
16
60
|
@app = app
|
17
61
|
@path = path
|
18
62
|
|
63
|
+
@request_method_match = request_method_match
|
19
64
|
@constraints = constraints
|
20
65
|
@defaults = defaults
|
21
66
|
@required_defaults = nil
|
67
|
+
@_required_defaults = required_defaults
|
22
68
|
@required_parts = nil
|
23
69
|
@parts = nil
|
24
|
-
@
|
25
|
-
@precedence = 0
|
70
|
+
@precedence = precedence
|
26
71
|
@path_formatter = @path.build_formatter
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
72
|
+
@scope_options = scope_options
|
73
|
+
@internal = internal
|
74
|
+
@source_location = source_location
|
75
|
+
|
76
|
+
@ast = @path.ast.root
|
77
|
+
@path.ast.route = self
|
78
|
+
end
|
79
|
+
|
80
|
+
def eager_load!
|
81
|
+
path.eager_load!
|
82
|
+
parts
|
83
|
+
required_defaults
|
84
|
+
nil
|
85
|
+
end
|
86
|
+
|
87
|
+
# Needed for `bin/rails routes`. Picks up succinctly defined requirements for a
|
88
|
+
# route, for example route
|
89
|
+
#
|
90
|
+
# get 'photo/:id', :controller => 'photos', :action => 'show',
|
91
|
+
# :id => /[A-Z]\d{5}/
|
92
|
+
#
|
93
|
+
# will have {:controller=>"photos", :action=>"show", :[id=>/](A-Z){5}/} as
|
94
|
+
# requirements.
|
95
|
+
def requirements
|
96
|
+
@defaults.merge(path.requirements).delete_if { |_, v|
|
97
|
+
/.+?/m == v
|
41
98
|
}
|
42
99
|
end
|
43
100
|
|
@@ -49,18 +106,16 @@ module ActionDispatch
|
|
49
106
|
required_parts + required_defaults.keys
|
50
107
|
end
|
51
108
|
|
52
|
-
def score(
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
return -1 unless (required_keys - supplied_keys).empty?
|
109
|
+
def score(supplied_keys)
|
110
|
+
path.required_names.each do |k|
|
111
|
+
return -1 unless supplied_keys.include?(k)
|
112
|
+
end
|
57
113
|
|
58
|
-
|
59
|
-
score + (required_defaults.length * 2)
|
114
|
+
(required_defaults.length * 2) + path.names.count { |k| supplied_keys.include?(k) }
|
60
115
|
end
|
61
116
|
|
62
117
|
def parts
|
63
|
-
@parts ||= segments.map
|
118
|
+
@parts ||= segments.map(&:to_sym)
|
64
119
|
end
|
65
120
|
alias :segment_keys :parts
|
66
121
|
|
@@ -68,26 +123,22 @@ module ActionDispatch
|
|
68
123
|
@path_formatter.evaluate path_options
|
69
124
|
end
|
70
125
|
|
71
|
-
def optional_parts
|
72
|
-
path.optional_names.map { |n| n.to_sym }
|
73
|
-
end
|
74
|
-
|
75
126
|
def required_parts
|
76
|
-
@required_parts ||= path.required_names.map
|
127
|
+
@required_parts ||= path.required_names.map(&:to_sym)
|
77
128
|
end
|
78
129
|
|
79
130
|
def required_default?(key)
|
80
|
-
|
131
|
+
@_required_defaults.include?(key)
|
81
132
|
end
|
82
133
|
|
83
134
|
def required_defaults
|
84
|
-
@required_defaults ||= @defaults.dup.delete_if do |k,_|
|
135
|
+
@required_defaults ||= @defaults.dup.delete_if do |k, _|
|
85
136
|
parts.include?(k) || !required_default?(k)
|
86
137
|
end
|
87
138
|
end
|
88
139
|
|
89
140
|
def glob?
|
90
|
-
|
141
|
+
path.ast.glob?
|
91
142
|
end
|
92
143
|
|
93
144
|
def dispatcher?
|
@@ -95,9 +146,8 @@ module ActionDispatch
|
|
95
146
|
end
|
96
147
|
|
97
148
|
def matches?(request)
|
98
|
-
|
99
|
-
|
100
|
-
|
149
|
+
match_verb(request) &&
|
150
|
+
constraints.all? { |method, value|
|
101
151
|
case value
|
102
152
|
when Regexp, String
|
103
153
|
value === request.send(method).to_s
|
@@ -110,16 +160,30 @@ module ActionDispatch
|
|
110
160
|
else
|
111
161
|
value === request.send(method)
|
112
162
|
end
|
113
|
-
|
163
|
+
}
|
114
164
|
end
|
115
165
|
|
116
166
|
def ip
|
117
167
|
constraints[:ip] || //
|
118
168
|
end
|
119
169
|
|
170
|
+
def requires_matching_verb?
|
171
|
+
!@request_method_match.all? { |x| x == VerbMatchers::All }
|
172
|
+
end
|
173
|
+
|
120
174
|
def verb
|
121
|
-
|
175
|
+
verbs.join("|")
|
122
176
|
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
|
123
186
|
end
|
124
187
|
end
|
188
|
+
# :startdoc:
|
125
189
|
end
|
@@ -1,45 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :markup: markdown
|
4
|
+
|
1
5
|
module ActionDispatch
|
2
6
|
module Journey # :nodoc:
|
3
7
|
class Router # :nodoc:
|
4
8
|
class Utils # :nodoc:
|
5
9
|
# Normalizes URI path.
|
6
10
|
#
|
7
|
-
# Strips off trailing slash and ensures there is a leading slash.
|
8
|
-
#
|
11
|
+
# Strips off trailing slash and ensures there is a leading slash. Also converts
|
12
|
+
# downcase URL encoded string to uppercase.
|
9
13
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
14
|
+
# normalize_path("/foo") # => "/foo"
|
15
|
+
# normalize_path("/foo/") # => "/foo"
|
16
|
+
# normalize_path("foo") # => "/foo"
|
17
|
+
# normalize_path("") # => "/"
|
18
|
+
# normalize_path("/%ab") # => "/%AB"
|
15
19
|
def self.normalize_path(path)
|
16
|
-
path
|
17
|
-
path.
|
18
|
-
path
|
19
|
-
path.
|
20
|
-
|
21
|
-
path
|
20
|
+
path ||= ""
|
21
|
+
encoding = path.encoding
|
22
|
+
path = +"/#{path}"
|
23
|
+
path.squeeze!("/")
|
24
|
+
|
25
|
+
unless path == "/"
|
26
|
+
path.delete_suffix!("/")
|
27
|
+
path.gsub!(/(%[a-f0-9]{2})/) { $1.upcase }
|
28
|
+
end
|
29
|
+
|
30
|
+
path.force_encoding(encoding)
|
22
31
|
end
|
23
32
|
|
24
|
-
# URI path and fragment escaping
|
25
|
-
# http://tools.ietf.org/html/rfc3986
|
33
|
+
# URI path and fragment escaping https://tools.ietf.org/html/rfc3986
|
26
34
|
class UriEncoder # :nodoc:
|
27
|
-
ENCODE = "%%%02X"
|
35
|
+
ENCODE = "%%%02X"
|
28
36
|
US_ASCII = Encoding::US_ASCII
|
29
37
|
UTF_8 = Encoding::UTF_8
|
30
|
-
EMPTY = "".force_encoding(US_ASCII).freeze
|
31
|
-
DEC2HEX = (0..255).
|
38
|
+
EMPTY = (+"").force_encoding(US_ASCII).freeze
|
39
|
+
DEC2HEX = (0..255).map { |i| (ENCODE % i).force_encoding(US_ASCII) }
|
32
40
|
|
33
|
-
ALPHA = "a-zA-Z"
|
34
|
-
DIGIT = "0-9"
|
35
|
-
UNRESERVED = "#{ALPHA}#{DIGIT}\\-\\._~"
|
36
|
-
SUB_DELIMS = "!\\$&'\\(\\)\\*\\+,;="
|
41
|
+
ALPHA = "a-zA-Z"
|
42
|
+
DIGIT = "0-9"
|
43
|
+
UNRESERVED = "#{ALPHA}#{DIGIT}\\-\\._~"
|
44
|
+
SUB_DELIMS = "!\\$&'\\(\\)\\*\\+,;="
|
37
45
|
|
38
|
-
ESCAPED = /%[a-zA-Z0-9]{2}
|
46
|
+
ESCAPED = /%[a-zA-Z0-9]{2}/
|
39
47
|
|
40
|
-
FRAGMENT = /[^#{UNRESERVED}#{SUB_DELIMS}
|
41
|
-
SEGMENT = /[^#{UNRESERVED}#{SUB_DELIMS}:@]
|
42
|
-
PATH = /[^#{UNRESERVED}#{SUB_DELIMS}:@\/]
|
48
|
+
FRAGMENT = /[^#{UNRESERVED}#{SUB_DELIMS}:@\/?]/
|
49
|
+
SEGMENT = /[^#{UNRESERVED}#{SUB_DELIMS}:@]/
|
50
|
+
PATH = /[^#{UNRESERVED}#{SUB_DELIMS}:@\/]/
|
43
51
|
|
44
52
|
def escape_fragment(fragment)
|
45
53
|
escape(fragment, FRAGMENT)
|
@@ -55,12 +63,12 @@ module ActionDispatch
|
|
55
63
|
|
56
64
|
def unescape_uri(uri)
|
57
65
|
encoding = uri.encoding == US_ASCII ? UTF_8 : uri.encoding
|
58
|
-
uri.gsub(ESCAPED) { [
|
66
|
+
uri.gsub(ESCAPED) { |match| [match[1, 2].hex].pack("C") }.force_encoding(encoding)
|
59
67
|
end
|
60
68
|
|
61
|
-
|
69
|
+
private
|
62
70
|
def escape(component, pattern)
|
63
|
-
component.gsub(pattern){ |unsafe| percent_encode(unsafe) }.force_encoding(US_ASCII)
|
71
|
+
component.gsub(pattern) { |unsafe| percent_encode(unsafe) }.force_encoding(US_ASCII)
|
64
72
|
end
|
65
73
|
|
66
74
|
def percent_encode(unsafe)
|
@@ -84,6 +92,10 @@ module ActionDispatch
|
|
84
92
|
ENCODER.escape_fragment(fragment.to_s)
|
85
93
|
end
|
86
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"
|
87
99
|
def self.unescape_uri(uri)
|
88
100
|
ENCODER.unescape_uri(uri)
|
89
101
|
end
|