rails/actionpack/test/controller/send_file_test.rb

209 lines
6.1 KiB
Ruby
Raw Normal View History

# encoding: utf-8
require 'abstract_unit'
module TestFileUtils
def file_name() File.basename(__FILE__) end
def file_path() File.expand_path(__FILE__) end
def file_data() @data ||= File.open(file_path, 'rb') { |f| f.read } end
end
class SendFileController < ActionController::Base
include TestFileUtils
layout "layouts/standard" # to make sure layouts don't interfere
attr_writer :options
def options
@options ||= {}
end
def file
send_file(file_path, options)
end
def data
send_data(file_data, options)
end
end
class SendFileWithActionControllerLive < SendFileController
include ActionController::Live
end
class SendFileTest < ActionController::TestCase
include TestFileUtils
def setup
@controller = SendFileController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
def test_file_nostream
@controller.options = { :stream => false }
response = nil
assert_nothing_raised { response = process('file') }
assert_not_nil response
body = response.body
assert_kind_of String, body
assert_equal file_data, body
end
def test_file_stream
response = nil
assert_nothing_raised { response = process('file') }
assert_not_nil response
assert_respond_to response.stream, :each
assert_respond_to response.stream, :to_path
2009-05-21 19:48:26 +00:00
require 'stringio'
output = StringIO.new
output.binmode
output.string.force_encoding(file_data.encoding)
response.body_parts.each { |part| output << part.to_s }
assert_equal file_data, output.string
end
def test_file_url_based_filename
@controller.options = { :url_based_filename => true }
response = nil
assert_nothing_raised { response = process('file') }
assert_not_nil response
assert_equal "attachment", response.headers["Content-Disposition"]
end
def test_data
response = nil
assert_nothing_raised { response = process('data') }
assert_not_nil response
assert_kind_of String, response.body
assert_equal file_data, response.body
end
def test_headers_after_send_shouldnt_include_charset
response = process('data')
assert_equal "application/octet-stream", response.headers["Content-Type"]
response = process('file')
assert_equal "application/octet-stream", response.headers["Content-Type"]
end
# Test that send_file_headers! is setting the correct HTTP headers.
def test_send_file_headers_bang
options = {
:type => Mime::PNG,
:disposition => 'disposition',
:filename => 'filename'
}
# Do it a few times: the resulting headers should be identical
# no matter how many times you send with the same options.
# Test resolving Ticket #458.
@controller.headers = {}
@controller.send(:send_file_headers!, options)
@controller.send(:send_file_headers!, options)
@controller.send(:send_file_headers!, options)
h = @controller.headers
assert_equal 'image/png', @controller.content_type
assert_equal 'disposition; filename="filename"', h['Content-Disposition']
assert_equal 'binary', h['Content-Transfer-Encoding']
# test overriding Cache-Control: no-cache header to fix IE open/save dialog
@controller.send(:send_file_headers!, options)
@controller.response.prepare!
assert_equal 'private', h['Cache-Control']
end
def test_send_file_headers_with_disposition_as_a_symbol
options = {
:type => Mime::PNG,
:disposition => :disposition,
:filename => 'filename'
}
@controller.headers = {}
@controller.send(:send_file_headers!, options)
assert_equal 'disposition; filename="filename"', @controller.headers['Content-Disposition']
end
def test_send_file_headers_with_mime_lookup_with_symbol
options = {
:type => :png
}
@controller.headers = {}
@controller.send(:send_file_headers!, options)
assert_equal 'image/png', @controller.content_type
end
def test_send_file_headers_with_bad_symbol
options = {
:type => :this_type_is_not_registered
}
@controller.headers = {}
Move the null mime type to request.format TLDR: always return an object that responds to the query methods from request.format, and do not touch Mime::Type[] lookup to avoid bugs. --- Long version: The initial issue was about being able to do checks like request.format.html? for request with an unknown format, where request.format would be nil. This is where the issue came from at first in #7837 and #8085 (merged in cba05887dc3b56a46a9fe2779b6b228880b49622), but the implementation went down the path of adding this to the mime type lookup logic. This unfortunately introduced subtle bugs, for instance in the merged commit a test related to send_file had to be changed to accomodate the introduction of the NullType. Later another bug was found in #13064, related to the content-type being shown as #<Mime::NullType:...> for templates with localized extensions but no format included. This one was fixed in #13133, merged in 43962d6ec50f918c9970bd3cd4b6ee5c7f7426ed. Besides that, custom handlers were not receiving the proper template formats anymore when passing through the rendering process, because of the NullType addition. That was found while migrating an application from 3.2 to 4.0 that uses the Markerb gem (a custom handler that generates both text and html emails from a markdown template). --- This changes the implementation moving away from returning this null object from the mime lookup, and still fixes the initial issue where request.format.zomg? would raise an exception for unknown formats due to request.format being nil.
2013-12-19 18:30:48 +00:00
assert_raise(ArgumentError) { @controller.send(:send_file_headers!, options) }
end
def test_send_file_headers_guess_type_from_extension
{
'image.png' => 'image/png',
'image.jpeg' => 'image/jpeg',
'image.jpg' => 'image/jpeg',
'image.tif' => 'image/tiff',
'image.gif' => 'image/gif',
'movie.mpg' => 'video/mpeg',
'file.zip' => 'application/zip',
'file.unk' => 'application/octet-stream',
'zip' => 'application/octet-stream'
}.each do |filename,expected_type|
options = { :filename => filename }
@controller.headers = {}
@controller.send(:send_file_headers!, options)
assert_equal expected_type, @controller.content_type
end
end
def test_send_file_with_default_content_disposition_header
process('data')
assert_equal 'attachment', @controller.headers['Content-Disposition']
end
def test_send_file_without_content_disposition_header
@controller.options = {:disposition => nil}
process('data')
assert_nil @controller.headers['Content-Disposition']
end
%w(file data).each do |method|
define_method "test_send_#{method}_status" do
@controller.options = { :stream => false, :status => 500 }
assert_nothing_raised { assert_not_nil process(method) }
assert_equal 500, @response.status
end
define_method "test_send_#{method}_content_type" do
@controller.options = { :stream => false, :content_type => "application/x-ruby" }
assert_nothing_raised { assert_not_nil process(method) }
assert_equal "application/x-ruby", @response.content_type
end
define_method "test_default_send_#{method}_status" do
@controller.options = { :stream => false }
assert_nothing_raised { assert_not_nil process(method) }
assert_equal 200, @response.status
end
end
def test_send_file_with_action_controller_live
@controller = SendFileWithActionControllerLive.new
@controller.options = { :content_type => "application/x-ruby" }
response = process('file')
assert_equal 200, response.status
end
end