actionpack 3.2.22.5 → 5.2.4

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.

Files changed (271) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +279 -603
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +13 -297
  5. data/lib/abstract_controller/asset_paths.rb +4 -2
  6. data/lib/abstract_controller/base.rb +82 -52
  7. data/lib/abstract_controller/caching/fragments.rb +166 -0
  8. data/lib/abstract_controller/caching.rb +66 -0
  9. data/lib/abstract_controller/callbacks.rb +117 -103
  10. data/lib/abstract_controller/collector.rb +18 -7
  11. data/lib/abstract_controller/error.rb +6 -0
  12. data/lib/abstract_controller/helpers.rb +65 -38
  13. data/lib/abstract_controller/logger.rb +3 -2
  14. data/lib/abstract_controller/railties/routes_helpers.rb +5 -3
  15. data/lib/abstract_controller/rendering.rb +77 -129
  16. data/lib/abstract_controller/translation.rb +21 -3
  17. data/lib/abstract_controller/url_for.rb +9 -7
  18. data/lib/abstract_controller.rb +12 -13
  19. data/lib/action_controller/api/api_rendering.rb +16 -0
  20. data/lib/action_controller/api.rb +149 -0
  21. data/lib/action_controller/base.rb +81 -40
  22. data/lib/action_controller/caching.rb +22 -62
  23. data/lib/action_controller/form_builder.rb +50 -0
  24. data/lib/action_controller/log_subscriber.rb +30 -18
  25. data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
  26. data/lib/action_controller/metal/conditional_get.rb +190 -47
  27. data/lib/action_controller/metal/content_security_policy.rb +52 -0
  28. data/lib/action_controller/metal/cookies.rb +3 -3
  29. data/lib/action_controller/metal/data_streaming.rb +40 -65
  30. data/lib/action_controller/metal/etag_with_flash.rb +18 -0
  31. data/lib/action_controller/metal/etag_with_template_digest.rb +57 -0
  32. data/lib/action_controller/metal/exceptions.rb +19 -12
  33. data/lib/action_controller/metal/flash.rb +42 -9
  34. data/lib/action_controller/metal/force_ssl.rb +79 -19
  35. data/lib/action_controller/metal/head.rb +35 -10
  36. data/lib/action_controller/metal/helpers.rb +31 -21
  37. data/lib/action_controller/metal/http_authentication.rb +182 -134
  38. data/lib/action_controller/metal/implicit_render.rb +62 -8
  39. data/lib/action_controller/metal/instrumentation.rb +28 -26
  40. data/lib/action_controller/metal/live.rb +312 -0
  41. data/lib/action_controller/metal/mime_responds.rb +159 -163
  42. data/lib/action_controller/metal/parameter_encoding.rb +51 -0
  43. data/lib/action_controller/metal/params_wrapper.rb +146 -93
  44. data/lib/action_controller/metal/redirecting.rb +80 -56
  45. data/lib/action_controller/metal/renderers.rb +119 -47
  46. data/lib/action_controller/metal/rendering.rb +89 -32
  47. data/lib/action_controller/metal/request_forgery_protection.rb +373 -41
  48. data/lib/action_controller/metal/rescue.rb +9 -16
  49. data/lib/action_controller/metal/streaming.rb +39 -45
  50. data/lib/action_controller/metal/strong_parameters.rb +1086 -0
  51. data/lib/action_controller/metal/testing.rb +8 -29
  52. data/lib/action_controller/metal/url_for.rb +43 -32
  53. data/lib/action_controller/metal.rb +112 -106
  54. data/lib/action_controller/railtie.rb +56 -18
  55. data/lib/action_controller/railties/helpers.rb +24 -0
  56. data/lib/action_controller/renderer.rb +117 -0
  57. data/lib/action_controller/template_assertions.rb +11 -0
  58. data/lib/action_controller/test_case.rb +402 -347
  59. data/lib/action_controller.rb +31 -30
  60. data/lib/action_dispatch/http/cache.rb +133 -34
  61. data/lib/action_dispatch/http/content_security_policy.rb +272 -0
  62. data/lib/action_dispatch/http/filter_parameters.rb +40 -24
  63. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  64. data/lib/action_dispatch/http/headers.rb +117 -16
  65. data/lib/action_dispatch/http/mime_negotiation.rb +98 -33
  66. data/lib/action_dispatch/http/mime_type.rb +198 -146
  67. data/lib/action_dispatch/http/mime_types.rb +22 -7
  68. data/lib/action_dispatch/http/parameter_filter.rb +61 -49
  69. data/lib/action_dispatch/http/parameters.rb +94 -51
  70. data/lib/action_dispatch/http/rack_cache.rb +4 -3
  71. data/lib/action_dispatch/http/request.rb +262 -117
  72. data/lib/action_dispatch/http/response.rb +400 -86
  73. data/lib/action_dispatch/http/upload.rb +66 -29
  74. data/lib/action_dispatch/http/url.rb +232 -60
  75. data/lib/action_dispatch/journey/formatter.rb +189 -0
  76. data/lib/action_dispatch/journey/gtg/builder.rb +164 -0
  77. data/lib/action_dispatch/journey/gtg/simulator.rb +41 -0
  78. data/lib/action_dispatch/journey/gtg/transition_table.rb +158 -0
  79. data/lib/action_dispatch/journey/nfa/builder.rb +78 -0
  80. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  81. data/lib/action_dispatch/journey/nfa/simulator.rb +49 -0
  82. data/lib/action_dispatch/journey/nfa/transition_table.rb +120 -0
  83. data/lib/action_dispatch/journey/nodes/node.rb +140 -0
  84. data/lib/action_dispatch/journey/parser.rb +199 -0
  85. data/lib/action_dispatch/journey/parser.y +50 -0
  86. data/lib/action_dispatch/journey/parser_extras.rb +31 -0
  87. data/lib/action_dispatch/journey/path/pattern.rb +199 -0
  88. data/lib/action_dispatch/journey/route.rb +203 -0
  89. data/lib/action_dispatch/journey/router/utils.rb +102 -0
  90. data/lib/action_dispatch/journey/router.rb +156 -0
  91. data/lib/action_dispatch/journey/routes.rb +82 -0
  92. data/lib/action_dispatch/journey/scanner.rb +64 -0
  93. data/lib/action_dispatch/journey/visitors.rb +268 -0
  94. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  95. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  96. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  97. data/lib/action_dispatch/journey.rb +7 -0
  98. data/lib/action_dispatch/middleware/callbacks.rb +17 -13
  99. data/lib/action_dispatch/middleware/cookies.rb +494 -162
  100. data/lib/action_dispatch/middleware/debug_exceptions.rb +176 -53
  101. data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
  102. data/lib/action_dispatch/middleware/exception_wrapper.rb +103 -38
  103. data/lib/action_dispatch/middleware/executor.rb +21 -0
  104. data/lib/action_dispatch/middleware/flash.rb +128 -91
  105. data/lib/action_dispatch/middleware/public_exceptions.rb +43 -16
  106. data/lib/action_dispatch/middleware/reloader.rb +6 -83
  107. data/lib/action_dispatch/middleware/remote_ip.rb +151 -49
  108. data/lib/action_dispatch/middleware/request_id.rb +19 -15
  109. data/lib/action_dispatch/middleware/session/abstract_store.rb +38 -34
  110. data/lib/action_dispatch/middleware/session/cache_store.rb +14 -9
  111. data/lib/action_dispatch/middleware/session/cookie_store.rb +94 -44
  112. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -4
  113. data/lib/action_dispatch/middleware/show_exceptions.rb +36 -61
  114. data/lib/action_dispatch/middleware/ssl.rb +150 -0
  115. data/lib/action_dispatch/middleware/stack.rb +33 -41
  116. data/lib/action_dispatch/middleware/static.rb +92 -48
  117. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +22 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +27 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  122. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  123. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
  124. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  125. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
  126. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +134 -5
  128. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  132. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  136. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  137. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
  138. data/lib/action_dispatch/railtie.rb +29 -8
  139. data/lib/action_dispatch/request/session.rb +234 -0
  140. data/lib/action_dispatch/request/utils.rb +78 -0
  141. data/lib/action_dispatch/routing/endpoint.rb +17 -0
  142. data/lib/action_dispatch/routing/inspector.rb +225 -0
  143. data/lib/action_dispatch/routing/mapper.rb +1329 -582
  144. data/lib/action_dispatch/routing/polymorphic_routes.rb +237 -94
  145. data/lib/action_dispatch/routing/redirection.rb +120 -50
  146. data/lib/action_dispatch/routing/route_set.rb +545 -322
  147. data/lib/action_dispatch/routing/routes_proxy.rb +37 -7
  148. data/lib/action_dispatch/routing/url_for.rb +103 -34
  149. data/lib/action_dispatch/routing.rb +66 -99
  150. data/lib/action_dispatch/system_test_case.rb +147 -0
  151. data/lib/action_dispatch/system_testing/browser.rb +49 -0
  152. data/lib/action_dispatch/system_testing/driver.rb +59 -0
  153. data/lib/action_dispatch/system_testing/server.rb +31 -0
  154. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
  155. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
  156. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
  157. data/lib/action_dispatch/testing/assertion_response.rb +47 -0
  158. data/lib/action_dispatch/testing/assertions/response.rb +53 -42
  159. data/lib/action_dispatch/testing/assertions/routing.rb +79 -74
  160. data/lib/action_dispatch/testing/assertions.rb +15 -9
  161. data/lib/action_dispatch/testing/integration.rb +361 -207
  162. data/lib/action_dispatch/testing/request_encoder.rb +55 -0
  163. data/lib/action_dispatch/testing/test_process.rb +28 -19
  164. data/lib/action_dispatch/testing/test_request.rb +30 -33
  165. data/lib/action_dispatch/testing/test_response.rb +35 -11
  166. data/lib/action_dispatch.rb +42 -32
  167. data/lib/action_pack/gem_version.rb +17 -0
  168. data/lib/action_pack/version.rb +7 -7
  169. data/lib/action_pack.rb +4 -2
  170. metadata +116 -175
  171. data/lib/abstract_controller/layouts.rb +0 -423
  172. data/lib/abstract_controller/view_paths.rb +0 -96
  173. data/lib/action_controller/caching/actions.rb +0 -185
  174. data/lib/action_controller/caching/fragments.rb +0 -127
  175. data/lib/action_controller/caching/pages.rb +0 -187
  176. data/lib/action_controller/caching/sweeping.rb +0 -97
  177. data/lib/action_controller/deprecated/integration_test.rb +0 -2
  178. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  179. data/lib/action_controller/deprecated.rb +0 -3
  180. data/lib/action_controller/metal/compatibility.rb +0 -65
  181. data/lib/action_controller/metal/hide_actions.rb +0 -41
  182. data/lib/action_controller/metal/rack_delegation.rb +0 -26
  183. data/lib/action_controller/metal/responder.rb +0 -286
  184. data/lib/action_controller/metal/session_management.rb +0 -14
  185. data/lib/action_controller/middleware.rb +0 -39
  186. data/lib/action_controller/railties/paths.rb +0 -25
  187. data/lib/action_controller/record_identifier.rb +0 -85
  188. data/lib/action_controller/vendor/html-scanner/html/document.rb +0 -68
  189. data/lib/action_controller/vendor/html-scanner/html/node.rb +0 -532
  190. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +0 -177
  191. data/lib/action_controller/vendor/html-scanner/html/selector.rb +0 -830
  192. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +0 -107
  193. data/lib/action_controller/vendor/html-scanner/html/version.rb +0 -11
  194. data/lib/action_controller/vendor/html-scanner.rb +0 -20
  195. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  196. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  197. data/lib/action_dispatch/middleware/head.rb +0 -18
  198. data/lib/action_dispatch/middleware/params_parser.rb +0 -75
  199. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  200. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +0 -31
  201. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -26
  202. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +0 -10
  203. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -2
  204. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +0 -15
  205. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -17
  206. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +0 -2
  207. data/lib/action_dispatch/testing/assertions/dom.rb +0 -37
  208. data/lib/action_dispatch/testing/assertions/selector.rb +0 -435
  209. data/lib/action_dispatch/testing/assertions/tag.rb +0 -138
  210. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  211. data/lib/action_view/asset_paths.rb +0 -142
  212. data/lib/action_view/base.rb +0 -220
  213. data/lib/action_view/buffers.rb +0 -43
  214. data/lib/action_view/context.rb +0 -36
  215. data/lib/action_view/flows.rb +0 -79
  216. data/lib/action_view/helpers/active_model_helper.rb +0 -50
  217. data/lib/action_view/helpers/asset_paths.rb +0 -7
  218. data/lib/action_view/helpers/asset_tag_helper.rb +0 -457
  219. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  220. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  221. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  222. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  223. data/lib/action_view/helpers/atom_feed_helper.rb +0 -200
  224. data/lib/action_view/helpers/cache_helper.rb +0 -64
  225. data/lib/action_view/helpers/capture_helper.rb +0 -203
  226. data/lib/action_view/helpers/controller_helper.rb +0 -25
  227. data/lib/action_view/helpers/csrf_helper.rb +0 -32
  228. data/lib/action_view/helpers/date_helper.rb +0 -1062
  229. data/lib/action_view/helpers/debug_helper.rb +0 -40
  230. data/lib/action_view/helpers/form_helper.rb +0 -1486
  231. data/lib/action_view/helpers/form_options_helper.rb +0 -658
  232. data/lib/action_view/helpers/form_tag_helper.rb +0 -685
  233. data/lib/action_view/helpers/javascript_helper.rb +0 -110
  234. data/lib/action_view/helpers/number_helper.rb +0 -622
  235. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  236. data/lib/action_view/helpers/record_tag_helper.rb +0 -111
  237. data/lib/action_view/helpers/rendering_helper.rb +0 -92
  238. data/lib/action_view/helpers/sanitize_helper.rb +0 -259
  239. data/lib/action_view/helpers/tag_helper.rb +0 -167
  240. data/lib/action_view/helpers/text_helper.rb +0 -426
  241. data/lib/action_view/helpers/translation_helper.rb +0 -91
  242. data/lib/action_view/helpers/url_helper.rb +0 -693
  243. data/lib/action_view/helpers.rb +0 -60
  244. data/lib/action_view/locale/en.yml +0 -160
  245. data/lib/action_view/log_subscriber.rb +0 -28
  246. data/lib/action_view/lookup_context.rb +0 -258
  247. data/lib/action_view/path_set.rb +0 -101
  248. data/lib/action_view/railtie.rb +0 -55
  249. data/lib/action_view/renderer/abstract_renderer.rb +0 -41
  250. data/lib/action_view/renderer/partial_renderer.rb +0 -415
  251. data/lib/action_view/renderer/renderer.rb +0 -61
  252. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -106
  253. data/lib/action_view/renderer/template_renderer.rb +0 -95
  254. data/lib/action_view/template/error.rb +0 -128
  255. data/lib/action_view/template/handlers/builder.rb +0 -26
  256. data/lib/action_view/template/handlers/erb.rb +0 -125
  257. data/lib/action_view/template/handlers.rb +0 -50
  258. data/lib/action_view/template/resolver.rb +0 -298
  259. data/lib/action_view/template/text.rb +0 -30
  260. data/lib/action_view/template.rb +0 -337
  261. data/lib/action_view/test_case.rb +0 -246
  262. data/lib/action_view/testing/resolvers.rb +0 -49
  263. data/lib/action_view.rb +0 -84
  264. data/lib/sprockets/assets.rake +0 -99
  265. data/lib/sprockets/bootstrap.rb +0 -37
  266. data/lib/sprockets/compressors.rb +0 -83
  267. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  268. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  269. data/lib/sprockets/helpers.rb +0 -6
  270. data/lib/sprockets/railtie.rb +0 -62
  271. data/lib/sprockets/static_compiler.rb +0 -56
