actionpack 3.2.19 → 4.2.11.3

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 (244) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +412 -503
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +11 -294
  5. data/lib/abstract_controller/asset_paths.rb +2 -2
  6. data/lib/abstract_controller/base.rb +52 -18
  7. data/lib/abstract_controller/callbacks.rb +87 -89
  8. data/lib/abstract_controller/collector.rb +17 -3
  9. data/lib/abstract_controller/helpers.rb +41 -14
  10. data/lib/abstract_controller/logger.rb +1 -2
  11. data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
  12. data/lib/abstract_controller/rendering.rb +65 -118
  13. data/lib/abstract_controller/translation.rb +16 -1
  14. data/lib/abstract_controller/url_for.rb +7 -7
  15. data/lib/abstract_controller.rb +2 -10
  16. data/lib/action_controller/base.rb +61 -28
  17. data/lib/action_controller/caching/fragments.rb +30 -54
  18. data/lib/action_controller/caching.rb +38 -35
  19. data/lib/action_controller/log_subscriber.rb +35 -18
  20. data/lib/action_controller/metal/conditional_get.rb +103 -34
  21. data/lib/action_controller/metal/data_streaming.rb +20 -26
  22. data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
  23. data/lib/action_controller/metal/exceptions.rb +19 -6
  24. data/lib/action_controller/metal/flash.rb +41 -9
  25. data/lib/action_controller/metal/force_ssl.rb +70 -12
  26. data/lib/action_controller/metal/head.rb +30 -7
  27. data/lib/action_controller/metal/helpers.rb +11 -11
  28. data/lib/action_controller/metal/hide_actions.rb +0 -1
  29. data/lib/action_controller/metal/http_authentication.rb +140 -94
  30. data/lib/action_controller/metal/implicit_render.rb +1 -1
  31. data/lib/action_controller/metal/instrumentation.rb +11 -7
  32. data/lib/action_controller/metal/live.rb +328 -0
  33. data/lib/action_controller/metal/mime_responds.rb +161 -152
  34. data/lib/action_controller/metal/params_wrapper.rb +126 -81
  35. data/lib/action_controller/metal/rack_delegation.rb +10 -4
  36. data/lib/action_controller/metal/redirecting.rb +44 -41
  37. data/lib/action_controller/metal/renderers.rb +48 -19
  38. data/lib/action_controller/metal/rendering.rb +46 -11
  39. data/lib/action_controller/metal/request_forgery_protection.rb +250 -29
  40. data/lib/action_controller/metal/streaming.rb +30 -38
  41. data/lib/action_controller/metal/strong_parameters.rb +669 -0
  42. data/lib/action_controller/metal/testing.rb +12 -18
  43. data/lib/action_controller/metal/url_for.rb +31 -29
  44. data/lib/action_controller/metal.rb +31 -40
  45. data/lib/action_controller/model_naming.rb +12 -0
  46. data/lib/action_controller/railtie.rb +38 -18
  47. data/lib/action_controller/railties/helpers.rb +22 -0
  48. data/lib/action_controller/test_case.rb +359 -173
  49. data/lib/action_controller.rb +9 -16
  50. data/lib/action_dispatch/http/cache.rb +64 -11
  51. data/lib/action_dispatch/http/filter_parameters.rb +20 -10
  52. data/lib/action_dispatch/http/filter_redirect.rb +38 -0
  53. data/lib/action_dispatch/http/headers.rb +85 -17
  54. data/lib/action_dispatch/http/mime_negotiation.rb +55 -5
  55. data/lib/action_dispatch/http/mime_type.rb +167 -114
  56. data/lib/action_dispatch/http/mime_types.rb +2 -1
  57. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  58. data/lib/action_dispatch/http/parameters.rb +30 -46
  59. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  60. data/lib/action_dispatch/http/request.rb +108 -45
  61. data/lib/action_dispatch/http/response.rb +247 -48
  62. data/lib/action_dispatch/http/upload.rb +60 -29
  63. data/lib/action_dispatch/http/url.rb +135 -45
  64. data/lib/action_dispatch/journey/backwards.rb +5 -0
  65. data/lib/action_dispatch/journey/formatter.rb +166 -0
  66. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  67. data/lib/action_dispatch/journey/gtg/simulator.rb +47 -0
  68. data/lib/action_dispatch/journey/gtg/transition_table.rb +157 -0
  69. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  70. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  71. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  72. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  73. data/lib/action_dispatch/journey/nodes/node.rb +128 -0
  74. data/lib/action_dispatch/journey/parser.rb +198 -0
  75. data/lib/action_dispatch/journey/parser.y +49 -0
  76. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  77. data/lib/action_dispatch/journey/path/pattern.rb +193 -0
  78. data/lib/action_dispatch/journey/route.rb +125 -0
  79. data/lib/action_dispatch/journey/router/strexp.rb +27 -0
  80. data/lib/action_dispatch/journey/router/utils.rb +93 -0
  81. data/lib/action_dispatch/journey/router.rb +144 -0
  82. data/lib/action_dispatch/journey/routes.rb +80 -0
  83. data/lib/action_dispatch/journey/scanner.rb +61 -0
  84. data/lib/action_dispatch/journey/visitors.rb +221 -0
  85. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  86. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  87. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  88. data/lib/action_dispatch/journey.rb +5 -0
  89. data/lib/action_dispatch/middleware/callbacks.rb +16 -11
  90. data/lib/action_dispatch/middleware/cookies.rb +346 -125
  91. data/lib/action_dispatch/middleware/debug_exceptions.rb +52 -24
  92. data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -9
  93. data/lib/action_dispatch/middleware/flash.rb +85 -72
  94. data/lib/action_dispatch/middleware/params_parser.rb +16 -31
  95. data/lib/action_dispatch/middleware/public_exceptions.rb +39 -14
  96. data/lib/action_dispatch/middleware/reloader.rb +16 -7
  97. data/lib/action_dispatch/middleware/remote_ip.rb +132 -40
  98. data/lib/action_dispatch/middleware/request_id.rb +3 -7
  99. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  100. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  101. data/lib/action_dispatch/middleware/session/cookie_store.rb +84 -29
  102. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  103. data/lib/action_dispatch/middleware/show_exceptions.rb +15 -44
  104. data/lib/action_dispatch/middleware/ssl.rb +72 -0
  105. data/lib/action_dispatch/middleware/stack.rb +6 -1
  106. data/lib/action_dispatch/middleware/static.rb +80 -23
  107. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +34 -0
  108. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  109. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +27 -0
  110. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  111. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  112. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
  113. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  114. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +133 -5
  115. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  122. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  123. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  124. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
  125. data/lib/action_dispatch/railtie.rb +19 -6
  126. data/lib/action_dispatch/request/session.rb +193 -0
  127. data/lib/action_dispatch/request/utils.rb +35 -0
  128. data/lib/action_dispatch/routing/endpoint.rb +10 -0
  129. data/lib/action_dispatch/routing/inspector.rb +234 -0
  130. data/lib/action_dispatch/routing/mapper.rb +897 -436
  131. data/lib/action_dispatch/routing/polymorphic_routes.rb +213 -92
  132. data/lib/action_dispatch/routing/redirection.rb +97 -37
  133. data/lib/action_dispatch/routing/route_set.rb +432 -239
  134. data/lib/action_dispatch/routing/routes_proxy.rb +7 -4
  135. data/lib/action_dispatch/routing/url_for.rb +63 -34
  136. data/lib/action_dispatch/routing.rb +57 -89
  137. data/lib/action_dispatch/testing/assertions/dom.rb +2 -36
  138. data/lib/action_dispatch/testing/assertions/response.rb +24 -38
  139. data/lib/action_dispatch/testing/assertions/routing.rb +55 -54
  140. data/lib/action_dispatch/testing/assertions/selector.rb +2 -434
  141. data/lib/action_dispatch/testing/assertions/tag.rb +2 -137
  142. data/lib/action_dispatch/testing/assertions.rb +11 -7
  143. data/lib/action_dispatch/testing/integration.rb +88 -72
  144. data/lib/action_dispatch/testing/test_process.rb +9 -6
  145. data/lib/action_dispatch/testing/test_request.rb +13 -9
  146. data/lib/action_dispatch/testing/test_response.rb +1 -5
  147. data/lib/action_dispatch.rb +24 -21
  148. data/lib/action_pack/gem_version.rb +15 -0
  149. data/lib/action_pack/version.rb +5 -7
  150. data/lib/action_pack.rb +1 -1
  151. metadata +181 -292
  152. data/lib/abstract_controller/layouts.rb +0 -423
  153. data/lib/abstract_controller/view_paths.rb +0 -96
  154. data/lib/action_controller/caching/actions.rb +0 -185
  155. data/lib/action_controller/caching/pages.rb +0 -187
  156. data/lib/action_controller/caching/sweeping.rb +0 -97
  157. data/lib/action_controller/deprecated/integration_test.rb +0 -2
  158. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  159. data/lib/action_controller/deprecated.rb +0 -3
  160. data/lib/action_controller/metal/compatibility.rb +0 -65
  161. data/lib/action_controller/metal/responder.rb +0 -286
  162. data/lib/action_controller/metal/session_management.rb +0 -14
  163. data/lib/action_controller/railties/paths.rb +0 -25
  164. data/lib/action_controller/record_identifier.rb +0 -85
  165. data/lib/action_controller/vendor/html-scanner/html/document.rb +0 -68
  166. data/lib/action_controller/vendor/html-scanner/html/node.rb +0 -532
  167. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +0 -177
  168. data/lib/action_controller/vendor/html-scanner/html/selector.rb +0 -830
  169. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +0 -107
  170. data/lib/action_controller/vendor/html-scanner/html/version.rb +0 -11
  171. data/lib/action_controller/vendor/html-scanner.rb +0 -20
  172. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  173. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  174. data/lib/action_dispatch/middleware/head.rb +0 -18
  175. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  176. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +0 -31
  177. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -26
  178. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +0 -10
  179. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -2
  180. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +0 -15
  181. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -17
  182. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +0 -2
  183. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  184. data/lib/action_view/asset_paths.rb +0 -142
  185. data/lib/action_view/base.rb +0 -220
  186. data/lib/action_view/buffers.rb +0 -43
  187. data/lib/action_view/context.rb +0 -36
  188. data/lib/action_view/flows.rb +0 -79
  189. data/lib/action_view/helpers/active_model_helper.rb +0 -50
  190. data/lib/action_view/helpers/asset_paths.rb +0 -7
  191. data/lib/action_view/helpers/asset_tag_helper.rb +0 -457
  192. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  193. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  194. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  195. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  196. data/lib/action_view/helpers/atom_feed_helper.rb +0 -200
  197. data/lib/action_view/helpers/cache_helper.rb +0 -64
  198. data/lib/action_view/helpers/capture_helper.rb +0 -203
  199. data/lib/action_view/helpers/controller_helper.rb +0 -25
  200. data/lib/action_view/helpers/csrf_helper.rb +0 -32
  201. data/lib/action_view/helpers/date_helper.rb +0 -1062
  202. data/lib/action_view/helpers/debug_helper.rb +0 -40
  203. data/lib/action_view/helpers/form_helper.rb +0 -1486
  204. data/lib/action_view/helpers/form_options_helper.rb +0 -658
  205. data/lib/action_view/helpers/form_tag_helper.rb +0 -685
  206. data/lib/action_view/helpers/javascript_helper.rb +0 -110
  207. data/lib/action_view/helpers/number_helper.rb +0 -622
  208. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  209. data/lib/action_view/helpers/record_tag_helper.rb +0 -111
  210. data/lib/action_view/helpers/rendering_helper.rb +0 -90
  211. data/lib/action_view/helpers/sanitize_helper.rb +0 -259
  212. data/lib/action_view/helpers/tag_helper.rb +0 -160
  213. data/lib/action_view/helpers/text_helper.rb +0 -426
  214. data/lib/action_view/helpers/translation_helper.rb +0 -91
  215. data/lib/action_view/helpers/url_helper.rb +0 -693
  216. data/lib/action_view/helpers.rb +0 -60
  217. data/lib/action_view/locale/en.yml +0 -160
  218. data/lib/action_view/log_subscriber.rb +0 -28
  219. data/lib/action_view/lookup_context.rb +0 -254
  220. data/lib/action_view/path_set.rb +0 -89
  221. data/lib/action_view/railtie.rb +0 -55
  222. data/lib/action_view/renderer/abstract_renderer.rb +0 -41
  223. data/lib/action_view/renderer/partial_renderer.rb +0 -415
  224. data/lib/action_view/renderer/renderer.rb +0 -54
  225. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -106
  226. data/lib/action_view/renderer/template_renderer.rb +0 -94
  227. data/lib/action_view/template/error.rb +0 -128
  228. data/lib/action_view/template/handlers/builder.rb +0 -26
  229. data/lib/action_view/template/handlers/erb.rb +0 -125
  230. data/lib/action_view/template/handlers.rb +0 -50
  231. data/lib/action_view/template/resolver.rb +0 -272
  232. data/lib/action_view/template/text.rb +0 -30
  233. data/lib/action_view/template.rb +0 -337
  234. data/lib/action_view/test_case.rb +0 -245
  235. data/lib/action_view/testing/resolvers.rb +0 -50
  236. data/lib/action_view.rb +0 -84
  237. data/lib/sprockets/assets.rake +0 -99
  238. data/lib/sprockets/bootstrap.rb +0 -37
  239. data/lib/sprockets/compressors.rb +0 -83
  240. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  241. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  242. data/lib/sprockets/helpers.rb +0 -6
  243. data/lib/sprockets/railtie.rb +0 -62
  244. data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,85 +1,175 @@
