chneukirchen / rack-mirror

OUTDATED mirror of Rack's darcs repository, use github.com/chneukirchen/rack

This URL has Read+Write access

chneukirchen (author)
Sat May 24 08:54:49 -0700 2008
commit  5a117d0b45b4ed2785a714eaa060e8c66512c4c3
tree    0942c84f57f557d899fa767e06ca37a196563185
parent  ed86dfd676dcb46e276b6906f017df514e5632f9 parent  ebdd511d332d2b6cd33bda7bb4777518cfc89fa4
rack-mirror / lib / rack / file.rb
100644 113 lines (102 sloc) 3.275 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
require 'time'
 
module Rack
  # 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+.
 
  class File
    attr_accessor :root
    attr_accessor :path
 
    def initialize(root)
      @root = root
    end
 
    def call(env)
      dup._call(env)
    end
 
    F = ::File
 
    def _call(env)
      if env["PATH_INFO"].include? ".."
        return [403, {"Content-Type" => "text/plain"}, ["Forbidden\n"]]
      end
 
      @path = F.join(@root, Utils.unescape(env["PATH_INFO"]))
      ext = F.extname(@path)[1..-1]
 
      if F.file?(@path) && F.readable?(@path)
        [200, {
           "Last-Modified" => F.mtime(@path).rfc822,
           "Content-Type" => MIME_TYPES[ext] || "text/plain",
           "Content-Length" => F.size(@path).to_s
         }, self]
      else
        return [404, {"Content-Type" => "text/plain"},
                ["File not found: #{env["PATH_INFO"]}\n"]]
      end
    end
 
    def each
      F.open(@path, "rb") { |file|
        while part = file.read(8192)
          yield part
        end
      }
    end
 
    # :stopdoc:
    # From WEBrick.
    MIME_TYPES = {
      "ai" => "application/postscript",
      "asc" => "text/plain",
      "avi" => "video/x-msvideo",
      "bin" => "application/octet-stream",
      "bmp" => "image/bmp",
      "class" => "application/octet-stream",
      "cer" => "application/pkix-cert",
      "crl" => "application/pkix-crl",
      "crt" => "application/x-x509-ca-cert",
     #"crl" => "application/x-pkcs7-crl",
      "css" => "text/css",
      "dms" => "application/octet-stream",
      "doc" => "application/msword",
      "dvi" => "application/x-dvi",
      "eps" => "application/postscript",
      "etx" => "text/x-setext",
      "exe" => "application/octet-stream",
      "gif" => "image/gif",
      "htm" => "text/html",
      "html" => "text/html",
      "jpe" => "image/jpeg",
      "jpeg" => "image/jpeg",
      "jpg" => "image/jpeg",
      "js" => "text/javascript",
      "lha" => "application/octet-stream",
      "lzh" => "application/octet-stream",
      "mov" => "video/quicktime",
      "mpe" => "video/mpeg",
      "mpeg" => "video/mpeg",
      "mpg" => "video/mpeg",
      "pbm" => "image/x-portable-bitmap",
      "pdf" => "application/pdf",
      "pgm" => "image/x-portable-graymap",
      "png" => "image/png",
      "pnm" => "image/x-portable-anymap",
      "ppm" => "image/x-portable-pixmap",
      "ppt" => "application/vnd.ms-powerpoint",
      "ps" => "application/postscript",
      "qt" => "video/quicktime",
      "ras" => "image/x-cmu-raster",
      "rb" => "text/plain",
      "rd" => "text/plain",
      "rtf" => "application/rtf",
      "sgm" => "text/sgml",
      "sgml" => "text/sgml",
      "tif" => "image/tiff",
      "tiff" => "image/tiff",
      "txt" => "text/plain",
      "xbm" => "image/x-xbitmap",
      "xls" => "application/vnd.ms-excel",
      "xml" => "text/xml",
      "xpm" => "image/x-xpixmap",
      "xwd" => "image/x-xwindowdump",
      "zip" => "application/zip",
    }
    # :startdoc:
  end
end