Sha256: be06e65823ce6bf5269937b53d96c9b2089837443b3aaf0827c8035330ae3dd6

Contents?: true

Size: 1.93 KB

Versions: 29

Compression:

Stored size: 1.93 KB

Contents

require 'time'
require 'rack/utils'
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

    alias :to_path :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 = Utils.bytesize(body.first)
      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

29 entries across 29 versions & 13 rubygems

Version Path
kjvarga-rack-1.0.0 lib/rack/file.rb
qoobaa-rack-1.0.0.1 lib/rack/file.rb
qoobaa-rack-1.0.2 lib/rack/file.rb
timocratic-rack-1.0.0 lib/rack/file.rb
middleman-0.12.2 lib/middleman/vendor/gems/gems/rack-1.0.1/lib/rack/file.rb
middleman-0.12.1 lib/middleman/vendor/gems/gems/rack-1.0.1/lib/rack/file.rb
middleman-0.12.0.pre3 lib/middleman/vendor/gems/gems/rack-1.0.1/lib/rack/file.rb
middleman-0.12.0.pre2 lib/middleman/vendor/gems/gems/rack-1.0.1/lib/rack/file.rb
colouringcode-passenger-0.1 vendor/rack-1.0.0-git/lib/rack/file.rb
middleman-0.12.0.pre lib/middleman/vendor/gems/gems/rack-1.0.1/lib/rack/file.rb
rango-0.0.6 vendor/rack/lib/rack/file.rb
rango-0.1.pre vendor/rack/lib/rack/file.rb
passenger-2.2.7 vendor/rack-1.0.0-git/lib/rack/file.rb
passenger-2.2.6 vendor/rack-1.0.0-git/lib/rack/file.rb
middleman-0.10.17 vendor/gems/gems/rack-1.0.1/lib/rack/file.rb
middleman-0.10.16 vendor/gems/gems/rack-1.0.1/lib/rack/file.rb
middleman-0.10.15 vendor/gems/gems/rack-1.0.1/lib/rack/file.rb
rackjour-0.1.8 vendor/gems/gems/rack-1.0.1/lib/rack/file.rb
middleman-0.10.14 vendor/gems/gems/rack-1.0.1/lib/rack/file.rb
rack-1.0.1 lib/rack/file.rb