1
+ require 'active_support/core_ext/module/attribute_accessors'
2
+ require 'active_support/core_ext/hash/slice'
3
+
1
4
  module ActionDispatch
2
5
  module Http
3
6
  module URL
7
+ IP_HOST_REGEXP = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
8
+ HOST_REGEXP = /(^[^:]+:\/\/)?(\[[^\]]+\]|[^:]+)(?::(\d+$))?/
9
+ PROTOCOL_REGEXP = /^([^:]+)(:)?(\/\/)?$/
10
+
4
11
  mattr_accessor :tld_length
5
12
  self.tld_length = 1
6
13
 
7
14
  class << self
8
- def extract_domain(host, tld_length = @@tld_length)
9
- return nil unless named_host?(host)
10
- host.split('.').last(1 + tld_length).join('.')
15
+ def extract_domain(host, tld_length)
16
+ extract_domain_from(host, tld_length) if named_host?(host)
11
17
  end
12
18
 
13
- def extract_subdomains(host, tld_length = @@tld_length)
14
- return [] unless named_host?(host)
15
- parts = host.split('.')
16
- parts[0..-(tld_length+2)]
19
+ def extract_subdomains(host, tld_length)
20
+ if named_host?(host)
21
+ extract_subdomains_from(host, tld_length)
22
+ else
23
+ []
24
+ end
17
25
  end
