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.

Methods

_call   call   each   forbidden   new   not_found   serving  

Constants

F = ::File

Attributes

path  [RW] 
root  [RW] 

Public Class methods

[Source]

    # File lib/rack/file.rb, line 15
15:     def initialize(root)
16:       @root = root
17:     end

Public Instance methods

[Source]

    # 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

[Source]

    # File lib/rack/file.rb, line 19
19:     def call(env)
20:       dup._call(env)
21:     end

[Source]

    # 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

[Source]

    # 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

[Source]

    # 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.

[Source]

    # 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

[Validate]