class Closure::FileResponse

Can be used as a Rack::Response. Provides advanced cache control.

Attributes

filename[R]

Filename attribute. Alias is used by some rack servers to detach from Ruby early. @return [String]

to_path[R]

Filename attribute. Alias is used by some rack servers to detach from Ruby early. @return [String]

Public Class Methods

new(env, filename, content_type = nil) click to toggle source
# File lib/closure/file_response.rb, line 22
def initialize(env, filename, content_type = nil)
  @env = env
  @filename = filename
  @status = 200
  @headers = {}
  @body = []
  
  begin
    raise Errno::EPERM unless File.file?(filename) and File.readable?(filename)
  rescue SystemCallError
    @body = ["404 Not Found\n"]
    @headers["Content-Length"] = @body.first.size.to_s
    @headers["Content-Type"] = "text/plain"
    @headers["X-Cascade"] = "pass"
    @status = 404
    return
  end
  
  # Caching strategy
  mod_since = Time.httpdate(env['HTTP_IF_MODIFIED_SINCE']) rescue nil
  last_modified = File.mtime(filename)
  @status = 304 and return if last_modified == mod_since
  @headers["Last-Modified"] = last_modified.httpdate
  if env['QUERY_STRING'] =~ /^[0-9]{9,10}$/ and last_modified == Time.at(env['QUERY_STRING'].to_i)
    @headers["Cache-Control"] = 'max-age=86400, public' # one day
  else
    @headers["Cache-Control"] = 'max-age=0, private, must-revalidate'
  end
  
  # Sending the file or reading an unknown length stream to send
  @body = self
  unless size = File.size?(filename)
    @body = [File.read(filename)]
    size = @body.first.respond_to?(:bytesize) ? @body.first.bytesize : @body.first.size
  end
  @headers["Content-Length"] = size.to_s
  @headers["Content-Type"] = content_type || Rack::Mime.mime_type(File.extname(filename), 'text/plain')
end

Public Instance Methods

each() { |part| ... } click to toggle source

Support using self as a response body. @yield [String] 8k blocks

# File lib/closure/file_response.rb, line 63
def each
  File.open(@filename, "rb") do |file|
    while part = file.read(8192)
      yield part
    end
  end
end
finish() click to toggle source

Present the final response for rack. @return (Array)[status, headers, body]

# File lib/closure/file_response.rb, line 84
def finish
  [@status, @headers, @body]
end
found?() click to toggle source

Was the file in the system and ready to be served?

# File lib/closure/file_response.rb, line 78
def found?
  @status == 200 or @status == 304
end