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>.
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.
11 # URLMap dispatches in such a way that the longest paths are tried
12 # first, since they are most specific.
15 def initialize(map
= {})
20 @mapping = map
.map
{ |location
, app
|
21 if location
=~
%r
{\Ahttps
?://(.*?)(/.*)}
22 host
, location
= $1, $2
27 unless location
[0] == ?/
28 raise ArgumentError
, "paths need to start with /"
30 location
= location
.chomp('/')
33 }.sort_by
{ |(h
, l
, a
)| [-l
.size
, h
.to_s
.size
] } # Longest path first
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
] == ?/
48 'SCRIPT_NAME' => (script_name
+ location
),
49 'PATH_INFO' => path
[location
.size
..-1]))
51 [404, {"Content-Type" => "text/plain"}, ["Not Found: #{path}"]]