18
26
 
19
- def extract_subdomain(host, tld_length = @@tld_length)
27
+ def extract_subdomain(host, tld_length)
20
28
  extract_subdomains(host, tld_length).join('.')
21
29
  end
22
30
 
23
- def url_for(options = {})
24
- unless options[:host].present? || options[:only_path].present?
31
+ def url_for(options)
32
+ if options[:only_path]
33
+ path_for options
34
+ else
35
+ full_url_for options
36
+ end
37
+ end
38
+
39
+ def full_url_for(options)
40
+ host = options[:host]
41
+ protocol = options[:protocol]
42
+ port = options[:port]
43
+
44
+ unless host
25
45
  raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true'
26
46
  end
27
47
 
28
- rewritten_url = ""
29
-
30
- unless options[:only_path]
31
- unless options[:protocol] == false
32
- rewritten_url << (options[:protocol] || "http")
33
- rewritten_url << ":" unless rewritten_url.match(%r{:|//})
34
- end
35
- rewritten_url << "//" unless rewritten_url.match("//")
36
- rewritten_url << rewrite_authentication(options)
37
- rewritten_url << host_or_subdomain_and_domain(options)
38
- rewritten_url << ":#{options.delete(:port)}" if options[:port]
48
+ build_host_url(host, port, protocol, options, path_for(options))
49
+ end
50
+
51
+ def path_for(options)
52
+ path = options[:script_name].to_s.chomp("/")
53
+ path << options[:path] if options.key?(:path)
54
+
55
+ add_trailing_slash(path) if options[:trailing_slash]
56
+ add_params(path, options[:params]) if options.key?(:params)
57
+ add_anchor(path, options[:anchor]) if options.key?(:anchor)
58
+
59
+ path
60
+ end
61
+
62
+ private
63
+
64
+ def add_params(path, params)
65
+ params = { params: params } unless params.is_a?(Hash)
66
+ params.reject! { |_,v| v.to_param.nil? }
67
+ path << "?#{params.to_query}" unless params.empty?
68
+ end
69
+
70
+ def add_anchor(path, anchor)
71
+ if anchor
72
+ path << "##{Journey::Router::Utils.escape_fragment(anchor.to_param)}"
39
73
  end
74
+ end
40
75
 
41
- path = options.delete(:path) || ''
76
+ def extract_domain_from(host, tld_length)
77
+ host.split('.').last(1 + tld_length).join('.')
78
+ end
42
79
 
43
- params = options[:params] || {}
44
- params.reject! {|k,v| v.to_param.nil? }
80
+ def extract_subdomains_from(host, tld_length)
81
+ parts = host.split('.')
82
+ parts[0..-(tld_length + 2)]
83
+ end
45
84
 
46
- if options[:trailing_slash] && !path.ends_with?('/')
47
- rewritten_url << path.sub(/(\?|\z)/) { "/" + $& }
48
- else
49
- rewritten_url << path
85
+ def add_trailing_slash(path)
86
+ # includes querysting
87
+ if path.include?('?')
88
+ path.sub!(/\?/, '/\&')
89
+ # does not have a .format
90
+ elsif !path.include?(".")
91
+ path.sub!(/[^\/]\z|\A\z/, '\&/')
50
92
  end
51
- rewritten_url << "?#{params.to_query}" unless params.empty?
52
- rewritten_url << "##{Journey::Router::Utils.escape_fragment(options[:anchor].to_param.to_s)}" if options[:anchor]
53
- rewritten_url
54
93
  end
55
94
 
56
- private
95
+ def build_host_url(host, port, protocol, options, path)
96
+ if match = host.match(HOST_REGEXP)
97
+ protocol ||= match[1] unless protocol == false
98
+ host = match[2]
99
+ port = match[3] unless options.key? :port
100
+ end
101
+
102
+ protocol = normalize_protocol protocol
103
+ host = normalize_host(host, options)
104
+
105
+ result = protocol.dup
106
+
107
+ if options[:user] && options[:password]
108
+ result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
109
+ end
110
+
111
+ result << host
112
+ normalize_port(port, protocol) { |normalized_port|
113
+ result << ":#{normalized_port}"
114
+ }
115
+
116
+ result.concat path
117
+ end
57
118
 
58
119
  def named_host?(host)
59
- !(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host))
120
+ IP_HOST_REGEXP !~ host
60
121
  end
61
122
 
62
- def rewrite_authentication(options)
63
- if options[:user] && options[:password]
64
- "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
123
+ def normalize_protocol(protocol)
124
+ case protocol
125
+ when nil
126
+ "http://"
127
+ when false, "//"
128
+ "//"
129
+ when PROTOCOL_REGEXP
130
+ "#{$1}://"
65
131
  else
66
- ""
132
+ raise ArgumentError, "Invalid :protocol option: #{protocol.inspect}"
67
133
  end
68
134
  end
69
135
 
70
- def host_or_subdomain_and_domain(options)
71
- return options[:host] if !named_host?(options[:host]) || (options[:subdomain].nil? && options[:domain].nil?)
136
+ def normalize_host(_host, options)
137
+ return _host unless named_host?(_host)
72
138
 
73
139
  tld_length = options[:tld_length] || @@tld_length
140
+ subdomain = options.fetch :subdomain, true
141
+ domain = options[:domain]
74
142
 
75
143
  host = ""
76
- unless options[:subdomain] == false
77
- host << (options[:subdomain] || extract_subdomain(options[:host], tld_length)).to_param
78
- host << "."
144
+ if subdomain == true
145
+ return _host if domain.nil?
146
+
147
+ host << extract_subdomains_from(_host, tld_length).join('.')
148
+ elsif subdomain
149
+ host << subdomain.to_param
79
150
  end
80
- host << (options[:domain] || extract_domain(options[:host], tld_length))
151
+ host << "." unless host.empty?
152
+ host << (domain || extract_domain_from(_host, tld_length))
81
153
  host
82
154
  end
155
+
156
+ def normalize_port(port, protocol)
157
+ return unless port
158
+
159
+ case protocol
160
+ when "//" then yield port
161
+ when "https://"
162
+ yield port unless port.to_i == 443
163
+ else
164
+ yield port unless port.to_i == 80
165
+ end
166
+ end
167
+ end
168
+
169
+ def initialize(env)
170
+ super
171
+ @protocol = nil
172
+ @port = nil
83
173
  end
84
174
 
85
175
  # Returns the complete URL used for this request.
@@ -94,7 +184,7 @@ module ActionDispatch
94
184
 
95
185
  # Returns the \host for this request, such as "example.com".
96
186
  def raw_host_with_port
97
- if forwarded = env["HTTP_X_FORWARDED_HOST"]
187
+ if forwarded = env["HTTP_X_FORWARDED_HOST"].presence
98
188
  forwarded.split(/,\s?/).last
99
189
  else
100
190
  env['HTTP_HOST'] || "#{env['SERVER_NAME'] || env['SERVER_ADDR']}:#{env['SERVER_PORT']}"
@@ -171,7 +261,7 @@ module ActionDispatch
171
261
  # such as 2 to catch <tt>"www"</tt> instead of <tt>"www.rubyonrails"</tt>
172
262
  # in "www.rubyonrails.co.uk".
173
263
  def subdomain(tld_length = @@tld_length)
174
- subdomains(tld_length).join(".")
264
+ ActionDispatch::Http::URL.extract_subdomain(host, tld_length)
175
265
  end
176
266
  end
177
267
  end
@@ -0,0 +1,5 @@
1
+ module Rack # :nodoc:
2
+ Mount = ActionDispatch::Journey::Router
3
+ Mount::RouteSet = ActionDispatch::Journey::Router
4
+ Mount::RegexpWithNamedGroups = ActionDispatch::Journey::Path::Pattern
5
+ end
@@ -0,0 +1,166 @@
1
+ require 'action_controller/metal/exceptions'
2
+ require 'active_support/deprecation'
3
+
4
+ module ActionDispatch
5
+ module Journey
6
+ # The Formatter class is used for formatting URLs. For example, parameters
7
+ # passed to +url_for+ in Rails will eventually call Formatter#generate.
8
+ class Formatter # :nodoc:
9
+ attr_reader :routes
10
+
11
+ def initialize(routes)
12
+ @routes = routes
13
+ @cache = nil
14
+ end
15
+
16
+ def generate(name, options, path_parameters, parameterize = nil)
17
+ constraints = path_parameters.merge(options)
18
+ missing_keys = []
19
+
20
+ match_route(name, constraints) do |route|
21
+ parameterized_parts = extract_parameterized_parts(route, options, path_parameters, parameterize)
22
+
23
+ # Skip this route unless a name has been provided or it is a
24
+ # standard Rails route since we can't determine whether an options
25
+ # hash passed to url_for matches a Rack application or a redirect.
26
+ next unless name || route.dispatcher?
27
+
28
+ missing_keys = missing_keys(route, parameterized_parts)
29
+ next unless missing_keys.empty?
30
+ params = options.dup.delete_if do |key, _|
31
+ parameterized_parts.key?(key) || route.defaults.key?(key)
32
+ end
33
+
34
+ defaults = route.defaults
35
+ required_parts = route.required_parts
36
+ parameterized_parts.delete_if do |key, value|
37
+ value.to_s == defaults[key].to_s && !required_parts.include?(key)
38
+ end
39
+
40
+ return [route.format(parameterized_parts), params]
41
+ end
42
+
43
+ message = "No route matches #{Hash[constraints.sort_by{|k,v| k.to_s}].inspect}"
44
+ message << " missing required keys: #{missing_keys.sort.inspect}" unless missing_keys.empty?
45
+
46
+ raise ActionController::UrlGenerationError, message
47
+ end
48
+
49
+ def clear
50
+ @cache = nil
51
+ end
52
+
53
+ private
54
+
55
+ def extract_parameterized_parts(route, options, recall, parameterize = nil)
56
+ parameterized_parts = recall.merge(options)
57
+
58
+ keys_to_keep = route.parts.reverse.drop_while { |part|
59
+ !options.key?(part) || (options[part] || recall[part]).nil?
60
+ } | route.required_parts
61
+
62
+ (parameterized_parts.keys - keys_to_keep).each do |bad_key|
63
+ parameterized_parts.delete(bad_key)
64
+ end
65
+
66
+ if parameterize
67
+ parameterized_parts.each do |k, v|
68
+ parameterized_parts[k] = parameterize.call(k, v)
69
+ end
70
+ end
71
+
72
+ parameterized_parts.keep_if { |_, v| v }
73
+ parameterized_parts
74
+ end
75
+
76
+ def named_routes
77
+ routes.named_routes
78
+ end
79
+
80
+ def match_route(name, options)
81
+ if named_routes.key?(name)
82
+ yield named_routes[name]
83
+ else
84
+ # Make sure we don't show the deprecation warning more than once
85
+ warned = false
86
+
87
+ routes = non_recursive(cache, options)
88
+
89
+ hash = routes.group_by { |_, r| r.score(options) }
90
+
91
+ hash.keys.sort.reverse_each do |score|
92
+ break if score < 0
93
+
94
+ hash[score].sort_by { |i, _| i }.each do |_, route|
95
+ if name && !warned
96
+ ActiveSupport::Deprecation.warn <<-MSG.squish
97
+ You are trying to generate the URL for a named route called
98
+ #{name.inspect} but no such route was found. In the future,
99
+ this will result in an `ActionController::UrlGenerationError`
100
+ exception.
101
+ MSG
102
+
103
+ warned = true
104
+ end
105
+
106
+ yield route
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ def non_recursive(cache, options)
113
+ routes = []
114
+ queue = [cache]
115
+
116
+ while queue.any?
117
+ c = queue.shift
118
+ routes.concat(c[:___routes]) if c.key?(:___routes)
119
+
120
+ options.each do |pair|
121
+ queue << c[pair] if c.key?(pair)
122
+ end
123
+ end
124
+
125
+ routes
126
+ end
127
+
128
+ # Returns an array populated with missing keys if any are present.
129
+ def missing_keys(route, parts)
130
+ missing_keys = []
131
+ tests = route.path.requirements
132
+ route.required_parts.each { |key|
133
+ if tests.key?(key)
134
+ missing_keys << key unless /\A#{tests[key]}\Z/ === parts[key]
135
+ else
136
+ missing_keys << key unless parts[key]
137
+ end
138
+ }
139
+ missing_keys
140
+ end
141
+
142
+ def possibles(cache, options, depth = 0)
143
+ cache.fetch(:___routes) { [] } + options.find_all { |pair|
144
+ cache.key?(pair)
145
+ }.flat_map { |pair|
146
+ possibles(cache[pair], options, depth + 1)
147
+ }
148
+ end
149
+
150
+ def build_cache
151
+ root = { ___routes: [] }
152
+ routes.each_with_index do |route, i|
153
+ leaf = route.required_defaults.inject(root) do |h, tuple|
154
+ h[tuple] ||= {}
155
+ end
156
+ (leaf[:___routes] ||= []) << [i, route]
157
+ end
158
+ root
159
+ end
160
+
161
+ def cache
162
+ @cache ||= build_cache
163
+ end
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,162 @@
1
+ require 'action_dispatch/journey/gtg/transition_table'
2
+
3
+ module ActionDispatch
4
+ module Journey # :nodoc:
5
+ module GTG # :nodoc:
6
+ class Builder # :nodoc:
7
+ DUMMY = Nodes::Dummy.new
8
+
9
+ attr_reader :root, :ast, :endpoints
10
+
11
+ def initialize(root)
12
+ @root = root
13
+ @ast = Nodes::Cat.new root, DUMMY
14
+ @followpos = nil
15
+ end
16
+
17
+ def transition_table
18
+ dtrans = TransitionTable.new
19
+ marked = {}
20
+ state_id = Hash.new { |h,k| h[k] = h.length }
21
+
22
+ start = firstpos(root)
23
+ dstates = [start]
24
+ until dstates.empty?
25
+ s = dstates.shift
26
+ next if marked[s]
27
+ marked[s] = true # mark s
28
+
29
+ s.group_by { |state| symbol(state) }.each do |sym, ps|
30
+ u = ps.flat_map { |l| followpos(l) }
31
+ next if u.empty?
32
+
33
+ if u.uniq == [DUMMY]
34
+ from = state_id[s]
35
+ to = state_id[Object.new]
36
+ dtrans[from, to] = sym
37
+
38
+ dtrans.add_accepting(to)
39
+ ps.each { |state| dtrans.add_memo(to, state.memo) }
40
+ else
41
+ dtrans[state_id[s], state_id[u]] = sym
42
+
43
+ if u.include?(DUMMY)
44
+ to = state_id[u]
45
+
46
+ accepting = ps.find_all { |l| followpos(l).include?(DUMMY) }
47
+
48
+ accepting.each { |accepting_state|
49
+ dtrans.add_memo(to, accepting_state.memo)
50
+ }
51
+
52
+ dtrans.add_accepting(state_id[u])
53
+ end
54
+ end
55
+
56
+ dstates << u
57
+ end
58
+ end
59
+
60
+ dtrans
61
+ end
62
+
63
+ def nullable?(node)
64
+ case node
65
+ when Nodes::Group
66
+ true
67
+ when Nodes::Star
68
+ true
69
+ when Nodes::Or
70
+ node.children.any? { |c| nullable?(c) }
71
+ when Nodes::Cat
72
+ nullable?(node.left) && nullable?(node.right)
73
+ when Nodes::Terminal
74
+ !node.left
75
+ when Nodes::Unary
76
+ nullable?(node.left)
77
+ else
78
+ raise ArgumentError, 'unknown nullable: %s' % node.class.name
79
+ end
80
+ end
81
+
82
+ def firstpos(node)
83
+ case node
84
+ when Nodes::Star
85
+ firstpos(node.left)
86
+ when Nodes::Cat
87
+ if nullable?(node.left)
88
+ firstpos(node.left) | firstpos(node.right)
89
+ else
90
+ firstpos(node.left)
91
+ end
92
+ when Nodes::Or
93
+ node.children.flat_map { |c| firstpos(c) }.uniq
94
+ when Nodes::Unary
95
+ firstpos(node.left)
96
+ when Nodes::Terminal
97
+ nullable?(node) ? [] : [node]
98
+ else
99
+ raise ArgumentError, 'unknown firstpos: %s' % node.class.name
100
+ end
101
+ end
102
+
103
+ def lastpos(node)
104
+ case node
105
+ when Nodes::Star
106
+ firstpos(node.left)
107
+ when Nodes::Or
108
+ node.children.flat_map { |c| lastpos(c) }.uniq
109
+ when Nodes::Cat
110
+ if nullable?(node.right)
111
+ lastpos(node.left) | lastpos(node.right)
112
+ else
113
+ lastpos(node.right)
114
+ end
115
+ when Nodes::Terminal
116
+ nullable?(node) ? [] : [node]
117
+ when Nodes::Unary
118
+ lastpos(node.left)
119
+ else
120
+ raise ArgumentError, 'unknown lastpos: %s' % node.class.name
121
+ end
122
+ end
123
+
124
+ def followpos(node)
125
+ followpos_table[node]
126
+ end
127
+
128
+ private
129
+
130
+ def followpos_table
131
+ @followpos ||= build_followpos
132
+ end
133
+
134
+ def build_followpos
135
+ table = Hash.new { |h, k| h[k] = [] }
136
+ @ast.each do |n|
137
+ case n
138
+ when Nodes::Cat
139
+ lastpos(n.left).each do |i|
140
+ table[i] += firstpos(n.right)
141
+ end
142
+ when Nodes::Star
143
+ lastpos(n).each do |i|
144
+ table[i] += firstpos(n)
145
+ end
146
+ end
147
+ end
148
+ table
149
+ end
150
+
151
+ def symbol(edge)
152
+ case edge
153
+ when Journey::Nodes::Symbol
154
+ edge.regexp
155
+ else
156
+ edge.left
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,47 @@
1
+ require 'strscan'
2
+
3
+ module ActionDispatch
4
+ module Journey # :nodoc:
5
+ module GTG # :nodoc:
6
+ class MatchData # :nodoc:
7
+ attr_reader :memos
8
+
9
+ def initialize(memos)
10
+ @memos = memos
11
+ end
12
+ end
13
+
14
+ class Simulator # :nodoc:
15
+ attr_reader :tt
16
+
17
+ def initialize(transition_table)
18
+ @tt = transition_table
19
+ end
20
+
21
+ def simulate(string)
22
+ ms = memos(string) { return }
23
+ MatchData.new(ms)
24
+ end
25
+
26
+ alias :=~ :simulate
27
+ alias :match :simulate
28
+
29
+ def memos(string)
30
+ input = StringScanner.new(string)
31
+ state = [0]
32
+ while sym = input.scan(%r([/.?]|[^/.?]+))
33
+ state = tt.move(state, sym)
34
+ end
35
+
36
+ acceptance_states = state.find_all { |s|
37
+ tt.accepting? s
38
+ }
39
+
40
+ return yield if acceptance_states.empty?
41
+
42
+ acceptance_states.flat_map { |x| tt.memo(x) }.compact
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end