omg-actionpack 8.0.0.alpha1

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.
Files changed (187) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +129 -0
  3. data/MIT-LICENSE +21 -0
  4. data/README.rdoc +57 -0
  5. data/lib/abstract_controller/asset_paths.rb +14 -0
  6. data/lib/abstract_controller/base.rb +299 -0
  7. data/lib/abstract_controller/caching/fragments.rb +149 -0
  8. data/lib/abstract_controller/caching.rb +68 -0
  9. data/lib/abstract_controller/callbacks.rb +265 -0
  10. data/lib/abstract_controller/collector.rb +44 -0
  11. data/lib/abstract_controller/deprecator.rb +9 -0
  12. data/lib/abstract_controller/error.rb +8 -0
  13. data/lib/abstract_controller/helpers.rb +243 -0
  14. data/lib/abstract_controller/logger.rb +16 -0
  15. data/lib/abstract_controller/railties/routes_helpers.rb +25 -0
  16. data/lib/abstract_controller/rendering.rb +126 -0
  17. data/lib/abstract_controller/translation.rb +42 -0
  18. data/lib/abstract_controller/url_for.rb +37 -0
  19. data/lib/abstract_controller.rb +36 -0
  20. data/lib/action_controller/api/api_rendering.rb +18 -0
  21. data/lib/action_controller/api.rb +155 -0
  22. data/lib/action_controller/base.rb +332 -0
  23. data/lib/action_controller/caching.rb +49 -0
  24. data/lib/action_controller/deprecator.rb +9 -0
  25. data/lib/action_controller/form_builder.rb +55 -0
  26. data/lib/action_controller/log_subscriber.rb +96 -0
  27. data/lib/action_controller/metal/allow_browser.rb +123 -0
  28. data/lib/action_controller/metal/basic_implicit_render.rb +17 -0
  29. data/lib/action_controller/metal/conditional_get.rb +341 -0
  30. data/lib/action_controller/metal/content_security_policy.rb +86 -0
  31. data/lib/action_controller/metal/cookies.rb +20 -0
  32. data/lib/action_controller/metal/data_streaming.rb +154 -0
  33. data/lib/action_controller/metal/default_headers.rb +21 -0
  34. data/lib/action_controller/metal/etag_with_flash.rb +22 -0
  35. data/lib/action_controller/metal/etag_with_template_digest.rb +59 -0
  36. data/lib/action_controller/metal/exceptions.rb +106 -0
  37. data/lib/action_controller/metal/flash.rb +67 -0
  38. data/lib/action_controller/metal/head.rb +67 -0
  39. data/lib/action_controller/metal/helpers.rb +129 -0
  40. data/lib/action_controller/metal/http_authentication.rb +565 -0
  41. data/lib/action_controller/metal/implicit_render.rb +67 -0
  42. data/lib/action_controller/metal/instrumentation.rb +120 -0
  43. data/lib/action_controller/metal/live.rb +398 -0
  44. data/lib/action_controller/metal/logging.rb +22 -0
  45. data/lib/action_controller/metal/mime_responds.rb +337 -0
  46. data/lib/action_controller/metal/parameter_encoding.rb +84 -0
  47. data/lib/action_controller/metal/params_wrapper.rb +312 -0
  48. data/lib/action_controller/metal/permissions_policy.rb +38 -0
  49. data/lib/action_controller/metal/rate_limiting.rb +62 -0
  50. data/lib/action_controller/metal/redirecting.rb +251 -0
  51. data/lib/action_controller/metal/renderers.rb +181 -0
  52. data/lib/action_controller/metal/rendering.rb +260 -0
  53. data/lib/action_controller/metal/request_forgery_protection.rb +667 -0
  54. data/lib/action_controller/metal/rescue.rb +33 -0
  55. data/lib/action_controller/metal/streaming.rb +183 -0
  56. data/lib/action_controller/metal/strong_parameters.rb +1546 -0
  57. data/lib/action_controller/metal/testing.rb +25 -0
  58. data/lib/action_controller/metal/url_for.rb +65 -0
  59. data/lib/action_controller/metal.rb +339 -0
  60. data/lib/action_controller/railtie.rb +149 -0
  61. data/lib/action_controller/railties/helpers.rb +26 -0
  62. data/lib/action_controller/renderer.rb +161 -0
  63. data/lib/action_controller/template_assertions.rb +13 -0
  64. data/lib/action_controller/test_case.rb +691 -0
  65. data/lib/action_controller.rb +80 -0
  66. data/lib/action_dispatch/constants.rb +34 -0
  67. data/lib/action_dispatch/deprecator.rb +9 -0
  68. data/lib/action_dispatch/http/cache.rb +249 -0
  69. data/lib/action_dispatch/http/content_disposition.rb +47 -0
  70. data/lib/action_dispatch/http/content_security_policy.rb +365 -0
  71. data/lib/action_dispatch/http/filter_parameters.rb +80 -0
  72. data/lib/action_dispatch/http/filter_redirect.rb +50 -0
  73. data/lib/action_dispatch/http/headers.rb +134 -0
  74. data/lib/action_dispatch/http/mime_negotiation.rb +187 -0
  75. data/lib/action_dispatch/http/mime_type.rb +389 -0
  76. data/lib/action_dispatch/http/mime_types.rb +54 -0
  77. data/lib/action_dispatch/http/parameters.rb +119 -0
  78. data/lib/action_dispatch/http/permissions_policy.rb +189 -0
  79. data/lib/action_dispatch/http/rack_cache.rb +67 -0
  80. data/lib/action_dispatch/http/request.rb +498 -0
  81. data/lib/action_dispatch/http/response.rb +556 -0
  82. data/lib/action_dispatch/http/upload.rb +107 -0
  83. data/lib/action_dispatch/http/url.rb +344 -0
  84. data/lib/action_dispatch/journey/formatter.rb +226 -0
  85. data/lib/action_dispatch/journey/gtg/builder.rb +149 -0
  86. data/lib/action_dispatch/journey/gtg/simulator.rb +50 -0
  87. data/lib/action_dispatch/journey/gtg/transition_table.rb +217 -0
  88. data/lib/action_dispatch/journey/nfa/dot.rb +27 -0
  89. data/lib/action_dispatch/journey/nodes/node.rb +208 -0
  90. data/lib/action_dispatch/journey/parser.rb +103 -0
  91. data/lib/action_dispatch/journey/path/pattern.rb +209 -0
  92. data/lib/action_dispatch/journey/route.rb +189 -0
  93. data/lib/action_dispatch/journey/router/utils.rb +105 -0
  94. data/lib/action_dispatch/journey/router.rb +151 -0
  95. data/lib/action_dispatch/journey/routes.rb +82 -0
  96. data/lib/action_dispatch/journey/scanner.rb +70 -0
  97. data/lib/action_dispatch/journey/visitors.rb +267 -0
  98. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  99. data/lib/action_dispatch/journey/visualizer/fsm.js +159 -0
  100. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  101. data/lib/action_dispatch/journey.rb +7 -0
  102. data/lib/action_dispatch/log_subscriber.rb +25 -0
  103. data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
  104. data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
  105. data/lib/action_dispatch/middleware/callbacks.rb +38 -0
  106. data/lib/action_dispatch/middleware/cookies.rb +719 -0
  107. data/lib/action_dispatch/middleware/debug_exceptions.rb +206 -0
  108. data/lib/action_dispatch/middleware/debug_locks.rb +129 -0
  109. data/lib/action_dispatch/middleware/debug_view.rb +73 -0
  110. data/lib/action_dispatch/middleware/exception_wrapper.rb +350 -0
  111. data/lib/action_dispatch/middleware/executor.rb +32 -0
  112. data/lib/action_dispatch/middleware/flash.rb +318 -0
  113. data/lib/action_dispatch/middleware/host_authorization.rb +171 -0
  114. data/lib/action_dispatch/middleware/public_exceptions.rb +64 -0
  115. data/lib/action_dispatch/middleware/reloader.rb +16 -0
  116. data/lib/action_dispatch/middleware/remote_ip.rb +199 -0
  117. data/lib/action_dispatch/middleware/request_id.rb +50 -0
  118. data/lib/action_dispatch/middleware/server_timing.rb +78 -0
  119. data/lib/action_dispatch/middleware/session/abstract_store.rb +112 -0
  120. data/lib/action_dispatch/middleware/session/cache_store.rb +66 -0
  121. data/lib/action_dispatch/middleware/session/cookie_store.rb +129 -0
  122. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +34 -0
  123. data/lib/action_dispatch/middleware/show_exceptions.rb +88 -0
  124. data/lib/action_dispatch/middleware/ssl.rb +180 -0
  125. data/lib/action_dispatch/middleware/stack.rb +194 -0
  126. data/lib/action_dispatch/middleware/static.rb +192 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  128. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +17 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  132. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +36 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +62 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  136. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +12 -0
  137. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +9 -0
  138. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +35 -0
  139. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  140. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
  141. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +16 -0
  142. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +284 -0
  143. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +23 -0
  144. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  145. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  146. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  147. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  148. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  149. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  150. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  151. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  152. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  153. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +19 -0
  154. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +232 -0
  155. data/lib/action_dispatch/railtie.rb +77 -0
  156. data/lib/action_dispatch/request/session.rb +283 -0
  157. data/lib/action_dispatch/request/utils.rb +109 -0
  158. data/lib/action_dispatch/routing/endpoint.rb +19 -0
  159. data/lib/action_dispatch/routing/inspector.rb +323 -0
  160. data/lib/action_dispatch/routing/mapper.rb +2372 -0
  161. data/lib/action_dispatch/routing/polymorphic_routes.rb +363 -0
  162. data/lib/action_dispatch/routing/redirection.rb +218 -0
  163. data/lib/action_dispatch/routing/route_set.rb +958 -0
  164. data/lib/action_dispatch/routing/routes_proxy.rb +66 -0
  165. data/lib/action_dispatch/routing/url_for.rb +244 -0
  166. data/lib/action_dispatch/routing.rb +262 -0
  167. data/lib/action_dispatch/system_test_case.rb +206 -0
  168. data/lib/action_dispatch/system_testing/browser.rb +75 -0
  169. data/lib/action_dispatch/system_testing/driver.rb +85 -0
  170. data/lib/action_dispatch/system_testing/server.rb +33 -0
  171. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +164 -0
  172. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +23 -0
  173. data/lib/action_dispatch/testing/assertion_response.rb +48 -0
  174. data/lib/action_dispatch/testing/assertions/response.rb +114 -0
  175. data/lib/action_dispatch/testing/assertions/routing.rb +343 -0
  176. data/lib/action_dispatch/testing/assertions.rb +25 -0
  177. data/lib/action_dispatch/testing/integration.rb +694 -0
  178. data/lib/action_dispatch/testing/request_encoder.rb +60 -0
  179. data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
  180. data/lib/action_dispatch/testing/test_process.rb +57 -0
  181. data/lib/action_dispatch/testing/test_request.rb +73 -0
  182. data/lib/action_dispatch/testing/test_response.rb +58 -0
  183. data/lib/action_dispatch.rb +147 -0
  184. data/lib/action_pack/gem_version.rb +19 -0
  185. data/lib/action_pack/version.rb +12 -0
  186. data/lib/action_pack.rb +27 -0
  187. metadata +375 -0
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "action_dispatch/journey/scanner"
4
+ require "action_dispatch/journey/nodes/node"
5
+
6
+ module ActionDispatch
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
103
+ end
@@ -0,0 +1,209 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ module ActionDispatch
6
+ module Journey # :nodoc:
7
+ module Path # :nodoc:
8
+ class Pattern # :nodoc:
9
+ attr_reader :ast, :names, :requirements, :anchored, :spec
10
+
11
+ def initialize(ast, requirements, separators, anchored)
12
+ @ast = ast
13
+ @spec = ast.root
14
+ @requirements = requirements
15
+ @separators = separators
16
+ @anchored = anchored
17
+
18
+ @names = ast.names
19
+ @optional_names = nil
20
+ @required_names = nil
21
+ @re = nil
22
+ @offsets = nil
23
+ end
24
+
25
+ def build_formatter
26
+ Visitors::FormatBuilder.new.accept(spec)
27
+ end
28
+
29
+ def eager_load!
30
+ required_names
31
+ offsets
32
+ to_regexp
33
+ @ast = nil
34
+ end
35
+
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
+
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)
50
+
51
+ return false if back.literal?
52
+ return false if !fwd.nil? && fwd.literal?
53
+ }
54
+
55
+ true
56
+ end
57
+
58
+ def required_names
59
+ @required_names ||= names - optional_names
60
+ end
61
+
62
+ def optional_names
63
+ @optional_names ||= spec.find_all(&:group?).flat_map { |group|
64
+ group.find_all(&:symbol?)
65
+ }.map(&:name).uniq
66
+ end
67
+
68
+ class AnchoredRegexp < Journey::Visitors::Visitor # :nodoc:
69
+ def initialize(separator, matchers)
70
+ @separator = separator
71
+ @matchers = matchers
72
+ @separator_re = "([^#{separator}]+)"
73
+ super()
74
+ end
75
+
76
+ def accept(node)
77
+ %r{\A#{visit node}\Z}
78
+ end
79
+
80
+ def visit_CAT(node)
81
+ "#{visit(node.left)}#{visit(node.right)}"
82
+ end
83
+
84
+ def visit_SYMBOL(node)
85
+ node = node.to_sym
86
+
87
+ return @separator_re unless @matchers.key?(node)
88
+
89
+ re = @matchers[node]
90
+ "(#{Regexp.union(re)})"
91
+ end
92
+
93
+ def visit_GROUP(node)
94
+ "(?:#{visit node.left})?"
95
+ end
96
+
97
+ def visit_LITERAL(node)
98
+ Regexp.escape(node.left)
99
+ end
100
+ alias :visit_DOT :visit_LITERAL
101
+
102
+ def visit_SLASH(node)
103
+ node.left
104
+ end
105
+
106
+ def visit_STAR(node)
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(?|)})"
114
+ end
115
+ end
116
+
117
+ class UnanchoredRegexp < AnchoredRegexp # :nodoc:
118
+ def accept(node)
119
+ path = visit node
120
+ path == "/" ? %r{\A/} : %r{\A#{path}(?:\b|\Z|/)}
121
+ end
122
+ end
123
+
124
+ class MatchData # :nodoc:
125
+ attr_reader :names
126
+
127
+ def initialize(names, offsets, match)
128
+ @names = names
129
+ @offsets = offsets
130
+ @match = match
131
+ end
132
+
133
+ def captures
134
+ Array.new(length - 1) { |i| self[i + 1] }
135
+ end
136
+
137
+ def named_captures
138
+ @names.zip(captures).to_h
139
+ end
140
+
141
+ def [](x)
142
+ idx = @offsets[x - 1] + x
143
+ @match[idx]
144
+ end
145
+
146
+ def length
147
+ @offsets.length
148
+ end
149
+
150
+ def post_match
151
+ @match.post_match
152
+ end
153
+
154
+ def to_s
155
+ @match.to_s
156
+ end
157
+ end
158
+
159
+ def match(other)
160
+ return unless match = to_regexp.match(other)
161
+ MatchData.new(names, offsets, match)
162
+ end
163
+ alias :=~ :match
164
+
165
+ def match?(other)
166
+ to_regexp.match?(other)
167
+ end
168
+
169
+ def source
170
+ to_regexp.source
171
+ end
172
+
173
+ def to_regexp
174
+ @re ||= regexp_visitor.new(@separators, @requirements).accept spec
175
+ end
176
+
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
182
+
183
+ private
184
+ def regexp_visitor
185
+ @anchored ? AnchoredRegexp : UnanchoredRegexp
186
+ end
187
+
188
+ def offsets
189
+ @offsets ||= begin
190
+ offsets = [0]
191
+
192
+ spec.find_all(&:symbol?).each do |node|
193
+ node = node.to_sym
194
+
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
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,189 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ module ActionDispatch
6
+ # :stopdoc:
7
+ module Journey
8
+ class Route
9
+ attr_reader :app, :path, :defaults, :name, :precedence, :constraints,
10
+ :internal, :scope_options, :ast, :source_location
11
+
12
+ alias :conditions :constraints
13
+
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
54
+
55
+ ##
56
+ # +path+ is a path constraint.
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)
59
+ @name = name
60
+ @app = app
61
+ @path = path
62
+
63
+ @request_method_match = request_method_match
64
+ @constraints = constraints
65
+ @defaults = defaults
66
+ @required_defaults = nil
67
+ @_required_defaults = required_defaults
68
+ @required_parts = nil
69
+ @parts = nil
70
+ @precedence = precedence
71
+ @path_formatter = @path.build_formatter
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
98
+ }
99
+ end
100
+
101
+ def segments
102
+ path.names
103
+ end
104
+
105
+ def required_keys
106
+ required_parts + required_defaults.keys
107
+ end
108
+
109
+ def score(supplied_keys)
110
+ path.required_names.each do |k|
111
+ return -1 unless supplied_keys.include?(k)
112
+ end
113
+
114
+ (required_defaults.length * 2) + path.names.count { |k| supplied_keys.include?(k) }
115
+ end
116
+
117
+ def parts
118
+ @parts ||= segments.map(&:to_sym)
119
+ end
120
+ alias :segment_keys :parts
121
+
122
+ def format(path_options)
123
+ @path_formatter.evaluate path_options
124
+ end
125
+
126
+ def required_parts
127
+ @required_parts ||= path.required_names.map(&:to_sym)
128
+ end
129
+
130
+ def required_default?(key)
131
+ @_required_defaults.include?(key)
132
+ end
133
+
134
+ def required_defaults
135
+ @required_defaults ||= @defaults.dup.delete_if do |k, _|
136
+ parts.include?(k) || !required_default?(k)
137
+ end
138
+ end
139
+
140
+ def glob?
141
+ path.ast.glob?
142
+ end
143
+
144
+ def dispatcher?
145
+ @app.dispatcher?
146
+ end
147
+
148
+ def matches?(request)
149
+ match_verb(request) &&
150
+ constraints.all? { |method, value|
151
+ case value
152
+ when Regexp, String
153
+ value === request.send(method).to_s
154
+ when Array
155
+ value.include?(request.send(method))
156
+ when TrueClass
157
+ request.send(method).present?
158
+ when FalseClass
159
+ request.send(method).blank?
160
+ else
161
+ value === request.send(method)
162
+ end
163
+ }
164
+ end
165
+
166
+ def ip
167
+ constraints[:ip] || //
168
+ end
169
+
170
+ def requires_matching_verb?
171
+ !@request_method_match.all? { |x| x == VerbMatchers::All }
172
+ end
173
+
174
+ def verb
175
+ verbs.join("|")
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
186
+ end
187
+ end
188
+ # :startdoc:
189
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ module ActionDispatch
6
+ module Journey # :nodoc:
7
+ class Router # :nodoc:
8
+ class Utils # :nodoc:
9
+ # Normalizes URI path.
10
+ #
11
+ # Strips off trailing slash and ensures there is a leading slash. Also converts
12
+ # downcase URL encoded string to uppercase.
13
+ #
14
+ # normalize_path("/foo") # => "/foo"
15
+ # normalize_path("/foo/") # => "/foo"
16
+ # normalize_path("foo") # => "/foo"
17
+ # normalize_path("") # => "/"
18
+ # normalize_path("/%ab") # => "/%AB"
19
+ def self.normalize_path(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)
31
+ end
32
+
33
+ # URI path and fragment escaping https://tools.ietf.org/html/rfc3986
34
+ class UriEncoder # :nodoc:
35
+ ENCODE = "%%%02X"
36
+ US_ASCII = Encoding::US_ASCII
37
+ UTF_8 = Encoding::UTF_8
38
+ EMPTY = (+"").force_encoding(US_ASCII).freeze
39
+ DEC2HEX = (0..255).map { |i| (ENCODE % i).force_encoding(US_ASCII) }
40
+
41
+ ALPHA = "a-zA-Z"
42
+ DIGIT = "0-9"
43
+ UNRESERVED = "#{ALPHA}#{DIGIT}\\-\\._~"
44
+ SUB_DELIMS = "!\\$&'\\(\\)\\*\\+,;="
45
+
46
+ ESCAPED = /%[a-zA-Z0-9]{2}/
47
+
48
+ FRAGMENT = /[^#{UNRESERVED}#{SUB_DELIMS}:@\/?]/
49
+ SEGMENT = /[^#{UNRESERVED}#{SUB_DELIMS}:@]/
50
+ PATH = /[^#{UNRESERVED}#{SUB_DELIMS}:@\/]/
51
+
52
+ def escape_fragment(fragment)
53
+ escape(fragment, FRAGMENT)
54
+ end
55
+
56
+ def escape_path(path)
57
+ escape(path, PATH)
58
+ end
59
+
60
+ def escape_segment(segment)
61
+ escape(segment, SEGMENT)
62
+ end
63
+
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
+ private
70
+ def escape(component, pattern)
71
+ component.gsub(pattern) { |unsafe| percent_encode(unsafe) }.force_encoding(US_ASCII)
72
+ end
73
+
74
+ def percent_encode(unsafe)
75
+ safe = EMPTY.dup
76
+ unsafe.each_byte { |b| safe << DEC2HEX[b] }
77
+ safe
78
+ end
79
+ end
80
+
81
+ ENCODER = UriEncoder.new
82
+
83
+ def self.escape_path(path)
84
+ ENCODER.escape_path(path.to_s)
85
+ end
86
+
87
+ def self.escape_segment(segment)
88
+ ENCODER.escape_segment(segment.to_s)
89
+ end
90
+
91
+ def self.escape_fragment(fragment)
92
+ ENCODER.escape_fragment(fragment.to_s)
93
+ 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
+ end
103
+ end
104
+ end
105
+ end