class Rack::Directory
Rack::Directory serves entries below the
root
given, according to the path info of the Rack request. If a directory is found, the
file's contents will be presented in an html based index. If a file is
found, the env will be passed to the specified app
.
If app
is not specified, a Rack::File
of the same root
will be used.
Constants
- DIR_FILE
- DIR_PAGE
- FILESIZE_FORMAT
Stolen from Ramaze
Attributes
path[R]
root[R]
Public Class Methods
new(root, app=nil)
click to toggle source
# File lib/rack/directory.rb, line 59 def initialize(root, app=nil) @root = ::File.expand_path(root) @app = app || Rack::File.new(@root) @head = Rack::Head.new(lambda { |env| get env }) end
Public Instance Methods
call(env)
click to toggle source
# File lib/rack/directory.rb, line 65 def call(env) # strip body if this is a HEAD call @head.call env end
check_bad_request(path_info)
click to toggle source
# File lib/rack/directory.rb, line 84 def check_bad_request(path_info) return if Utils.valid_path?(path_info) body = "Bad Request\n" size = body.bytesize return [400, {CONTENT_TYPE => "text/plain", CONTENT_LENGTH => size.to_s, "X-Cascade" => "pass"}, [body]] end
check_forbidden(path_info)
click to toggle source
# File lib/rack/directory.rb, line 94 def check_forbidden(path_info) return unless path_info.include? ".." body = "Forbidden\n" size = body.bytesize return [403, {CONTENT_TYPE => "text/plain", CONTENT_LENGTH => size.to_s, "X-Cascade" => "pass"}, [body]] end
entity_not_found(path_info)
click to toggle source
# File lib/rack/directory.rb, line 154 def entity_not_found(path_info) body = "Entity not found: #{path_info}\n" size = body.bytesize return [404, {CONTENT_TYPE => "text/plain", CONTENT_LENGTH => size.to_s, "X-Cascade" => "pass"}, [body]] end
filesize_format(int)
click to toggle source
# File lib/rack/directory.rb, line 171 def filesize_format(int) FILESIZE_FORMAT.each do |format, size| return format % (int.to_f / size) if int >= size end "#{int}B" end
get(env)
click to toggle source
# File lib/rack/directory.rb, line 70 def get(env) script_name = env[SCRIPT_NAME] path_info = Utils.unescape_path(env[PATH_INFO]) if bad_request = check_bad_request(path_info) bad_request elsif forbidden = check_forbidden(path_info) forbidden else path = ::File.join(@root, path_info) list_path(env, path, path_info, script_name) end end
list_directory(path_info, path, script_name)
click to toggle source
# File lib/rack/directory.rb, line 104 def list_directory(path_info, path, script_name) files = [['../','Parent Directory','','','']] glob = ::File.join(path, '*') url_head = (script_name.split('/') + path_info.split('/')).map do |part| Rack::Utils.escape_path part end Dir[glob].sort.each do |node| stat = stat(node) next unless stat basename = ::File.basename(node) ext = ::File.extname(node) url = ::File.join(*url_head + [Rack::Utils.escape_path(basename)]) size = stat.size type = stat.directory? ? 'directory' : Mime.mime_type(ext) size = stat.directory? ? '-' : filesize_format(size) mtime = stat.mtime.httpdate url << '/' if stat.directory? basename << '/' if stat.directory? files << [ url, basename, size, type, mtime ] end return [ 200, { CONTENT_TYPE =>'text/html; charset=utf-8'}, DirectoryBody.new(@root, path, files) ] end
list_path(env, path, path_info, script_name)
click to toggle source
TODO: add correct response if not readable, not sure if 404 is the best
option
# File lib/rack/directory.rb, line 140 def list_path(env, path, path_info, script_name) stat = ::File.stat(path) if stat.readable? return @app.call(env) if stat.file? return list_directory(path_info, path, script_name) if stat.directory? else raise Errno::ENOENT, 'No such file or directory' end rescue Errno::ENOENT, Errno::ELOOP return entity_not_found(path_info) end
stat(node)
click to toggle source
# File lib/rack/directory.rb, line 132 def stat(node) ::File.stat(node) rescue Errno::ENOENT, Errno::ELOOP return nil end