Skip to content

Commit

Permalink
unbreak send_file compat specs; add media_type helper
Browse files Browse the repository at this point in the history
  • Loading branch information
rtomayko committed Dec 22, 2008
1 parent ed923ca commit 1c124f5
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 28 deletions.
2 changes: 1 addition & 1 deletion compat/streaming_test.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
end end


# Deprecated. The Content-Disposition is no longer handled by sendfile. # Deprecated. The Content-Disposition is no longer handled by sendfile.
xspecify "should include a Content-Disposition header" do specify "should include a Content-Disposition header" do
get '/' do get '/' do
send_file File.dirname(__FILE__) + '/public/foo.xml' send_file File.dirname(__FILE__) + '/public/foo.xml'
end end
Expand Down
56 changes: 29 additions & 27 deletions lib/sinatra/base.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -61,43 +61,45 @@ def session
env['rack.session'] ||= {} env['rack.session'] ||= {}
end end


# Set the content type of the response body (HTTP 'Content-Type' header). # Look up a media type by file extension in Rack's mime registry.
# def media_type(type)
# The +type+ argument may be a media type (e.g., 'text/html', return type if type.nil? || type.to_s.include?('/')
# 'application/xml+atom', 'image/png') or a Symbol key into the Rack::File::MIME_TYPES[type.to_s.sub(/^\./, '')]
# Rack::File::MIME_TYPES table. end
#
# Media type parameters, such as "charset", may also be specified using the # Set the Content-Type of the response body given a media type or file
# optional hash argument: # extension.
# get '/foo.html' do
# content_type 'text/html', :charset => 'utf-8'
# "<h1>Hello World</h1>"
# end
def content_type(type, params={}) def content_type(type, params={})
mediatype = media_type = self.media_type(type)
if type.kind_of?(Symbol) fail "Unknown media type: %p" % type if media_type.nil?
Rack::File::MIME_TYPES[type.to_s]
else
type
end
fail "Invalid or undefined media type: #{type.inspect}" if mediatype.nil?
if params.any? if params.any?
params = params.collect { |kv| "%s=%s" % kv }.join(', ') params = params.collect { |kv| "%s=%s" % kv }.join(', ')
response['Content-Type'] = [mediatype, params].join(";") response['Content-Type'] = [media_type, params].join(";")
else else
response['Content-Type'] = mediatype response['Content-Type'] = media_type
end
end

# Set the Content-Disposition to "attachment" with the specified filename,
# instructing the user agents to prompt to save.
def attachment(filename=nil)
response['Content-Disposition'] = 'attachment'
if filename
params = '; filename="%s"' % File.basename(filename)
response['Content-Disposition'] << params
end end
end end


def send_file(path) # Use the contents of the file as the response body and attempt to
def send_file(path, opts={})
stat = File.stat(path) stat = File.stat(path)
last_modified stat.mtime last_modified stat.mtime
response['Content-Length'] ||= stat.size.to_s content_type media_type(opts[:type]) ||
response['Content-Type'] = media_type(File.extname(path)) ||
Rack::File::MIME_TYPES[File.extname(path)[1..-1]] ||
response['Content-Type'] || response['Content-Type'] ||
'application/octet-stream' 'application/octet-stream'
throw :halt, StaticFile.open(path, 'rb') response['Content-Length'] ||= (opts[:length] || stat.size).to_s
halt StaticFile.open(path, 'rb')
rescue Errno::ENOENT rescue Errno::ENOENT
not_found not_found
end end
Expand Down Expand Up @@ -614,7 +616,7 @@ def metadef(message, &block)
pass unless options.static? && options.public? pass unless options.static? && options.public?
path = options.public + unescape(request.path_info) path = options.public + unescape(request.path_info)
pass unless File.file?(path) pass unless File.file?(path)
send_file path send_file path, :disposition => nil
end end


error ::Exception do error ::Exception do
Expand Down
9 changes: 9 additions & 0 deletions lib/sinatra/compat.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ def headers(header=nil)
# Deprecated. Use: etag # Deprecated. Use: etag
alias :entity_tag :etag alias :entity_tag :etag


# The :disposition option is deprecated; use: #attachment. This method
# setting the Content-Transfer-Encoding header is deprecated.
def send_file(path, opts={})
opts[:disposition] = 'attachment' if !opts.key?(:disposition)
attachment opts[:filename] || path if opts[:filename] || opts[:disposition]
response['Content-Transfer-Encoding'] = 'binary' if opts[:disposition]
super(path, opts)
end

def options ; self.class.options ; end def options ; self.class.options ; end


class << self class << self
Expand Down
30 changes: 30 additions & 0 deletions test/helpers_test.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -159,6 +159,25 @@ class Test::Unit::TestCase
end end
end end


describe '#media_type' do
include Sinatra::Helpers
it "looks up media types in Rack's MIME registry" do
Rack::File::MIME_TYPES['foo'] = 'application/foo'
media_type('foo').should.equal 'application/foo'
media_type('.foo').should.equal 'application/foo'
media_type(:foo).should.equal 'application/foo'
end
it 'returns nil when given nil' do
media_type(nil).should.be.nil
end
it 'returns nil when media type not registered' do
media_type(:bizzle).should.be.nil
end
it 'returns the argument when given a media type string' do
media_type('text/plain').should.equal 'text/plain'
end
end

describe '#content_type' do describe '#content_type' do
it 'sets the Content-Type header' do it 'sets the Content-Type header' do
mock_app { mock_app {
Expand Down Expand Up @@ -201,6 +220,17 @@ class Test::Unit::TestCase
response['Content-Type'].should.equal 'application/foo' response['Content-Type'].should.equal 'application/foo'
body.should.equal 'I AM FOO' body.should.equal 'I AM FOO'
end end

it 'fails when no mime type is registered for the argument provided' do
mock_app {
get '/foo.xml' do
content_type :bizzle
"I AM FOO"
end
}

lambda { get '/foo.xml' }.should.raise RuntimeError
end
end end


describe '#send_file' do describe '#send_file' do
Expand Down

0 comments on commit 1c124f5

Please sign in to comment.