@@ -0,0 +1,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ # :stopdoc:
5
+ module Journey
6
+ class Route
7
+ attr_reader :app, :path, :defaults, :name, :precedence
8
+
9
+ attr_reader :constraints, :internal
10
+ alias :conditions :constraints
11
+
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
56
+
57
+ ##
58
+ # +path+ is a path constraint.
59
+ # +constraints+ is a hash of constraints to be applied to this route.
60
+ def initialize(name, app, path, constraints, required_defaults, defaults, request_method_match, precedence, internal = false)
61
+ @name = name
62
+ @app = app
63
+ @path = path
64
+
65
+ @request_method_match = request_method_match
66
+ @constraints = constraints
67
+ @defaults = defaults
68
+ @required_defaults = nil
69
+ @_required_defaults = required_defaults
70
+ @required_parts = nil
71
+ @parts = nil
72
+ @decorated_ast = nil
73
+ @precedence = precedence
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
84
+ end
85
+
86
+ def ast
87
+ @decorated_ast ||= begin
88
+ decorated_ast = path.ast
89
+ decorated_ast.find_all(&:terminal?).each { |n| n.memo = self }
90
+ decorated_ast
91
+ end
92
+ end
93
+
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|
104
+ /.+?/ == v
105
+ }
106
+ end
107
+
108
+ def segments
109
+ path.names
110
+ end
111
+
112
+ def required_keys
113
+ required_parts + required_defaults.keys
114
+ end
115
+
116
+ def score(supplied_keys)
117
+ required_keys = path.required_names
118
+
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
127
+
128
+ score + (required_defaults.length * 2)
129
+ end
130
+
131
+ def parts
132
+ @parts ||= segments.map(&:to_sym)
133
+ end
134
+ alias :segment_keys :parts
135
+
136
+ def format(path_options)
137
+ @path_formatter.evaluate path_options
138
+ end
139
+
140
+ def required_parts
141
+ @required_parts ||= path.required_names.map(&:to_sym)
142
+ end
143
+
144
+ def required_default?(key)
145
+ @_required_defaults.include?(key)
146
+ end
147
+
148
+ def required_defaults
149
+ @required_defaults ||= @defaults.dup.delete_if do |k, _|
150
+ parts.include?(k) || !required_default?(k)
151
+ end
152
+ end
153
+
154
+ def glob?
155
+ !path.spec.grep(Nodes::Star).empty?
156
+ end
157
+
158
+ def dispatcher?
159
+ @app.dispatcher?
160
+ end
161
+
162
+ def matches?(request)
163
+ match_verb(request) &&
164
+ constraints.all? { |method, value|
165
+ case value
166
+ when Regexp, String
167
+ value === request.send(method).to_s
168
+ when Array
169
+ value.include?(request.send(method))
170
+ when TrueClass
171
+ request.send(method).present?
172
+ when FalseClass
173
+ request.send(method).blank?
174
+ else
175
+ value === request.send(method)
176
+ end
177
+ }
178
+ end
179
+
180
+ def ip
181
+ constraints[:ip] || //
182
+ end
183
+
184
+ def requires_matching_verb?
185
+ !@request_method_match.all? { |x| x == VerbMatchers::All }
186
+ end
187
+
188
+ def verb
189
+ verbs.join("|")
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
200
+ end
201
+ end
202
+ # :startdoc:
203
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ module Journey # :nodoc:
5
+ class Router # :nodoc:
6
+ class Utils # :nodoc:
7
+ # Normalizes URI path.
8
+ #
9
+ # Strips off trailing slash and ensures there is a leading slash.
10
+ # Also converts downcase URL encoded string to uppercase.
11
+ #
12
+ # normalize_path("/foo") # => "/foo"
13
+ # normalize_path("/foo/") # => "/foo"
14
+ # normalize_path("foo") # => "/foo"
15
+ # normalize_path("") # => "/"
16
+ # normalize_path("/%ab") # => "/%AB"
17
+ def self.normalize_path(path)
18
+ path ||= ""
19
+ encoding = path.encoding
20
+ path = "/#{path}".dup
21
+ path.squeeze!("/".freeze)
22
+ path.sub!(%r{/+\Z}, "".freeze)
23
+ path.gsub!(/(%[a-f0-9]{2})/) { $1.upcase }
24
+ path = "/".dup if path == "".freeze
25
+ path.force_encoding(encoding)
26
+ path
27
+ end
28
+
29
+ # URI path and fragment escaping
30
+ # https://tools.ietf.org/html/rfc3986
31
+ class UriEncoder # :nodoc:
32
+ ENCODE = "%%%02X".freeze
33
+ US_ASCII = Encoding::US_ASCII
34
+ UTF_8 = Encoding::UTF_8
35
+ EMPTY = "".dup.force_encoding(US_ASCII).freeze
36
+ DEC2HEX = (0..255).to_a.map { |i| ENCODE % i }.map { |s| s.force_encoding(US_ASCII) }
37
+
38
+ ALPHA = "a-zA-Z".freeze
39
+ DIGIT = "0-9".freeze
40
+ UNRESERVED = "#{ALPHA}#{DIGIT}\\-\\._~".freeze
41
+ SUB_DELIMS = "!\\$&'\\(\\)\\*\\+,;=".freeze
42
+
43
+ ESCAPED = /%[a-zA-Z0-9]{2}/.freeze
44
+
45
+ FRAGMENT = /[^#{UNRESERVED}#{SUB_DELIMS}:@\/\?]/.freeze
46
+ SEGMENT = /[^#{UNRESERVED}#{SUB_DELIMS}:@]/.freeze
47
+ PATH = /[^#{UNRESERVED}#{SUB_DELIMS}:@\/]/.freeze
48
+
49
+ def escape_fragment(fragment)
50
+ escape(fragment, FRAGMENT)
51
+ end
52
+
53
+ def escape_path(path)
54
+ escape(path, PATH)
55
+ end
56
+
57
+ def escape_segment(segment)
58
+ escape(segment, SEGMENT)
59
+ end
60
+
61
+ def unescape_uri(uri)
62
+ encoding = uri.encoding == US_ASCII ? UTF_8 : uri.encoding
63
+ uri.gsub(ESCAPED) { |match| [match[1, 2].hex].pack("C") }.force_encoding(encoding)
64
+ end
65
+
66
+ private
67
+ def escape(component, pattern)
68
+ component.gsub(pattern) { |unsafe| percent_encode(unsafe) }.force_encoding(US_ASCII)
69
+ end
70
+
71
+ def percent_encode(unsafe)
72
+ safe = EMPTY.dup
73
+ unsafe.each_byte { |b| safe << DEC2HEX[b] }
74
+ safe
75
+ end
76
+ end
77
+
78
+ ENCODER = UriEncoder.new
79
+
80
+ def self.escape_path(path)
81
+ ENCODER.escape_path(path.to_s)
82
+ end
83
+
84
+ def self.escape_segment(segment)
85
+ ENCODER.escape_segment(segment.to_s)
86
+ end
87
+
88
+ def self.escape_fragment(fragment)
89
+ ENCODER.escape_fragment(fragment.to_s)
90
+ end
91
+
92
+ # Replaces any escaped sequences with their unescaped representations.
93
+ #
94
+ # uri = "/topics?title=Ruby%20on%20Rails"
95
+ # unescape_uri(uri) #=> "/topics?title=Ruby on Rails"
96
+ def self.unescape_uri(uri)
97
+ ENCODER.unescape_uri(uri)
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,156 @@
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"
6
+
7
+ before = $-w
8
+ $-w = false
9
+ require "action_dispatch/journey/parser"
10
+ $-w = before
11
+
12
+ require "action_dispatch/journey/route"
13
+ require "action_dispatch/journey/path/pattern"
14
+
15
+ module ActionDispatch
16
+ module Journey # :nodoc:
17
+ class Router # :nodoc:
18
+ class RoutingError < ::StandardError # :nodoc:
19
+ end
20
+
21
+ attr_accessor :routes
22
+
23
+ def initialize(routes)
24
+ @routes = routes
25
+ end
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
+
34
+ def serve(req)
35
+ find_routes(req).each do |match, parameters, route|
36
+ set_params = req.path_parameters
37
+ path_info = req.path_info
38
+ script_name = req.script_name
39
+
40
+ unless route.path.anchored
41
+ req.script_name = (script_name.to_s + match.to_s).chomp("/")
42
+ req.path_info = match.post_match
43
+ req.path_info = "/" + req.path_info unless req.path_info.start_with? "/"
44
+ end
45
+
46
+ parameters = route.defaults.merge parameters.transform_values { |val|
47
+ val.dup.force_encoding(::Encoding::UTF_8)
48
+ }
49
+
50
+ req.path_parameters = set_params.merge parameters
51
+
52
+ status, headers, body = route.app.serve(req)
53
+
54
+ if "pass" == headers["X-Cascade"]
55
+ req.script_name = script_name
56
+ req.path_info = path_info
57
+ req.path_parameters = set_params
58
+ next
59
+ end
60
+
61
+ return [status, headers, body]
62
+ end
63
+
64
+ [404, { "X-Cascade" => "pass" }, ["Not Found"]]
65
+ end
66
+
67
+ def recognize(rails_req)
68
+ find_routes(rails_req).each do |match, parameters, route|
69
+ unless route.path.anchored
70
+ rails_req.script_name = match.to_s
71
+ rails_req.path_info = match.post_match.sub(/^([^\/])/, '/\1')
72
+ end
73
+
74
+ parameters = route.defaults.merge parameters
75
+ yield(route, parameters)
76
+ end
77
+ end
78
+
79
+ def visualizer
80
+ tt = GTG::Builder.new(ast).transition_table
81
+ groups = partitioned_routes.first.map(&:ast).group_by(&:to_s)
82
+ asts = groups.values.map(&:first)
83
+ tt.visualizer(asts)
84
+ end
85
+
86
+ private
87
+
88
+ def partitioned_routes
89
+ routes.partition { |r|
90
+ r.path.anchored && r.ast.grep(Nodes::Symbol).all? { |n| n.default_regexp? }
91
+ }
92
+ end
93
+
94
+ def ast
95
+ routes.ast
96
+ end
97
+
98
+ def simulator
99
+ routes.simulator
100
+ end
101
+
102
+ def custom_routes
103
+ routes.custom_routes
104
+ end
105
+
106
+ def filter_routes(path)
107
+ return [] unless ast
108
+ simulator.memos(path) { [] }
109
+ end
110
+
111
+ def find_routes(req)
112
+ routes = filter_routes(req.path_info).concat custom_routes.find_all { |r|
113
+ r.path.match(req.path_info)
114
+ }
115
+
116
+ routes =
117
+ if req.head?
118
+ match_head_routes(routes, req)
119
+ else
120
+ match_routes(routes, req)
121
+ end
122
+
123
+ routes.sort_by!(&:precedence)
124
+
125
+ routes.map! { |r|
126
+ match_data = r.path.match(req.path_info)
127
+ path_parameters = {}
128
+ match_data.names.zip(match_data.captures) { |name, val|
129
+ path_parameters[name.to_sym] = Utils.unescape_uri(val) if val
130
+ }
131
+ [match_data, path_parameters, r]
132
+ }
133
+ end
134
+
135
+ def match_head_routes(routes, req)
136
+ verb_specific_routes = routes.select(&:requires_matching_verb?)
137
+ head_routes = match_routes(verb_specific_routes, req)
138
+
139
+ if head_routes.empty?
140
+ begin
141
+ req.request_method = "GET"
142
+ match_routes(routes, req)
143
+ ensure
144
+ req.request_method = "HEAD"
145
+ end
146
+ else
147
+ head_routes
148
+ end
149
+ end
150
+
151
+ def match_routes(routes, req)
152
+ routes.select { |r| r.matches?(req) }
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ module Journey # :nodoc:
5
+ # The Routing table. Contains all routes for a system. Routes can be
6
+ # added to the table by calling Routes#add_route.
7
+ class Routes # :nodoc:
8
+ include Enumerable
9
+
10
+ attr_reader :routes, :custom_routes, :anchored_routes
11
+
12
+ def initialize
13
+ @routes = []
14
+ @ast = nil
15
+ @anchored_routes = []
16
+ @custom_routes = []
17
+ @simulator = nil
18
+ end
19
+
20
+ def empty?
21
+ routes.empty?
22
+ end
23
+
24
+ def length
25
+ routes.length
26
+ end
27
+ alias :size :length
28
+
29
+ def last
30
+ routes.last
31
+ end
32
+
33
+ def each(&block)
34
+ routes.each(&block)
35
+ end
36
+
37
+ def clear
38
+ routes.clear
39
+ anchored_routes.clear
40
+ custom_routes.clear
41
+ end
42
+
43
+ def partition_route(route)
44
+ if route.path.anchored && route.ast.grep(Nodes::Symbol).all?(&:default_regexp?)
45
+ anchored_routes << route
46
+ else
47
+ custom_routes << route
48
+ end
49
+ end
50
+
51
+ def ast
52
+ @ast ||= begin
53
+ asts = anchored_routes.map(&:ast)
54
+ Nodes::Or.new(asts)
55
+ end
56
+ end
57
+
58
+ def simulator
59
+ return if ast.nil?
60
+ @simulator ||= begin
61
+ gtg = GTG::Builder.new(ast).transition_table
62
+ GTG::Simulator.new(gtg)
63
+ end
64
+ end
65
+
66
+ def add_route(name, mapping)
67
+ route = mapping.make_route name, routes.length
68
+ routes << route
69
+ partition_route(route)
70
+ clear_cache!
71
+ route
72
+ end
73
+
74
+ private
75
+
76
+ def clear_cache!
77
+ @ast = nil
78
+ @simulator = nil
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "strscan"
4
+
5
+ module ActionDispatch
6
+ module Journey # :nodoc:
7
+ class Scanner # :nodoc:
8
+ def initialize
9
+ @ss = nil
10
+ end
11
+
12
+ def scan_setup(str)
13
+ @ss = StringScanner.new(str)
14
+ end
15
+
16
+ def eos?
17
+ @ss.eos?
18
+ end
19
+
20
+ def pos
21
+ @ss.pos
22
+ end
23
+
24
+ def pre_match
25
+ @ss.pre_match
26
+ end
27
+
28
+ def next_token
29
+ return if @ss.eos?
30
+
31
+ until token = scan || @ss.eos?; end
32
+ token
33
+ end
34
+
35
+ private
36
+
37
+ def scan
38
+ case
39
+ # /
40
+ when @ss.skip(/\//)
41
+ [:SLASH, "/"]
42
+ when @ss.skip(/\(/)
43
+ [:LPAREN, "("]
44
+ when @ss.skip(/\)/)
45
+ [:RPAREN, ")"]
46
+ when @ss.skip(/\|/)
47
+ [:OR, "|"]
48
+ when @ss.skip(/\./)
49
+ [:DOT, "."]
50
+ when text = @ss.scan(/:\w+/)
51
+ [:SYMBOL, text]
52
+ when text = @ss.scan(/\*\w+/)
53
+ [:STAR, text]
54
+ when text = @ss.scan(/(?:[\w%\-~!$&'*+,;=@]|\\[:()])+/)
55
+ text.tr! "\\", ""
56
+ [:LITERAL, text]
57
+ # any char
58
+ when text = @ss.scan(/./)
59
+ [:LITERAL, text]
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end