Serving Static Files

Often your dynamic site will have images and scripts and such. Fortunately, Camping supports the X-Sendfile header, which ensures that you can easily pass files through the web server with haste! You simply set the header to the full path of the file you want to send.

For example, here's a controller that adds a static folder which passes through all of its files using that header.

 #!ruby

 module Camping::Controllers
  class Static < R '/static/(.+)'         
    MIME_TYPES = {'.css' => 'text/css', '.js' => 'text/javascript', 
                  '.jpg' => 'image/jpeg'}
    PATH = File.expand_path(File.dirname(__FILE__))

    def get(path)
      @headers['Content-Type'] = MIME_TYPES[path[/\.\w+$/, 0]] || "text/plain"
      unless path.include? ".." # prevent directory traversal attacks
        @headers['X-Sendfile'] = "#{PATH}/static/#{path}"
      else
        @status = "403"
        "403 - Invalid path"
      end
    end
  end 
 end

Another great way to do this is by customizing your web server. Mongrel, for example, includes a DirHandler class which mounts a file directory to a URL. However, the above is superior for a self-contained app designed to run on a myriad of web servers.


For getting mime types without having to define them yourself:

gem install mime-types

require 'mime/types'
class Static < R('/static/(.+)')
  PATH = File.expand_path(File.dirname(__FILE__))

  def get file
   if file.include? '..'
      @status = '403'
      return '403 - Invalid path'
    else
      type = (MIME::Types.type_for(file)[0] || 'text/plain').to_s
      @headers['Content-Type'] = type
      @headers['X-Sendfile'] = File.join PATH, 'static', file
    end
  end
end

Return to CampingRulesOfThumb