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

External Aliases

path -> to_path

Attributes

path  [RW] 
root  [RW] 

Public Class methods

[Source]

    # File lib/rack/file.rb, line 18
18:     def initialize(root)
19:       @root = root
20:     end

Public Instance methods

[Source]

    # File lib/rack/file.rb, line 28
28:     def _call(env)
29:       @path_info = Utils.unescape(env["PATH_INFO"])
30:       return forbidden  if @path_info.include? ".."
31: 
32:       @path = F.join(@root, @path_info)
33: 
34:       begin
35:         if F.file?(@path) && F.readable?(@path)
36:           serving
37:         else
38:           raise Errno::EPERM
39:         end
40:       rescue SystemCallError
41:         not_found
42:       end
43:     end

[Source]

    # File lib/rack/file.rb, line 22
22:     def call(env)
23:       dup._call(env)
24:     end

[Source]

    # File lib/rack/file.rb, line 80
80:     def each
81:       F.open(@path, "rb") { |file|
82:         while part = file.read(8192)
83:           yield part
84:         end
85:       }
86:     end

[Source]

    # File lib/rack/file.rb, line 45
45:     def forbidden
46:       body = "Forbidden\n"
47:       [403, {"Content-Type" => "text/plain",
48:              "Content-Length" => body.size.to_s},
49:        [body]]
50:     end

[Source]

    # File lib/rack/file.rb, line 73
73:     def not_found
74:       body = "File not found: #{@path_info}\n"
75:       [404, {"Content-Type" => "text/plain",
76:          "Content-Length" => body.size.to_s},
77:        [body]]
78:     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 58
58:     def serving
59:       if size = F.size?(@path)
60:         body = self
61:       else
62:         body = [F.read(@path)]
63:         size = Utils.bytesize(body.first)
64:       end
65: 
66:       [200, {
67:         "Last-Modified"  => F.mtime(@path).httpdate,
68:         "Content-Type"   => Mime.mime_type(F.extname(@path), 'text/plain'),
69:         "Content-Length" => size.to_s
70:       }, body]
71:     end

[Validate]