Sha256: 134a44c02c998d5fca412929824b1702e4c96e965a328f52f2d099a303ae197b

Contents?: true

Size: 1.85 KB

Versions: 2

Compression:

Stored size: 1.85 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)
      return forbidden  if env["PATH_INFO"].include? ".."

      @path = F.join(@root, Utils.unescape(env["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}\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

2 entries across 2 versions & 1 rubygems

Version Path
kastner-rack-0.3.171 lib/rack/file.rb
kastner-rack-0.3.186 lib/rack/file.rb