Commit 567086e1 by Jon Yurek

Allow UploadedFileAdapter to force the use of `file`

* Based on rfc2822's commit ed05dc6b85f52ad88a83bc18e1986f3b75176740.
parent 716f1596
...@@ -40,6 +40,7 @@ require 'paperclip/attachment' ...@@ -40,6 +40,7 @@ require 'paperclip/attachment'
require 'paperclip/attachment_options' require 'paperclip/attachment_options'
require 'paperclip/storage' require 'paperclip/storage'
require 'paperclip/callbacks' require 'paperclip/callbacks'
require 'paperclip/file_command_content_type_detector'
require 'paperclip/content_type_detector' require 'paperclip/content_type_detector'
require 'paperclip/glue' require 'paperclip/glue'
require 'paperclip/errors' require 'paperclip/errors'
......
...@@ -49,18 +49,7 @@ module Paperclip ...@@ -49,18 +49,7 @@ module Paperclip
end end
def type_from_file_command def type_from_file_command
type = begin FileCommandContentTypeDetector.new(@filename).detect
# On BSDs, `file` doesn't give a result code of 1 if the file doesn't exist.
Paperclip.run("file", "-b --mime :file", :file => @filename)
rescue Cocaine::CommandLineError => e
Paperclip.log("Error while determining content type: #{e}")
SENSIBLE_DEFAULT
end
if type.nil? || type.match(/\(.*?\)/)
type = SENSIBLE_DEFAULT
end
type.split(/[:;\s]+/)[0]
end end
end end
......
module Paperclip
class FileCommandContentTypeDetector
SENSIBLE_DEFAULT = "application/octet-stream"
def initialize(filename)
@filename = filename
end
def detect
type_from_file_command
end
private
def type_from_file_command
type = begin
# On BSDs, `file` doesn't give a result code of 1 if the file doesn't exist.
Paperclip.run("file", "-b --mime :file", :file => @filename)
rescue Cocaine::CommandLineError => e
Paperclip.log("Error while determining content type: #{e}")
SENSIBLE_DEFAULT
end
if type.nil? || type.match(/\(.*?\)/)
type = SENSIBLE_DEFAULT
end
type.split(/[:;\s]+/)[0]
end
end
end
...@@ -11,13 +11,29 @@ module Paperclip ...@@ -11,13 +11,29 @@ module Paperclip
end end
end end
class << self
attr_accessor :content_type_detector
end
private private
def cache_current_values def cache_current_values
@original_filename = @target.original_filename @original_filename = @target.original_filename
@content_type = @target.content_type.to_s.strip @content_type = determine_content_type
@size = File.size(@target.path) @size = File.size(@target.path)
end end
def content_type_detector
self.class.content_type_detector
end
def determine_content_type
content_type = @target.content_type.to_s.strip
if content_type_detector
content_type = content_type_detector.new(@target.path).detect
end
content_type
end
end end
end end
......
...@@ -37,10 +37,4 @@ class ContentTypeDetectorTest < Test::Unit::TestCase ...@@ -37,10 +37,4 @@ class ContentTypeDetectorTest < Test::Unit::TestCase
assert_equal "application/octet-stream", Paperclip::ContentTypeDetector.new(@filename).detect assert_equal "application/octet-stream", Paperclip::ContentTypeDetector.new(@filename).detect
end end
end end
should 'return a sensible default on the odd change that run returns nil' do
Paperclip.stubs(:run).returns(nil)
assert_equal "application/octet-stream",
Paperclip::ContentTypeDetector.new("windows").detect
end
end end
require './test/helper'
class FileCommandContentTypeDetectorTest < Test::Unit::TestCase
should 'return a content type based on the content of the file' do
tempfile = Tempfile.new("something")
tempfile.write("This is a file.")
tempfile.rewind
assert_equal "text/plain", Paperclip::FileCommandContentTypeDetector.new(tempfile.path).detect
end
should 'return a sensible default when the file command is missing' do
Paperclip.stubs(:run).raises(Cocaine::CommandLineError.new)
@filename = "/path/to/something"
assert_equal "application/octet-stream",
Paperclip::FileCommandContentTypeDetector.new(@filename).detect
end
should 'return a sensible default on the odd chance that run returns nil' do
Paperclip.stubs(:run).returns(nil)
assert_equal "application/octet-stream",
Paperclip::FileCommandContentTypeDetector.new("windows").detect
end
end
...@@ -4,13 +4,15 @@ class UploadedFileAdapterTest < Test::Unit::TestCase ...@@ -4,13 +4,15 @@ class UploadedFileAdapterTest < Test::Unit::TestCase
context "a new instance" do context "a new instance" do
context "with UploadedFile responding to #tempfile" do context "with UploadedFile responding to #tempfile" do
setup do setup do
Paperclip::UploadedFileAdapter.content_type_detector = nil
class UploadedFile < OpenStruct; end class UploadedFile < OpenStruct; end
tempfile = File.new(fixture_file("5k.png")) tempfile = File.new(fixture_file("5k.png"))
tempfile.binmode tempfile.binmode
@file = UploadedFile.new( @file = UploadedFile.new(
:original_filename => "5k.png", :original_filename => "5k.png",
:content_type => "image/png\r", :content_type => "image/x-png-by-browser\r",
:head => "", :head => "",
:tempfile => tempfile, :tempfile => tempfile,
:path => tempfile.path :path => tempfile.path
...@@ -27,7 +29,7 @@ class UploadedFileAdapterTest < Test::Unit::TestCase ...@@ -27,7 +29,7 @@ class UploadedFileAdapterTest < Test::Unit::TestCase
end end
should "get the content type" do should "get the content type" do
assert_equal "image/png", @subject.content_type assert_equal "image/x-png-by-browser", @subject.content_type
end end
should "get the file's size" do should "get the file's size" do
...@@ -52,10 +54,12 @@ class UploadedFileAdapterTest < Test::Unit::TestCase ...@@ -52,10 +54,12 @@ class UploadedFileAdapterTest < Test::Unit::TestCase
context "with UploadFile responding to #path" do context "with UploadFile responding to #path" do
setup do setup do
Paperclip::UploadedFileAdapter.content_type_detector = nil
class UploadedFile < OpenStruct; end class UploadedFile < OpenStruct; end
@file = UploadedFile.new( @file = UploadedFile.new(
:original_filename => "5k.png", :original_filename => "5k.png",
:content_type => "image/png", :content_type => "image/x-png-by-browser",
:head => "", :head => "",
:path => fixture_file("5k.png") :path => fixture_file("5k.png")
) )
...@@ -71,7 +75,7 @@ class UploadedFileAdapterTest < Test::Unit::TestCase ...@@ -71,7 +75,7 @@ class UploadedFileAdapterTest < Test::Unit::TestCase
end end
should "get the content type" do should "get the content type" do
assert_equal "image/png", @subject.content_type assert_equal "image/x-png-by-browser", @subject.content_type
end end
should "get the file's size" do should "get the file's size" do
...@@ -94,6 +98,26 @@ class UploadedFileAdapterTest < Test::Unit::TestCase ...@@ -94,6 +98,26 @@ class UploadedFileAdapterTest < Test::Unit::TestCase
assert expected.length > 0 assert expected.length > 0
assert_equal expected, @subject.read assert_equal expected, @subject.read
end end
context "don't trust client-given MIME type" do
setup do
Paperclip::UploadedFileAdapter.content_type_detector =
Paperclip::FileCommandContentTypeDetector
class UploadedFile < OpenStruct; end
@file = UploadedFile.new(
:original_filename => "5k.png",
:content_type => "image/x-png-by-browser",
:head => "",
:path => fixture_file("5k.png")
)
@subject = Paperclip.io_adapters.for(@file)
end
should "get the content type" do
assert_equal "image/png", @subject.content_type
end
end
end end
end end
end end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment