actionpack 4.0.1 → 4.2.11.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (241) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +402 -1173
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +7 -7
  5. data/lib/abstract_controller/base.rb +39 -7
  6. data/lib/abstract_controller/callbacks.rb +32 -53
  7. data/lib/abstract_controller/collector.rb +11 -1
  8. data/lib/abstract_controller/helpers.rb +26 -16
  9. data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
  10. data/lib/abstract_controller/rendering.rb +57 -127
  11. data/lib/abstract_controller/url_for.rb +1 -1
  12. data/lib/abstract_controller.rb +1 -2
  13. data/lib/action_controller/base.rb +19 -10
  14. data/lib/action_controller/caching/fragments.rb +7 -1
  15. data/lib/action_controller/caching.rb +2 -12
  16. data/lib/action_controller/log_subscriber.rb +29 -20
  17. data/lib/action_controller/metal/conditional_get.rb +37 -12
  18. data/lib/action_controller/metal/data_streaming.rb +1 -1
  19. data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
  20. data/lib/action_controller/metal/exceptions.rb +1 -1
  21. data/lib/action_controller/metal/flash.rb +17 -0
  22. data/lib/action_controller/metal/force_ssl.rb +2 -2
  23. data/lib/action_controller/metal/head.rb +8 -6
  24. data/lib/action_controller/metal/helpers.rb +6 -2
  25. data/lib/action_controller/metal/http_authentication.rb +45 -23
  26. data/lib/action_controller/metal/instrumentation.rb +9 -6
  27. data/lib/action_controller/metal/live.rb +173 -20
  28. data/lib/action_controller/metal/mime_responds.rb +127 -232
  29. data/lib/action_controller/metal/params_wrapper.rb +16 -9
  30. data/lib/action_controller/metal/rack_delegation.rb +1 -1
  31. data/lib/action_controller/metal/redirecting.rb +34 -26
  32. data/lib/action_controller/metal/renderers.rb +39 -12
  33. data/lib/action_controller/metal/rendering.rb +41 -14
  34. data/lib/action_controller/metal/request_forgery_protection.rb +147 -19
  35. data/lib/action_controller/metal/streaming.rb +19 -21
  36. data/lib/action_controller/metal/strong_parameters.rb +166 -22
  37. data/lib/action_controller/metal/testing.rb +0 -1
  38. data/lib/action_controller/metal/url_for.rb +11 -12
  39. data/lib/action_controller/metal.rb +14 -8
  40. data/lib/action_controller/model_naming.rb +1 -1
  41. data/lib/action_controller/railtie.rb +5 -1
  42. data/lib/action_controller/test_case.rb +160 -94
  43. data/lib/action_controller.rb +2 -18
  44. data/lib/action_dispatch/http/cache.rb +5 -4
  45. data/lib/action_dispatch/http/filter_parameters.rb +2 -2
  46. data/lib/action_dispatch/http/filter_redirect.rb +5 -4
  47. data/lib/action_dispatch/http/headers.rb +46 -10
  48. data/lib/action_dispatch/http/mime_negotiation.rb +31 -4
  49. data/lib/action_dispatch/http/mime_type.rb +25 -26
  50. data/lib/action_dispatch/http/mime_types.rb +1 -0
  51. data/lib/action_dispatch/http/parameter_filter.rb +1 -1
  52. data/lib/action_dispatch/http/parameters.rb +25 -41
  53. data/lib/action_dispatch/http/request.rb +49 -32
  54. data/lib/action_dispatch/http/response.rb +127 -25
  55. data/lib/action_dispatch/http/upload.rb +9 -21
  56. data/lib/action_dispatch/http/url.rb +97 -70
  57. data/lib/action_dispatch/journey/formatter.rb +35 -19
  58. data/lib/action_dispatch/journey/gtg/builder.rb +3 -3
  59. data/lib/action_dispatch/journey/gtg/simulator.rb +10 -7
  60. data/lib/action_dispatch/journey/gtg/transition_table.rb +23 -33
  61. data/lib/action_dispatch/journey/nfa/dot.rb +2 -2
  62. data/lib/action_dispatch/journey/nfa/simulator.rb +1 -1
  63. data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -5
  64. data/lib/action_dispatch/journey/nodes/node.rb +4 -0
  65. data/lib/action_dispatch/journey/parser.rb +51 -59
  66. data/lib/action_dispatch/journey/parser.y +12 -10
  67. data/lib/action_dispatch/journey/path/pattern.rb +16 -19
  68. data/lib/action_dispatch/journey/route.rb +8 -19
  69. data/lib/action_dispatch/journey/router/strexp.rb +9 -6
  70. data/lib/action_dispatch/journey/router/utils.rb +54 -18
  71. data/lib/action_dispatch/journey/router.rb +53 -75
  72. data/lib/action_dispatch/journey/routes.rb +4 -0
  73. data/lib/action_dispatch/journey/scanner.rb +5 -5
  74. data/lib/action_dispatch/journey/visitors.rb +81 -60
  75. data/lib/action_dispatch/journey/visualizer/fsm.css +0 -4
  76. data/lib/action_dispatch/journey/visualizer/index.html.erb +2 -2
  77. data/lib/action_dispatch/middleware/callbacks.rb +7 -7
  78. data/lib/action_dispatch/middleware/cookies.rb +119 -43
  79. data/lib/action_dispatch/middleware/debug_exceptions.rb +32 -13
  80. data/lib/action_dispatch/middleware/exception_wrapper.rb +60 -20
  81. data/lib/action_dispatch/middleware/flash.rb +37 -24
  82. data/lib/action_dispatch/middleware/params_parser.rb +2 -2
  83. data/lib/action_dispatch/middleware/public_exceptions.rb +12 -3
  84. data/lib/action_dispatch/middleware/reloader.rb +11 -2
  85. data/lib/action_dispatch/middleware/remote_ip.rb +40 -54
  86. data/lib/action_dispatch/middleware/request_id.rb +1 -1
  87. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  88. data/lib/action_dispatch/middleware/session/cookie_store.rb +8 -7
  89. data/lib/action_dispatch/middleware/show_exceptions.rb +6 -2
  90. data/lib/action_dispatch/middleware/ssl.rb +10 -7
  91. data/lib/action_dispatch/middleware/static.rb +79 -23
  92. data/lib/action_dispatch/middleware/templates/rescues/{_request_and_response.erb → _request_and_response.html.erb} +0 -0
  93. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  94. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +21 -19
  95. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  96. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  97. data/lib/action_dispatch/middleware/templates/rescues/{diagnostics.erb → diagnostics.html.erb} +1 -1
  98. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  99. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +6 -0
  100. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  101. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  102. data/lib/action_dispatch/middleware/templates/rescues/{routing_error.erb → routing_error.html.erb} +3 -1
  103. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  104. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  105. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  106. data/lib/action_dispatch/middleware/templates/rescues/{unknown_action.erb → unknown_action.html.erb} +1 -1
  107. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  108. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +120 -64
  109. data/lib/action_dispatch/railtie.rb +5 -2
  110. data/lib/action_dispatch/request/session.rb +12 -0
  111. data/lib/action_dispatch/request/utils.rb +35 -0
  112. data/lib/action_dispatch/routing/endpoint.rb +10 -0
  113. data/lib/action_dispatch/routing/inspector.rb +11 -17
  114. data/lib/action_dispatch/routing/mapper.rb +519 -312
  115. data/lib/action_dispatch/routing/polymorphic_routes.rb +204 -79
  116. data/lib/action_dispatch/routing/redirection.rb +51 -26
  117. data/lib/action_dispatch/routing/route_set.rb +331 -206
  118. data/lib/action_dispatch/routing/routes_proxy.rb +5 -4
  119. data/lib/action_dispatch/routing/url_for.rb +19 -5
  120. data/lib/action_dispatch/routing.rb +9 -6
  121. data/lib/action_dispatch/testing/assertions/dom.rb +2 -26
  122. data/lib/action_dispatch/testing/assertions/response.rb +9 -15
  123. data/lib/action_dispatch/testing/assertions/routing.rb +22 -22
  124. data/lib/action_dispatch/testing/assertions/selector.rb +2 -429
  125. data/lib/action_dispatch/testing/assertions/tag.rb +2 -134
  126. data/lib/action_dispatch/testing/assertions.rb +11 -7
  127. data/lib/action_dispatch/testing/integration.rb +31 -29
  128. data/lib/action_dispatch/testing/test_request.rb +1 -1
  129. data/lib/action_dispatch/testing/test_response.rb +1 -5
  130. data/lib/action_dispatch.rb +5 -8
  131. data/lib/action_pack/gem_version.rb +15 -0
  132. data/lib/action_pack/version.rb +4 -7
  133. data/lib/action_pack.rb +1 -1
  134. metadata +77 -159
  135. data/lib/abstract_controller/layouts.rb +0 -423
  136. data/lib/abstract_controller/view_paths.rb +0 -96
  137. data/lib/action_controller/deprecated/integration_test.rb +0 -5
  138. data/lib/action_controller/deprecated.rb +0 -7
  139. data/lib/action_controller/metal/responder.rb +0 -287
  140. data/lib/action_controller/record_identifier.rb +0 -31
  141. data/lib/action_controller/vendor/html-scanner.rb +0 -5
  142. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -24
  143. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -7
  144. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -43
  145. data/lib/action_view/base.rb +0 -201
  146. data/lib/action_view/buffers.rb +0 -49
  147. data/lib/action_view/context.rb +0 -36
  148. data/lib/action_view/dependency_tracker.rb +0 -93
  149. data/lib/action_view/digestor.rb +0 -113
  150. data/lib/action_view/flows.rb +0 -76
  151. data/lib/action_view/helpers/active_model_helper.rb +0 -49
  152. data/lib/action_view/helpers/asset_tag_helper.rb +0 -320
  153. data/lib/action_view/helpers/asset_url_helper.rb +0 -355
  154. data/lib/action_view/helpers/atom_feed_helper.rb +0 -203
  155. data/lib/action_view/helpers/cache_helper.rb +0 -196
  156. data/lib/action_view/helpers/capture_helper.rb +0 -216
  157. data/lib/action_view/helpers/controller_helper.rb +0 -25
  158. data/lib/action_view/helpers/csrf_helper.rb +0 -30
  159. data/lib/action_view/helpers/date_helper.rb +0 -1083
  160. data/lib/action_view/helpers/debug_helper.rb +0 -39
  161. data/lib/action_view/helpers/form_helper.rb +0 -1880
  162. data/lib/action_view/helpers/form_options_helper.rb +0 -838
  163. data/lib/action_view/helpers/form_tag_helper.rb +0 -785
  164. data/lib/action_view/helpers/javascript_helper.rb +0 -117
  165. data/lib/action_view/helpers/number_helper.rb +0 -441
  166. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  167. data/lib/action_view/helpers/record_tag_helper.rb +0 -106
  168. data/lib/action_view/helpers/rendering_helper.rb +0 -90
  169. data/lib/action_view/helpers/sanitize_helper.rb +0 -256
  170. data/lib/action_view/helpers/tag_helper.rb +0 -173
  171. data/lib/action_view/helpers/tags/base.rb +0 -148
  172. data/lib/action_view/helpers/tags/check_box.rb +0 -64
  173. data/lib/action_view/helpers/tags/checkable.rb +0 -16
  174. data/lib/action_view/helpers/tags/collection_check_boxes.rb +0 -44
  175. data/lib/action_view/helpers/tags/collection_helpers.rb +0 -84
  176. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +0 -36
  177. data/lib/action_view/helpers/tags/collection_select.rb +0 -28
  178. data/lib/action_view/helpers/tags/color_field.rb +0 -25
  179. data/lib/action_view/helpers/tags/date_field.rb +0 -13
  180. data/lib/action_view/helpers/tags/date_select.rb +0 -72
  181. data/lib/action_view/helpers/tags/datetime_field.rb +0 -22
  182. data/lib/action_view/helpers/tags/datetime_local_field.rb +0 -19
  183. data/lib/action_view/helpers/tags/datetime_select.rb +0 -8
  184. data/lib/action_view/helpers/tags/email_field.rb +0 -8
  185. data/lib/action_view/helpers/tags/file_field.rb +0 -8
  186. data/lib/action_view/helpers/tags/grouped_collection_select.rb +0 -29
  187. data/lib/action_view/helpers/tags/hidden_field.rb +0 -8
  188. data/lib/action_view/helpers/tags/label.rb +0 -66
  189. data/lib/action_view/helpers/tags/month_field.rb +0 -13
  190. data/lib/action_view/helpers/tags/number_field.rb +0 -18
  191. data/lib/action_view/helpers/tags/password_field.rb +0 -12
  192. data/lib/action_view/helpers/tags/radio_button.rb +0 -31
  193. data/lib/action_view/helpers/tags/range_field.rb +0 -8
  194. data/lib/action_view/helpers/tags/search_field.rb +0 -24
  195. data/lib/action_view/helpers/tags/select.rb +0 -40
  196. data/lib/action_view/helpers/tags/tel_field.rb +0 -8
  197. data/lib/action_view/helpers/tags/text_area.rb +0 -18
  198. data/lib/action_view/helpers/tags/text_field.rb +0 -29
  199. data/lib/action_view/helpers/tags/time_field.rb +0 -13
  200. data/lib/action_view/helpers/tags/time_select.rb +0 -8
  201. data/lib/action_view/helpers/tags/time_zone_select.rb +0 -20
  202. data/lib/action_view/helpers/tags/url_field.rb +0 -8
  203. data/lib/action_view/helpers/tags/week_field.rb +0 -13
  204. data/lib/action_view/helpers/tags.rb +0 -39
  205. data/lib/action_view/helpers/text_helper.rb +0 -443
  206. data/lib/action_view/helpers/translation_helper.rb +0 -107
  207. data/lib/action_view/helpers/url_helper.rb +0 -635
  208. data/lib/action_view/helpers.rb +0 -58
  209. data/lib/action_view/locale/en.yml +0 -56
  210. data/lib/action_view/log_subscriber.rb +0 -30
  211. data/lib/action_view/lookup_context.rb +0 -241
  212. data/lib/action_view/model_naming.rb +0 -12
  213. data/lib/action_view/path_set.rb +0 -77
  214. data/lib/action_view/railtie.rb +0 -43
  215. data/lib/action_view/record_identifier.rb +0 -84
  216. data/lib/action_view/renderer/abstract_renderer.rb +0 -47
  217. data/lib/action_view/renderer/partial_renderer.rb +0 -492
  218. data/lib/action_view/renderer/renderer.rb +0 -50
  219. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -103
  220. data/lib/action_view/renderer/template_renderer.rb +0 -96
  221. data/lib/action_view/routing_url_for.rb +0 -107
  222. data/lib/action_view/tasks/dependencies.rake +0 -17
  223. data/lib/action_view/template/error.rb +0 -138
  224. data/lib/action_view/template/handlers/builder.rb +0 -26
  225. data/lib/action_view/template/handlers/erb.rb +0 -146
  226. data/lib/action_view/template/handlers/raw.rb +0 -11
  227. data/lib/action_view/template/handlers.rb +0 -53
  228. data/lib/action_view/template/resolver.rb +0 -326
  229. data/lib/action_view/template/text.rb +0 -34
  230. data/lib/action_view/template/types.rb +0 -57
  231. data/lib/action_view/template.rb +0 -339
  232. data/lib/action_view/test_case.rb +0 -270
  233. data/lib/action_view/testing/resolvers.rb +0 -50
  234. data/lib/action_view/vendor/html-scanner/html/document.rb +0 -68
  235. data/lib/action_view/vendor/html-scanner/html/node.rb +0 -532
  236. data/lib/action_view/vendor/html-scanner/html/sanitizer.rb +0 -188
  237. data/lib/action_view/vendor/html-scanner/html/selector.rb +0 -830
  238. data/lib/action_view/vendor/html-scanner/html/tokenizer.rb +0 -107
  239. data/lib/action_view/vendor/html-scanner/html/version.rb +0 -11
  240. data/lib/action_view/vendor/html-scanner.rb +0 -20
  241. data/lib/action_view.rb +0 -93
