| 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