0ff32df1813799ec02d4bce893f5290943242ff0
[feedcatcher.git] / vendor / rails / actionpack / lib / action_controller / vendor / rack-1.0 / rack / urlmap.rb
1 module Rack
2 # Rack::URLMap takes a hash mapping urls or paths to apps, and
3 # dispatches accordingly. Support for HTTP/1.1 host names exists if
4 # the URLs start with <tt>http://</tt> or <tt>https://</tt>.
5 #
6 # URLMap modifies the SCRIPT_NAME and PATH_INFO such that the part
7 # relevant for dispatch is in the SCRIPT_NAME, and the rest in the
8 # PATH_INFO. This should be taken care of when you need to
9 # reconstruct the URL in order to create links.
10 #
11 # URLMap dispatches in such a way that the longest paths are tried
12 # first, since they are most specific.
13
14 class URLMap
15 def initialize(map = {})
16 remap(map)
17 end
18
19 def remap(map)
20 @mapping = map.map { |location, app|
21 if location =~ %r{\Ahttps?://(.*?)(/.*)}
22 host, location = $1, $2
23 else
24 host = nil
25 end
26
27 unless location[0] == ?/
28 raise ArgumentError, "paths need to start with /"
29 end
30 location = location.chomp('/')
31
32 [host, location, app]
33 }.sort_by { |(h, l, a)| [-l.size, h.to_s.size] } # Longest path first
34 end
35
36 def call(env)
37 path = env["PATH_INFO"].to_s.squeeze("/")
38 script_name = env['SCRIPT_NAME']
39 hHost, sName, sPort = env.values_at('HTTP_HOST','SERVER_NAME','SERVER_PORT')
40 @mapping.each { |host, location, app|
41 next unless (hHost == host || sName == host \
42 || (host.nil? && (hHost == sName || hHost == sName+':'+sPort)))
43 next unless location == path[0, location.size]
44 next unless path[location.size] == nil || path[location.size] == ?/
45
46 return app.call(
47 env.merge(
48 'SCRIPT_NAME' => (script_name + location),
49 'PATH_INFO' => path[location.size..-1]))
50 }
51 [404, {"Content-Type" => "text/plain"}, ["Not Found: #{path}"]]
52 end
53 end
54 end
55