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

- (FileResponse) initialize(env, filename, content_type = nil)

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

- (String) filename (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| ... }

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

- (Array) finish

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

- (Boolean) found?

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