diff --git a/lib/sinatra.rb b/lib/sinatra.rb index 7bf29287..8be5644a 100644 --- a/lib/sinatra.rb +++ b/lib/sinatra.rb @@ -192,8 +192,8 @@ module Sinatra def block Proc.new do - send_file Sinatra.application.options.public + - request.path_info + send_file Sinatra.application.options.public + request.path_info, + :disposition => nil end end @@ -246,7 +246,8 @@ module Sinatra # * :type - specifies an HTTP content type. # Defaults to 'application/octet-stream'. # * :disposition - specifies whether the file will be shown inline or downloaded. - # Valid values are 'inline' and 'attachment' (default). + # Valid values are 'inline' and 'attachment' (default). When set to nil, the + # Content-Disposition and Content-Transfer-Encoding headers are omitted entirely. # * :stream - whether to send the file to the user agent as it is read (true) # or to read the entire file before sending (false). Defaults to true. # * :buffer_size - specifies size (in bytes) of the buffer used to stream the file. @@ -331,9 +332,9 @@ module Sinatra private def send_file_headers!(options) - options.update(DEFAULT_SEND_FILE_OPTIONS.merge(options)) + options = DEFAULT_SEND_FILE_OPTIONS.merge(options) [:length, :type, :disposition].each do |arg| - raise ArgumentError, ":#{arg} option required" if options[arg].nil? + raise ArgumentError, ":#{arg} option required" unless options.key?(arg) end # Send a "304 Not Modified" if the last_modified option is provided and matches @@ -343,17 +344,19 @@ module Sinatra throw :halt, [ 304, '' ] if last_modified == request.env['HTTP_IF_MODIFIED_SINCE'] end - disposition = options[:disposition].dup || 'attachment' - - disposition <<= %(; filename="#{options[:filename]}") if options[:filename] - headers( 'Content-Length' => options[:length].to_s, - 'Content-Type' => options[:type].strip, # fixes a problem with extra '\r' with some browsers - 'Content-Disposition' => disposition, - 'Content-Transfer-Encoding' => 'binary' + 'Content-Type' => options[:type].strip # fixes a problem with extra '\r' with some browsers ) + # Omit Content-Disposition and Content-Transfer-Encoding headers if + # the :disposition option set to nil. + if !options[:disposition].nil? + disposition = options[:disposition].dup || 'attachment' + disposition <<= %(; filename="#{options[:filename]}") if options[:filename] + headers 'Content-Disposition' => disposition, 'Content-Transfer-Encoding' => 'binary' + end + # Fix a problem with IE 6.0 on opening downloaded files: # If Cache-Control: no-cache is set (which Rails does by default), # IE removes the file it just downloaded from its cache immediately diff --git a/test/streaming_test.rb b/test/streaming_test.rb index 197ac1b5..8449b4e3 100644 --- a/test/streaming_test.rb +++ b/test/streaming_test.rb @@ -70,6 +70,13 @@ context "Static files (by default)" do body.should.be.empty end + specify "should omit Content-Disposition headers" do + get_it('/foo.xml') + should.be.ok + headers['Content-Disposition'].should.be.nil + headers['Content-Transfer-Encoding'].should.be.nil + end + end context "SendData" do @@ -89,4 +96,17 @@ context "SendData" do body.should.equal 'asdf' end + specify "should include a Content-Disposition header" do + get '/' do + send_file File.dirname(__FILE__) + '/public/foo.xml' + end + + get_it '/' + + should.be.ok + headers['Content-Disposition'].should.not.be.nil + headers['Content-Disposition'].should.equal 'attachment; filename="foo.xml"' + headers['Content-Transfer-Encoding'].should.equal 'binary' + end + end