Problem/Motivation

The file.mime_type.guesser employs the service collector pattern to collection all services tagged as mime_type_guesser and the calls each of the guessers until one of them returns a guess. In doing so it accounts for the documented behavior of mime type guessers, as MimeTypeGuesserInterface::guess() documents the return value as:

string|null The mime type or NULL, if none could be guessed

However, the default (and only) mime type guesser in core (ExtensionMimeTypeGuesser) does not follow this behavior and itself returns a default mime type (application/octet-stream) if the extension of the file is not a known one. Thus, any mime type guesser that would otherwise come afterwards is ignored.

The concrete use case is to employ Symfony's FileBinaryMimeTypeGuesser to determine the file's mime type by introspecting the file itself. The service collector pattern suggests that this should be easily possible, but it is not.

Proposed resolution

No longer return a default value from ExtensionMimeTypeGuesser::guess(). Note that because this is a behavioral change, this is targeted for 9.1, even though it is a bug report. (This assessment was not coordinated with release managers and, thus, may be invalid in either direction.)

The default value could either be returned by the service collector itself, if none of the guessers returned anything, or we could add a FallbackMimeTypeGuesser that always returns the default and has a very low priority allowing others to intervene before the fallback, but after ExtensionMimeTypeGuesser.

Issue fork drupal-3156672

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

tstoeckler created an issue. See original summary.

tstoeckler’s picture

Note that I added #3055193: [Symfony 5] The "Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser" class is deprecated since Symfony 4.3, use "Symfony\Component\Mime\MimeTypes" instead. as a related issue because it touches the same code that would/will be touched here and seems likely to land in the near future, but as far as I can tell it is orthogonal in the sense that that would not actually fix this issue or require a different fix here.

tstoeckler’s picture

Issue summary: View changes
tstoeckler’s picture

Found #2388749: Register symfony's mime guessers if they are supported which is related to the use-case in the issue summary. In that patch the binary mime type guesser has a higher priority than the extension one, which is why this issue hasn't come up, I assume.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

pieterdc’s picture

Status: Active » Needs review
StatusFileSize
new409 bytes

Thanks for sharing this info.
I created a small patch to make ExtensionMimeTypeGuesser::guess() adhere to its interface.
This will probably break some existing tests but it does fix the fallback to other mime_type_guesser services.

Status: Needs review » Needs work

The last submitted patch, 6: 3156672-6.patch, failed testing. View results

pieterdc’s picture

The failed tests need fixing.

Next to the already outlined benefit (in the ticket description), this change also allows to differentiate between a detected (guessed) 'application/octet-stream' mime type and no detected one.

longwave’s picture

we could add a FallbackMimeTypeGuesser that always returns the default and has a very low priority allowing others to intervene before the fallback

This seems like the best approach, as it avoids breaking backward compatibility while fixing this issue. Sites could also opt out by removing the fallback service if they wanted to for some reason.

We could also add a deprecation warning if the fallback is triggered to warn users that the default will be removed in Drupal 10.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

longwave’s picture

Status: Needs work » Needs review
StatusFileSize
new4.07 KB

Implemented a fallback guesser so other guessers can be inserted in the chain.

The existing test conveniently covers both the full chain and the existing extension guesser in separate cases so we can reuse that to test both the fallback and the NULL return.

The NULL return also means we have to fix the return type in the proxy class at the same time, which is currently missing the nullable part.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

pieterdc’s picture

Testing a patch from this issue with Drupal core 9.4.x, you also need the patch from #3190265-28: guessMimeType declaration not compatible with Symfony interface otherwise Drupal won't allow a NULL return value.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new144 bytes

The Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

joegraduate made their first commit to this issue’s fork.

joegraduate’s picture

Status: Needs work » Needs review

Re-rolled #11 in MR !8288.

smustgrave’s picture

Status: Needs review » Needs work

For backwards compatibility concern can we add a deprecation for the return with a CR that says in D12 it will return null.

joegraduate’s picture

Issue tags: +Needs change record
kim.pepper’s picture

As per https://www.drupal.org/about/core/policies/core-change-policies/drupal-d... we can't really trigger a deprecation warning or use the @deprecated annotation. Instead we need to document the behaviour change in the docblock, and add a @todo to switch to returning NULL in the next major.

