Class: Mongrel::DirHandler

Inherits:
HttpHandler show all
Defined in:
lib/mongrel/handlers.rb

Overview

Serves the contents of a directory. You give it the path to the root where the files are located, and it tries to find the files based on the PATH_INFO inside the directory. If the requested path is a directory then it returns a simple directory listing.

It does a simple protection against going outside it’s root path by converting all paths to an absolute expanded path, and then making sure that the final expanded path includes the root path. If it doesn’t than it simply gives a 404.

Constant Summary collapse

MIME_TYPES =
{
  ".css"        =>  "text/css",
  ".gif"        =>  "image/gif",
  ".htm"        =>  "text/html",
  ".html"       =>  "text/html",
  ".jpeg"       =>  "image/jpeg",
  ".jpg"        =>  "image/jpeg",
  ".js"         =>  "text/javascript",
  ".png"        =>  "image/png",
  ".swf"        =>  "application/x-shockwave-flash",
  ".txt"        =>  "text/plain"
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, listing_allowed = true, index_html = "index.html") ⇒ DirHandler

You give it the path to the directory root and an (optional)



60
61
62
63
64
# File 'lib/mongrel/handlers.rb', line 60

def initialize(path, listing_allowed=true, index_html="index.html")
  @path = File.expand_path(path)
  @listing_allowed=listing_allowed
  @index_html = index_html
end

Instance Attribute Details

#pathObject (readonly)

Returns the value of attribute path.



57
58
59
# File 'lib/mongrel/handlers.rb', line 57

def path
  @path
end

Class Method Details

.add_mime_type(extension, type) ⇒ Object

There is a small number of default mime types for extensions, but this lets you add any others you’ll need when serving content.



175
176
177
# File 'lib/mongrel/handlers.rb', line 175

def DirHandler::add_mime_type(extension, type)
  MIME_TYPES[extension] = type
end

Instance Method Details

#can_serve(path_info) ⇒ Object

Checks if the given path can be served and returns the full path (or nil if not).



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
# File 'lib/mongrel/handlers.rb', line 67

def can_serve(path_info)
  req = File.expand_path(File.join(@path,path_info), @path)

  if req.index(@path) == 0 and File.exist? req
    # it exists and it's in the right location
    if File.directory? req
      # the request is for a directory
      index = File.join(req, @index_html)
      if File.exist? index
        # serve the index
        return index
      elsif @listing_allowed
        # serve the directory
        req
      else
        # do not serve anything
        return nil
      end
    else
      # it's a file and it's there
      return req
    end
  else
    # does not exist or isn't in the right spot
    return nil
  end
end

#process(request, response) ⇒ Object

Process the request to either serve a file or a directory listing if allowed (based on the listing_allowed paramter to the constructor).



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/mongrel/handlers.rb', line 149

def process(request, response)
  req = can_serve request.params['PATH_INFO']
  if not req
    # not found, return a 404
    response.start(404) do |head,out|
      out << "File not found"
    end
  else
    begin
      if File.directory? req
        send_dir_listing(request.params["REQUEST_URI"],req, response)
      else
        send_file(req, response)
      end
    rescue => details
      response.reset
      response.start(403) do |head,out|
        out << "Error accessing file: #{details}"
        out << details.backtrace.join("\n")
      end
    end
  end
end

#send_dir_listing(base, dir, response) ⇒ Object

Returns a simplistic directory listing if they’re enabled, otherwise a 403. Base is the base URI from the REQUEST_URI, dir is the directory to serve on the file system (comes from can_serve()), and response is the HttpResponse object to send the results on.



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/mongrel/handlers.rb', line 100

def send_dir_listing(base, dir, response)
  # take off any trailing / so the links come out right
  base.chop! if base[-1] == "/"[-1]

  if @listing_allowed
    response.start(200) do |head,out|
      head['Content-Type'] = "text/html"
      out << "<html><head><title>Directory Listing</title></head><body>"
      Dir.entries(dir).each do |child|
        next if child == "."

        if child == ".."
          out << "<a href=\"#{base}/#{child}\">Up to parent..</a><br/>"
        else
          out << "<a href=\"#{base}/#{child}\">#{child}</a><br/>"
        end
      end
      out << "</body></html>"
    end
  else
    response.start(403) do |head,out|
      out.write("Directory listings not allowed")
    end
  end
end

#send_file(req, response) ⇒ Object

Sends the contents of a file back to the user. Not terribly efficient since it’s opening and closing the file for each read.



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/mongrel/handlers.rb', line 129

def send_file(req, response)
  response.start(200) do |head,out|
    # set the mime type from our map based on the ending
    dot_at = req.rindex(".")
    if dot_at
      ext = req[dot_at .. -1]
      if MIME_TYPES[ext]
        head['Content-Type'] = MIME_TYPES[ext]
      end
    end

    open(req, "rb") do |f|
      out.write(f.read)
    end
  end
end