Class: Rack::Directory
- Inherits:
-
Object
- Object
- Rack::Directory
- Defined in:
- lib/rack/directory.rb
Overview
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::Files of the same root will be used.
Defined Under Namespace
Classes: DirectoryBody
Constant Summary collapse
- DIR_FILE =
"<tr><td class='name'><a href='%s'>%s</a></td><td class='size'>%s</td><td class='type'>%s</td><td class='mtime'>%s</td></tr>"- DIR_PAGE =
"<html><head>\n <title>%s</title>\n <meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n <style type='text/css'>\ntable { width:100%%; }\n.name { text-align:left; }\n.size, .mtime { text-align:right; }\n.type { width:11em; }\n.mtime { width:15em; }\n </style>\n</head><body>\n<h1>%s</h1>\n<hr />\n<table>\n <tr>\n<th class='name'>Name</th>\n<th class='size'>Size</th>\n<th class='type'>Type</th>\n<th class='mtime'>Last Modified</th>\n </tr>\n%s\n</table>\n<hr />\n</body></html>\n"- FILESIZE_FORMAT =
Stolen from Ramaze
[ ['%.1fT', 1 << 40], ['%.1fG', 1 << 30], ['%.1fM', 1 << 20], ['%.1fK', 1 << 10], ]
Instance Attribute Summary collapse
-
#path ⇒ Object
readonly
Returns the value of attribute path.
-
#root ⇒ Object
readonly
Returns the value of attribute root.
Instance Method Summary collapse
- #call(env) ⇒ Object
- #check_bad_request(path_info) ⇒ Object
- #check_forbidden(path_info) ⇒ Object
- #entity_not_found(path_info) ⇒ Object
- #filesize_format(int) ⇒ Object
- #get(env) ⇒ Object
-
#initialize(root, app = nil) ⇒ Directory
constructor
A new instance of Directory.
- #list_directory(path_info, path, script_name) ⇒ Object
-
#list_path(env, path, path_info, script_name) ⇒ Object
TODO: add correct response if not readable, not sure if 404 is the best option.
- #stat(node) ⇒ Object
Constructor Details
#initialize(root, app = nil) ⇒ Directory
Returns a new instance of Directory.
62 63 64 65 66 |
# File 'lib/rack/directory.rb', line 62 def initialize(root, app = nil) @root = ::File.(root) @app = app || Rack::Files.new(@root) @head = Rack::Head.new(lambda { |env| get env }) end |
Instance Attribute Details
#path ⇒ Object (readonly)
Returns the value of attribute path.
60 61 62 |
# File 'lib/rack/directory.rb', line 60 def path @path end |
#root ⇒ Object (readonly)
Returns the value of attribute root.
60 61 62 |
# File 'lib/rack/directory.rb', line 60 def root @root end |
Instance Method Details
#call(env) ⇒ Object
68 69 70 71 |
# File 'lib/rack/directory.rb', line 68 def call(env) # strip body if this is a HEAD call @head.call env end |
#check_bad_request(path_info) ⇒ Object
87 88 89 90 91 92 93 94 95 |
# File 'lib/rack/directory.rb', line 87 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) ⇒ Object
97 98 99 100 101 102 103 104 105 |
# File 'lib/rack/directory.rb', line 97 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) ⇒ Object
157 158 159 160 161 162 163 |
# File 'lib/rack/directory.rb', line 157 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) ⇒ Object
174 175 176 177 178 179 180 |
# File 'lib/rack/directory.rb', line 174 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) ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/rack/directory.rb', line 73 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) ⇒ Object
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/rack/directory.rb', line 107 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) ⇒ Object
TODO: add correct response if not readable, not sure if 404 is the best
option
143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/rack/directory.rb', line 143 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) ⇒ Object
135 136 137 138 139 |
# File 'lib/rack/directory.rb', line 135 def stat(node) ::File.stat(node) rescue Errno::ENOENT, Errno::ELOOP return nil end |