kim.pepper’s picture

For example:

   * @return string|null
   *   The mime type or NULL, if none could be guessed.
   *   For BC, this currently returns 'application/octet-stream' when none could
   *   be guessed but will return NULL in drupal:12.0.0.

and // @todo https://www.drupal.org/node/3156672 Return NULL in Drupal 12.0.0.

kim.pepper’s picture

Status: Needs work » Needs review

Tried a new approach to add a constructor param to trigger a deprecation.

kim.pepper’s picture

Hiding patch files

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs change record

Changed deprecation to 12 vs 11. But deprecation looks good.

longwave’s picture

Why do we need the deprecation here? The fallback means the end result is the same if you use the mime type guesser service properly, IMHO if you are calling file.mime_type.guesser.extension directly you are on your own.

kim.pepper’s picture

@longwave I thought we were doing this issue to fix the problem of guessers that come after.

Thus, any mime type guesser that would otherwise come afterwards is ignored.

However, I think we can use priority to allow workarounds.

Reverted.

kim.pepper’s picture

Hmm. I'm having second thoughts about reverting. I think we need to return NULL.

kim.pepper’s picture

Sorry for all the noise. I think I went back and forth with this too many times, and made changes I shouldn't have.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

I'm wondering whether adding a fallback guesser is really necessary and whether the best place to add the fallback is in \Drupal\Core\File\MimeType\MimeTypeGuesser::guessMimeType()

kim.pepper’s picture

Status: Needs work » Needs review

Agree there is no need for a FallbackMimeTypeGuesser if we can return 'application/octet-stream' by default from \Drupal\Core\File\MimeType\MimeTypeGuesser::guessMimeType()

tstoeckler’s picture

Status: Needs review » Reviewed & tested by the community

I don't really have an opinion on which approach is better, but this looks good to me as well. Updated the change notice for the new approach, so as far as I can tell this is good to go again.

alexpott’s picture

@tstoeckler the advantage of this approach is now we don't need to be concerned with enforcing which mime type guesser comes last. Also less services.

  • longwave committed 2d42a30b on 10.4.x
    Issue #3156672 by kim.pepper, joegraduate, longwave, PieterDC,...
longwave’s picture

Version: 11.x-dev » 10.4.x-dev
Status: Reviewed & tested by the community » Fixed

Given this is a bug fix but also a minor behaviour change let's not commit this to 10.3, but I think it can go in 10.4 and 11.0.

Committed and pushed cc9baee953 to 11.x and 98eea842a3 to 11.0.x and 2d42a30bba to 10.4.x. Thanks!

Will update and publish the change record.

  • longwave committed 98eea842 on 11.0.x
    Issue #3156672 by kim.pepper, joegraduate, longwave, PieterDC,...

  • longwave committed cc9baee9 on 11.x
    Issue #3156672 by kim.pepper, joegraduate, longwave, PieterDC,...

  • xjm committed 61cc0660 on 10.3.x authored by longwave
    Issue #3156672 by kim.pepper, joegraduate, longwave, PieterDC,...
xjm’s picture

Discussed with @longwave and @alexpott. It's weird to have a behavior change of any kind in 10.4 and 11.0 but not 10.3 -- 10.4 is supposed to be a maintenance minor that limits disruptive bugfixes, and 11.0 is almost-RC-ish as of the week this was committed.

We agreed the disruption is minimal enough to backport to 10.3.x, which resolves potential 10.3/11.0 parity issues with this API. There is a CR, so the few projects that might be affected can get the info they need.

If this does cause more serious issues for contrib or sites, please open a followup issue linking this one and tag it "Contributed project blocker" if appropriate. Thanks!

mondrake’s picture

FTR, Sophron module was adjusted to mirror this.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

mxr576’s picture

FTR, fixing this issue created an E_DEPRECATED warning elsewhere which has not been spotted by the test suite on D.o: #3466462: Fix handling of unknown file extensions in FileMediaFormatterBase

Although it breaks functional tests on downstream... ;S #3467081: E_DEPRECATED warnings makes functional tests fail

xjm’s picture

Amending attribution.