From 574ffecd38b8cf0f30edb7e9b1034725905e89ee Mon Sep 17 00:00:00 2001 From: Jeremy Daer Date: Tue, 12 Sep 2023 21:46:54 -0700 Subject: [PATCH] Fix Illustrator detection as application/pdf instead of application/illustrator Given an .ai file with an application/postscript declared type, the filename extension would be ignored as a potential subtype of the application/pdf magic-byte-detected type. Fix by evaluating all candidate types rather than a single fallback. --- lib/marcel/mime_type.rb | 32 ++++++-------------------------- test/illustrator_test.rb | 9 +++++++++ 2 files changed, 15 insertions(+), 26 deletions(-) create mode 100644 test/illustrator_test.rb diff --git a/lib/marcel/mime_type.rb b/lib/marcel/mime_type.rb index 01db58e..6d7c15e 100644 --- a/lib/marcel/mime_type.rb +++ b/lib/marcel/mime_type.rb @@ -27,14 +27,8 @@ def extend(type, extensions: [], parents: [], magic: nil) # # If no type can be determined, then +application/octet-stream+ is returned. def for(pathname_or_io = nil, name: nil, extension: nil, declared_type: nil) - type_from_data = for_data(pathname_or_io) - fallback_type = for_declared_type(declared_type) || for_name(name) || for_extension(extension) || BINARY - - if type_from_data - most_specific_type type_from_data, fallback_type - else - fallback_type - end + filename_type = for_name(name) || for_extension(extension) + most_specific_type for_data(pathname_or_io), for_declared_type(declared_type), filename_type, BINARY end private @@ -66,11 +60,7 @@ def for_extension(extension) end def for_declared_type(declared_type) - type = parse_media_type(declared_type) - - if type != BINARY && !type.nil? - type.downcase - end + parse_media_type(declared_type) end def with_io(pathname_or_io, &block) @@ -91,19 +81,9 @@ def parse_media_type(content_type) # For some document types (notably Microsoft Office) we recognise the main content # type with magic, but not the specific subclass. In this situation, if we can get a more # specific class using either the name or declared_type, we should use that in preference - def most_specific_type(from_magic_type, fallback_type) - if (root_types(from_magic_type) & root_types(fallback_type)).any? - fallback_type - else - from_magic_type - end - end - - def root_types(type) - if TYPE_EXTS[type].nil? || TYPE_PARENTS[type].nil? - [ type ] - else - TYPE_PARENTS[type].map {|t| root_types t }.flatten + def most_specific_type(*candidates) + candidates.compact.uniq.reduce do |type, candidate| + Marcel::Magic.child?(candidate, type) ? candidate : type end end end diff --git a/test/illustrator_test.rb b/test/illustrator_test.rb new file mode 100644 index 0000000..9831d67 --- /dev/null +++ b/test/illustrator_test.rb @@ -0,0 +1,9 @@ +require 'test_helper' +require 'rack' + +class Marcel::MimeType::IllustratorTest < Marcel::TestCase + test ".ai uploaded as application/postscript" do + file = files("name/application/illustrator/illustrator.ai") + assert_equal "application/illustrator", Marcel::MimeType.for(file, name: "illustrator.ai", declared_type: "application/postscript") + end +end