use Rack::File for serving static files

This commit is contained in:
Konstantin Haase 2011-05-27 10:19:45 +02:00
parent 3233c16ee6
commit 8d6a1b35bb
1 changed files with 7 additions and 51 deletions

View File

@ -187,9 +187,6 @@ module Sinatra
# Use the contents of the file at +path+ as the response body. # Use the contents of the file at +path+ as the response body.
def send_file(path, opts={}) def send_file(path, opts={})
stat = File.stat(path)
last_modified(opts[:last_modified] || stat.mtime)
if opts[:type] or not response['Content-Type'] if opts[:type] or not response['Content-Type']
content_type opts[:type] || File.extname(path), :default => 'application/octet-stream' content_type opts[:type] || File.extname(path), :default => 'application/octet-stream'
end end
@ -200,58 +197,17 @@ module Sinatra
response['Content-Disposition'] = 'inline' response['Content-Disposition'] = 'inline'
end end
file_length = opts[:length] || stat.size last_modified opts[:last_modified] if opts[:last_modified]
sf = StaticFile.open(path, 'rb')
if ! sf.parse_ranges(env, file_length) file = Rack::File.new nil
response['Content-Range'] = "bytes */#{file_length}" file.path = path
halt 416 result = file.serving env
elsif r=sf.range result[1].each { |k,v| headers[k] ||= v }
response['Content-Range'] = "bytes #{r.begin}-#{r.end}/#{file_length}" halt result[0], result[2]
response['Content-Length'] = (r.end - r.begin + 1).to_s
halt 206, sf
else
response['Content-Length'] ||= file_length.to_s
halt sf
end
rescue Errno::ENOENT rescue Errno::ENOENT
not_found not_found
end end
# Rack response body used to deliver static files. The file contents are
# generated iteratively in 8K chunks.
class StaticFile < ::File #:nodoc:
alias_method :to_path, :path
attr_accessor :range # a Range or nil
# Checks for byte-ranges in the request and sets self.range appropriately.
# Returns false if the ranges are unsatisfiable and the request should return 416.
def parse_ranges(env, size)
r = Rack::Utils.byte_ranges(env, size)
return false if r == [] # Unsatisfiable; report error
@range = r[0] if r && r.length == 1 # Ignore multiple-range requests for now
return true
end
CHUNK_SIZE = 8192
def each
if @range
self.pos = @range.begin
length = @range.end - @range.begin + 1
while length > 0 && (buf = read([CHUNK_SIZE,length].min))
yield buf
length -= buf.length
end
else
rewind
while buf = read(CHUNK_SIZE)
yield buf
end
end
end
end
# Specify response freshness policy for HTTP caches (Cache-Control header). # Specify response freshness policy for HTTP caches (Cache-Control header).
# Any number of non-value directives (:public, :private, :no_cache, # Any number of non-value directives (:public, :private, :no_cache,
# :no_store, :must_revalidate, :proxy_revalidate) may be passed along with # :no_store, :must_revalidate, :proxy_revalidate) may be passed along with