Class: Closure::FileResponse

Inherits:
Object
  • Object
show all
Defined in:
lib/closure/file_response.rb

Overview

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env, filename, content_type = nil) ⇒ FileResponse

Returns a new instance of FileResponse.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 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

Instance Attribute Details

#filenameString (readonly) Also known as: to_path

Filename attribute. Alias is used by some rack servers to detach from Ruby early.

Returns:

  • (String)


74
75
76
# File 'lib/closure/file_response.rb', line 74

def filename
  @filename
end

Instance Method Details

#each {|String| ... } ⇒ Object

Support using self as a response body.

Yields:

  • (String)

    8k blocks



63
64
65
66
67
68
69
# 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

#finishArray

Present the final response for rack.

Returns:

  • (Array)
    status, headers, body


84
85
86
# File 'lib/closure/file_response.rb', line 84

def finish
  [@status, @headers, @body]
end

#found?Boolean

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

Returns:

  • (Boolean)


78
79
80
# File 'lib/closure/file_response.rb', line 78

def found?
  @status == 200 or @status == 304
end