Sha256: 49025707e18f560d3934959d959c1dd71338b7e2cd59938c9715d66d2b3d54e5

Contents?: true

Size: 1.88 KB

Versions: 13

Compression:

Stored size: 1.88 KB

Contents

require 'time'
require 'rack/mime'

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)
      @path_info = Utils.unescape(env["PATH_INFO"])
      return forbidden  if @path_info.include? ".."

      @path = F.join(@root, @path_info)

      begin
        if F.file?(@path) && F.readable?(@path)
          serving
        else
          raise Errno::EPERM
        end
      rescue SystemCallError
        not_found
      end
    end

    def forbidden
      body = "Forbidden\n"
      [403, {"Content-Type" => "text/plain",
             "Content-Length" => body.size.to_s},
       [body]]
    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.

    def serving
      if size = F.size?(@path)
        body = self
      else
        body = [F.read(@path)]
        size = body.first.size
      end

      [200, {
        "Last-Modified"  => F.mtime(@path).httpdate,
        "Content-Type"   => Mime.mime_type(F.extname(@path), 'text/plain'),
        "Content-Length" => size.to_s
      }, body]
    end

    def not_found
      body = "File not found: #{@path_info}\n"
      [404, {"Content-Type" => "text/plain",
         "Content-Length" => body.size.to_s},
       [body]]
    end

    def each
      F.open(@path, "rb") { |file|
        while part = file.read(8192)
          yield part
        end
      }
    end
  end
end

Version data entries

13 entries across 13 versions & 6 rubygems

Version Path
p8-castronaut-0.6.1.1 vendor/rack/lib/rack/file.rb
relevance-castronaut-0.6.0 vendor/rack/lib/rack/file.rb
relevance-castronaut-0.6.1 vendor/rack/lib/rack/file.rb
relevance-castronaut-0.7.4 vendor/rack/lib/rack/file.rb
relevance-castronaut-0.7.5 vendor/rack/lib/rack/file.rb
nbudin-castronaut-0.7.5 vendor/rack/lib/rack/file.rb
mack-0.8.3.1 lib/gems/rack-0.9.1/lib/rack/file.rb
mack-0.8.3 lib/gems/rack-0.9.1/lib/rack/file.rb
passenger-2.1.2 vendor/rack-0.9.1/lib/rack/file.rb
passenger-2.2.1 vendor/rack-0.9.1/lib/rack/file.rb
passenger-2.2.0 vendor/rack-0.9.1/lib/rack/file.rb
passenger-2.1.3 vendor/rack-0.9.1/lib/rack/file.rb
rack-0.9.1 lib/rack/file.rb