Class | Rack::File |
In: |
lib/rack/file.rb
|
Parent: | Object |
Rack::File serves files below the root given, according to the path info of the Rack request.
Handlers can detect if bodies are a Rack::File, and use mechanisms like sendfile on the path.
F | = | ::File |
path | [RW] | |
root | [RW] |
# File lib/rack/file.rb, line 25 25: def _call(env) 26: @path_info = Utils.unescape(env["PATH_INFO"]) 27: return forbidden if @path_info.include? ".." 28: 29: @path = F.join(@root, @path_info) 30: 31: begin 32: if F.file?(@path) && F.readable?(@path) 33: serving 34: else 35: raise Errno::EPERM 36: end 37: rescue SystemCallError 38: not_found 39: end 40: end
# File lib/rack/file.rb, line 77 77: def each 78: F.open(@path, "rb") { |file| 79: while part = file.read(8192) 80: yield part 81: end 82: } 83: end
# File lib/rack/file.rb, line 42 42: def forbidden 43: body = "Forbidden\n" 44: [403, {"Content-Type" => "text/plain", 45: "Content-Length" => body.size.to_s}, 46: [body]] 47: end
# File lib/rack/file.rb, line 70 70: def not_found 71: body = "File not found: #{@path_info}\n" 72: [404, {"Content-Type" => "text/plain", 73: "Content-Length" => body.size.to_s}, 74: [body]] 75: end
NOTE:
We check via File::size? whether this file provides size info via stat (e.g. /proc files often don't), otherwise we have to figure it out by reading the whole file into memory. And while we're at it we also use this as body then.
# File lib/rack/file.rb, line 55 55: def serving 56: if size = F.size?(@path) 57: body = self 58: else 59: body = [F.read(@path)] 60: size = body.first.size 61: end 62: 63: [200, { 64: "Last-Modified" => F.mtime(@path).httpdate, 65: "Content-Type" => Mime.mime_type(F.extname(@path), 'text/plain'), 66: "Content-Length" => size.to_s 67: }, body] 68: end