@@ -1,5 +1,3 @@
1
- require 'uri'
2
-
3
1
  module ActionDispatch
4
2
  module Journey # :nodoc:
5
3
  class Router # :nodoc:
@@ -15,7 +13,7 @@ module ActionDispatch
15
13
  # normalize_path("") # => "/"
16
14
  # normalize_path("/%ab") # => "/%AB"
17
15
  def self.normalize_path(path)
18
- path = "/#{path}"
16
+ path = "/#{path}".force_encoding(Encoding::UTF_8)
19
17
  path.squeeze!('/')
20
18
  path.sub!(%r{/+\Z}, '')
21
19
  path.gsub!(/(%[a-f0-9]{2})/) { $1.upcase }
@@ -25,31 +23,69 @@ module ActionDispatch
25
23
 
26
24
  # URI path and fragment escaping
27
25
  # http://tools.ietf.org/html/rfc3986
28
- module UriEscape # :nodoc:
29
- # Symbol captures can generate multiple path segments, so include /.
30
- reserved_segment = '/'
31
- reserved_fragment = '/?'
32
- reserved_pchar = ':@&=+$,;%'
33
-
34
- safe_pchar = "#{URI::REGEXP::PATTERN::UNRESERVED}#{reserved_pchar}"
35
- safe_segment = "#{safe_pchar}#{reserved_segment}"
36
- safe_fragment = "#{safe_pchar}#{reserved_fragment}"
37
- UNSAFE_SEGMENT = Regexp.new("[^#{safe_segment}]", false).freeze
38
- UNSAFE_FRAGMENT = Regexp.new("[^#{safe_fragment}]", false).freeze
26
+ class UriEncoder # :nodoc:
27
+ ENCODE = "%%%02X".freeze
28
+ US_ASCII = Encoding::US_ASCII
29
+ UTF_8 = Encoding::UTF_8
30
+ EMPTY = "".force_encoding(US_ASCII).freeze
31
+ DEC2HEX = (0..255).to_a.map{ |i| ENCODE % i }.map{ |s| s.force_encoding(US_ASCII) }
32
+
33
+ ALPHA = "a-zA-Z".freeze
34
+ DIGIT = "0-9".freeze
35
+ UNRESERVED = "#{ALPHA}#{DIGIT}\\-\\._~".freeze
36
+ SUB_DELIMS = "!\\$&'\\(\\)\\*\\+,;=".freeze
37
+
38
+ ESCAPED = /%[a-zA-Z0-9]{2}/.freeze
39
+
40
+ FRAGMENT = /[^#{UNRESERVED}#{SUB_DELIMS}:@\/\?]/.freeze
41
+ SEGMENT = /[^#{UNRESERVED}#{SUB_DELIMS}:@]/.freeze
42
+ PATH = /[^#{UNRESERVED}#{SUB_DELIMS}:@\/]/.freeze
43
+
44
+ def escape_fragment(fragment)
45
+ escape(fragment, FRAGMENT)
46
+ end
47
+
48
+ def escape_path(path)
49
+ escape(path, PATH)
50
+ end
51
+
52
+ def escape_segment(segment)
53
+ escape(segment, SEGMENT)
54
+ end
55
+
56
+ def unescape_uri(uri)
57
+ encoding = uri.encoding == US_ASCII ? UTF_8 : uri.encoding
58
+ uri.gsub(ESCAPED) { [$&[1, 2].hex].pack('C') }.force_encoding(encoding)
59
+ end
60
+
61
+ protected
62
+ def escape(component, pattern)
63
+ component.gsub(pattern){ |unsafe| percent_encode(unsafe) }.force_encoding(US_ASCII)
64
+ end
65
+
66
+ def percent_encode(unsafe)
67
+ safe = EMPTY.dup
68
+ unsafe.each_byte { |b| safe << DEC2HEX[b] }
69
+ safe
70
+ end
39
71
  end
40
72
 
41
- Parser = URI.const_defined?(:Parser) ? URI::Parser.new : URI
73
+ ENCODER = UriEncoder.new
42
74
 
43
75
  def self.escape_path(path)
44
- Parser.escape(path.to_s, UriEscape::UNSAFE_SEGMENT)
76
+ ENCODER.escape_path(path.to_s)
77
+ end
78
+
79
+ def self.escape_segment(segment)
80
+ ENCODER.escape_segment(segment.to_s)
45
81
  end
46
82
 
47
83
  def self.escape_fragment(fragment)
48
- Parser.escape(fragment.to_s, UriEscape::UNSAFE_FRAGMENT)
84
+ ENCODER.escape_fragment(fragment.to_s)
49
85
  end
50
86
 
51
87
  def self.unescape_uri(uri)
52
- Parser.unescape(uri)
88
+ ENCODER.unescape_uri(uri)
53
89
  end
54
90
  end
55
91
  end
@@ -20,60 +20,32 @@ module ActionDispatch
20
20
  # :nodoc:
21
21
  VERSION = '2.0.0'
22
22
 
23
- class NullReq # :nodoc:
24
- attr_reader :env
25
- def initialize(env)
26
- @env = env
27
- end
28
-
29
- def request_method
30
- env['REQUEST_METHOD']
31
- end
32
-
33
- def path_info
34
- env['PATH_INFO']
35
- end
36
-
37
- def ip
38
- env['REMOTE_ADDR']
39
- end
40
-
41
- def [](k)
42
- env[k]
43
- end
44
- end
45
-
46
- attr_reader :request_class, :formatter
47
23
  attr_accessor :routes
48
24
 
49
- def initialize(routes, options)
50
- @options = options
51
- @params_key = options[:parameters_key]
52
- @request_class = options[:request_class] || NullReq
53
- @routes = routes
25
+ def initialize(routes)
26
+ @routes = routes
54
27
  end
55
28
 
56
- def call(env)
57
- env['PATH_INFO'] = Utils.normalize_path(env['PATH_INFO'])
58
-
59
- find_routes(env).each do |match, parameters, route|
60
- script_name, path_info, set_params = env.values_at('SCRIPT_NAME',
61
- 'PATH_INFO',
62
- @params_key)
29
+ def serve(req)
30
+ find_routes(req).each do |match, parameters, route|
31
+ set_params = req.path_parameters
32
+ path_info = req.path_info
33
+ script_name = req.script_name
63
34
 
64
35
  unless route.path.anchored
65
- env['SCRIPT_NAME'] = (script_name.to_s + match.to_s).chomp('/')
66
- env['PATH_INFO'] = match.post_match
36
+ req.script_name = (script_name.to_s + match.to_s).chomp('/')
37
+ req.path_info = match.post_match
38
+ req.path_info = "/" + req.path_info unless req.path_info.start_with? "/"
67
39
  end
68
40
 
69
- env[@params_key] = (set_params || {}).merge parameters
41
+ req.path_parameters = set_params.merge parameters
70
42
 
71
- status, headers, body = route.app.call(env)
43
+ status, headers, body = route.app.serve(req)
72
44
 
73
45
  if 'pass' == headers['X-Cascade']
74
- env['SCRIPT_NAME'] = script_name
75
- env['PATH_INFO'] = path_info
76
- env[@params_key] = set_params
46
+ req.script_name = script_name
47
+ req.path_info = path_info
48
+ req.path_parameters = set_params
77
49
  next
78
50
  end
79
51
 
@@ -83,14 +55,14 @@ module ActionDispatch
83
55
  return [404, {'X-Cascade' => 'pass'}, ['Not Found']]
84
56
  end
85
57
 
86
- def recognize(req)
87
- find_routes(req.env).each do |match, parameters, route|
58
+ def recognize(rails_req)
59
+ find_routes(rails_req).each do |match, parameters, route|
88
60
  unless route.path.anchored
89
- req.env['SCRIPT_NAME'] = match.to_s
90
- req.env['PATH_INFO'] = match.post_match.sub(/^([^\/])/, '/\1')
61
+ rails_req.script_name = match.to_s
62
+ rails_req.path_info = match.post_match.sub(/^([^\/])/, '/\1')
91
63
  end
92
64
 
93
- yield(route, nil, parameters)
65
+ yield(route, parameters)
94
66
  end
95
67
  end
96
68
 
@@ -121,45 +93,51 @@ module ActionDispatch
121
93
 
122
94
  def filter_routes(path)
123
95
  return [] unless ast
124
- data = simulator.match(path)
125
- data ? data.memos : []
96
+ simulator.memos(path) { [] }
126
97
  end
127
98
 
128
- def find_routes env
129
- req = request_class.new(env)
130
-
99
+ def find_routes req
131
100
  routes = filter_routes(req.path_info).concat custom_routes.find_all { |r|
132
101
  r.path.match(req.path_info)
133
102
  }
134
- routes.concat get_routes_as_head(routes)
135
103
 
136
- routes.sort_by!(&:precedence).select! { |r| r.matches?(req) }
104
+ routes =
105
+ if req.request_method == "HEAD"
106
+ match_head_routes(routes, req)
107
+ else
108
+ match_routes(routes, req)
109
+ end
110
+
111
+ routes.sort_by!(&:precedence)
137
112
 
138
113
  routes.map! { |r|
139
114
  match_data = r.path.match(req.path_info)
140
- match_names = match_data.names.map { |n| n.to_sym }
141
- match_values = match_data.captures.map { |v| v && Utils.unescape_uri(v) }
142
- info = Hash[match_names.zip(match_values).find_all { |_, y| y }]
143
-
144
- [match_data, r.defaults.merge(info), r]
115
+ path_parameters = r.defaults.dup
116
+ match_data.names.zip(match_data.captures) { |name,val|
117
+ path_parameters[name.to_sym] = Utils.unescape_uri(val) if val
118
+ }
119
+ [match_data, path_parameters, r]
145
120
  }
146
121
  end
147
122
 
148
- def get_routes_as_head(routes)
149
- precedence = (routes.map(&:precedence).max || 0) + 1
150
- routes = routes.select { |r|
151
- r.verb === "GET" && !(r.verb === "HEAD")
152
- }.map! { |r|
153
- Route.new(r.name,
154
- r.app,
155
- r.path,
156
- r.conditions.merge(request_method: "HEAD"),
157
- r.defaults).tap do |route|
158
- route.precedence = r.precedence + precedence
159
- end
160
- }
161
- routes.flatten!
162
- routes
123
+ def match_head_routes(routes, req)
124
+ verb_specific_routes = routes.reject { |route| route.verb == // }
125
+ head_routes = match_routes(verb_specific_routes, req)
126
+
127
+ if head_routes.empty?
128
+ begin
129
+ req.request_method = "GET"
130
+ match_routes(routes, req)
131
+ ensure
132
+ req.request_method = "HEAD"
133
+ end
134
+ else
135
+ head_routes
136
+ end
137
+ end
138
+
139
+ def match_routes(routes, req)
140
+ routes.select { |r| r.matches?(req) }
163
141
  end
164
142
  end
165
143
  end
@@ -15,6 +15,10 @@ module ActionDispatch
15
15
  @simulator = nil
16
16
  end
17
17
 
18
+ def empty?
19
+ routes.empty?
20
+ end
21
+
18
22
  def length
19
23
  routes.length
20
24
  end
@@ -39,18 +39,18 @@ module ActionDispatch
39
39
  [:SLASH, text]
40
40
  when text = @ss.scan(/\*\w+/)
41
41
  [:STAR, text]
42
- when text = @ss.scan(/\(/)
42
+ when text = @ss.scan(/(?<!\\)\(/)
43
43
  [:LPAREN, text]
44
- when text = @ss.scan(/\)/)
44
+ when text = @ss.scan(/(?<!\\)\)/)
45
45
  [:RPAREN, text]
46
46
  when text = @ss.scan(/\|/)
47
47
  [:OR, text]
48
48
  when text = @ss.scan(/\./)
49
49
  [:DOT, text]
50
- when text = @ss.scan(/:\w+/)
50
+ when text = @ss.scan(/(?<!\\):\w+/)
51
51
  [:SYMBOL, text]
52
- when text = @ss.scan(/[\w%\-~]+/)
53
- [:LITERAL, text]
52
+ when text = @ss.scan(/(?:[\w%\-~!$&'*+,;=@]|\\:|\\\(|\\\))+/)
53
+ [:LITERAL, text.tr('\\', '')]
54
54
  # any char
55
55
  when text = @ss.scan(/./)
56
56
  [:LITERAL, text]
@@ -1,14 +1,57 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'thread_safe'
4
-
5
3
  module ActionDispatch
6
4
  module Journey # :nodoc:
5
+ class Format
6
+ ESCAPE_PATH = ->(value) { Router::Utils.escape_path(value) }
7
+ ESCAPE_SEGMENT = ->(value) { Router::Utils.escape_segment(value) }
8
+
9
+ class Parameter < Struct.new(:name, :escaper)
10
+ def escape(value); escaper.call value; end
11
+ end
12
+
13
+ def self.required_path(symbol)
14
+ Parameter.new symbol, ESCAPE_PATH
15
+ end
16
+
17
+ def self.required_segment(symbol)
18
+ Parameter.new symbol, ESCAPE_SEGMENT
19
+ end
20
+
21
+ def initialize(parts)
22
+ @parts = parts
23
+ @children = []
24
+ @parameters = []
25
+
26
+ parts.each_with_index do |object,i|
27
+ case object
28
+ when Journey::Format
29
+ @children << i
30
+ when Parameter
31
+ @parameters << i
32
+ end
33
+ end
34
+ end
35
+
36
+ def evaluate(hash)
37
+ parts = @parts.dup
38
+
39
+ @parameters.each do |index|
40
+ param = parts[index]
41
+ value = hash[param.name]
42
+ return ''.freeze unless value
43
+ parts[index] = param.escape value
44
+ end
45
+
46
+ @children.each { |index| parts[index] = parts[index].evaluate(hash) }
47
+
48
+ parts.join
49
+ end
50
+ end
51
+
7
52
  module Visitors # :nodoc:
8
53
  class Visitor # :nodoc:
9
- DISPATCH_CACHE = ThreadSafe::Cache.new { |h,k|
10
- h[k] = :"visit_#{k}"
11
- }
54
+ DISPATCH_CACHE = {}
12
55
 
13
56
  def accept(node)
14
57
  visit(node)
@@ -38,9 +81,39 @@ module ActionDispatch
38
81
  def visit_STAR(n); unary(n); end
39
82
 
40
83
  def terminal(node); end
41
- %w{ LITERAL SYMBOL SLASH DOT }.each do |t|
42
- class_eval %{ def visit_#{t}(n); terminal(n); end }, __FILE__, __LINE__
84
+ def visit_LITERAL(n); terminal(n); end
85
+ def visit_SYMBOL(n); terminal(n); end
86
+ def visit_SLASH(n); terminal(n); end
87
+ def visit_DOT(n); terminal(n); end
88
+
89
+ private_instance_methods(false).each do |pim|
90
+ next unless pim =~ /^visit_(.*)$/
91
+ DISPATCH_CACHE[$1.to_sym] = pim
92
+ end
93
+ end
94
+
95
+ class FormatBuilder < Visitor # :nodoc:
96
+ def accept(node); Journey::Format.new(super); end
97
+ def terminal(node); [node.left]; end
98
+
99
+ def binary(node)
100
+ visit(node.left) + visit(node.right)
101
+ end
102
+
103
+ def visit_GROUP(n); [Journey::Format.new(unary(n))]; end
104
+
105
+ def visit_STAR(n)
106
+ [Journey::Format.required_path(n.left.to_sym)]
107
+ end
108
+
109
+ def visit_SYMBOL(n)
110
+ symbol = n.to_sym
111
+ if symbol == :controller
112
+ [Journey::Format.required_path(symbol)]
113
+ else
114
+ [Journey::Format.required_segment(symbol)]
43
115
  end
116
+ end
44
117
  end
45
118
 
46
119
  # Loop through the requirements AST
@@ -52,8 +125,8 @@ module ActionDispatch
52
125
  end
53
126
 
54
127
  def visit(node)
55
- super
56
128
  block.call(node)
129
+ super
57
130
  end
58
131
  end
59
132
 
@@ -77,58 +150,6 @@ module ActionDispatch
77
150
  end
78
151
  end
79
152
 
80
- class OptimizedPath < String # :nodoc:
81
- private
82
-
83
- def visit_GROUP(node)
84
- ""
85
- end
86
- end
87
-
88
- # Used for formatting urls (url_for)
89
- class Formatter < Visitor # :nodoc:
90
- attr_reader :options, :consumed
91
-
92
- def initialize(options)
93
- @options = options
94
- @consumed = {}
95
- end
96
-
97
- private
98
-
99
- def visit_GROUP(node)
100
- if consumed == options
101
- nil
102
- else
103
- route = visit(node.left)
104
- route.include?("\0") ? nil : route
105
- end
106
- end
107
-
108
- def terminal(node)
109
- node.left
110
- end
111
-
112
- def binary(node)
113
- [visit(node.left), visit(node.right)].join
114
- end
115
-
116
- def nary(node)
117
- node.children.map { |c| visit(c) }.join
118
- end
119
-
120
- def visit_SYMBOL(node)
121
- key = node.to_sym
122
-
123
- if value = options[key]
124
- consumed[key] = value
125
- Router::Utils.escape_path(value)
126
- else
127
- "\0"
128
- end
129
- end
130
- end
131
-
132
153
  class Dot < Visitor # :nodoc:
133
154
  def initialize
134
155
  @nodes = []
@@ -16,10 +16,6 @@ h2 {
16
16
  font-size: 0.5em;
17
17
  }
18
18
 
19
- div#chart-2 {
20
- height: 350px;
21
- }
22
-
23
19
  .clearfix {display: inline-block; }
24
20
  .input { overflow: show;}
25
21
  .instruction { color: #666; padding: 0 30px 20px; font-size: 0.9em}
@@ -2,13 +2,13 @@
2
2
  <html>
3
3
  <head>
4
4
  <title><%= title %></title>
5
- <link rel="stylesheet" href="https://raw.github.com/gist/1706081/af944401f75ea20515a02ddb3fb43d23ecb8c662/reset.css" type="text/css">
5
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css" type="text/css">
6
6
  <style>
7
7
  <% stylesheets.each do |style| %>
8
8
  <%= style %>
9
9
  <% end %>
10
10
  </style>
11
- <script src="https://raw.github.com/gist/1706081/df464722a05c3c2bec450b7b5c8240d9c31fa52d/d3.min.js" type="text/javascript"></script>
11
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.8/d3.min.js" type="text/javascript"></script>
12
12
  </head>
13
13
  <body>
14
14
  <div id="wrapper">
@@ -1,6 +1,6 @@
1
1
 
2
2
  module ActionDispatch
3
- # Provide callbacks to be executed before and after the request dispatch.
3
+ # Provides callbacks to be executed before and after dispatching the request.
4
4
  class Callbacks
5
5
  include ActiveSupport::Callbacks
6
6
 
@@ -8,14 +8,14 @@ module ActionDispatch
8
8
 
9
9
  class << self
10
10
  delegate :to_prepare, :to_cleanup, :to => "ActionDispatch::Reloader"
11
- end
12
11
 
13
- def self.before(*args, &block)
14
- set_callback(:call, :before, *args, &block)
15
- end
12
+ def before(*args, &block)
13
+ set_callback(:call, :before, *args, &block)
14
+ end
16
15
 
17
- def self.after(*args, &block)
18
- set_callback(:call, :after, *args, &block)
16
+ def after(*args, &block)
17
+ set_callback(:call, :after, *args, &block)
18
+ end
19
19
  end
20
20
 
21
21
  def initialize(app)