Skip to content

Fix directory path served as file in \Magento\MediaStorage\App\Media#40516

Open
DmitryFurs wants to merge 1 commit intomagento:2.4-developfrom
DmitryFurs:fix/media-directory-served-as-file
Open

Fix directory path served as file in \Magento\MediaStorage\App\Media#40516
DmitryFurs wants to merge 1 commit intomagento:2.4-developfrom
DmitryFurs:fix/media-directory-served-as-file

Conversation

@DmitryFurs
Copy link
Contributor

@DmitryFurs DmitryFurs commented Feb 6, 2026

Description

Magento\MediaStorage\App\Media::launch() does not check whether the requested path is a file before serving it. When a directory path is requested (e.g., /media/email/logo/websites/1/), it passes isReadable() but reaches Magento\Framework\File\Transfer\Adapter\Http::send() which throws:

Exception: File '/path/pub/media/email/logo/websites/1/' does not exists.

The same bug was previously fixed in pub/get.php (line 70) with an is_dir() guard, but the equivalent check was never added to Media::launch().

This PR adds isFile() checks alongside existing isReadable() checks in two places:

  • launch() - before setting the response file path
  • createLocalCopy() - before returning early for already-synced files

Sentry Catch:
image

Related Pull Requests

Manual testing scenarios

  1. Configure an email logo at Stores > Configuration > Sales > Sales Emails > Email Logo Image
  2. Clear the resource config cache (var/resource_config.json)
  3. Send a request to the directory path without filename:
    curl -X OPTIONS https://your-store.com/media/email/logo/websites/1/
    
  4. Before fix: Exception thrown - File '...' does not exists.
  5. After fix: Placeholder image returned (no exception)

Alternative scenario:

  1. Request any media directory path (e.g., /media/catalog/product/m/a/) when var/resource_config.json is expired or missing
  2. Before fix: Exception in Http::send()
  3. After fix: Placeholder image returned gracefully

Questions or comments

The is_dir() guard in pub/get.php (line 55) was added to fix #296, but only covers the fast-path when the resource config cache is valid. When the cache is expired or missing, get.php falls through to Media::launch() which lacks this check.

Real-world trigger: Microsoft Outlook sends OPTIONS preflight requests to directory paths before loading email logo images. Access log example:

"OPTIONS /media/email/logo/websites/1/ HTTP/1.1" 200 20 "-" "Microsoft Office Outlook 2014" ← directory path, triggers the bug
[02/Feb/2026:14:25:54 -0500] "GET /media/email/logo/websites/1/logo.png HTTP/1.1" 200 2997 "-" "Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0 (via ggpht.com GoogleImageProxy)"  ← actual file, works fine
146.75.146.1 - - [02/Feb/2026:23:09:09 -0500] "GET /media/email/logo/websites/1/logo.png HTTP/1.1" 200 2997 "-" "Mozilla/5.0"   ← actual file, works fine

Outlook's OPTIONS request targets the parent directory URL (without the filename), which passes through get.php to Media::launch() and causes the exception. This is reproducible with any email client that sends preflight requests to media URLs.

Contribution checklist (*)

  • Pull request has a meaningful description of its purpose
  • All commits are accompanied by meaningful commit messages
  • All new or changed code is covered with unit/integration tests (if applicable)
  • README.md files for modified modules are updated and included in the pull request if any README.md predefined sections require an update
  • All automated tests passed successfully (all builds are green)

Resolved issues:

  1. resolves [Issue] Fix directory path served as file in \Magento\MediaStorage\App\Media #40520: Fix directory path served as file in \Magento\MediaStorage\App\Media

@m2-assistant
Copy link

m2-assistant bot commented Feb 6, 2026

Hi @DmitryFurs. Thank you for your contribution!
Here are some useful tips on how you can test your changes using Magento test environment.
❗ Automated tests can be triggered manually with an appropriate comment:

  • @magento run all tests - run or re-run all required tests against the PR changes
  • @magento run <test-build(s)> - run or re-run specific test build(s)
    For example: @magento run Unit Tests

<test-build(s)> is a comma-separated list of build names.

Allowed build names are:
  1. Database Compare
  2. Functional Tests CE
  3. Functional Tests EE
  4. Functional Tests B2B
  5. Integration Tests
  6. Magento Health Index
  7. Sample Data Tests CE
  8. Sample Data Tests EE
  9. Sample Data Tests B2B
  10. Static Tests
  11. Unit Tests
  12. WebAPI Tests
  13. Semantic Version Checker

You can find more information about the builds here
ℹ️ Run only required test builds during development. Run all test builds before sending your pull request for review.


For more details, review the Code Contributions documentation.
Join Magento Community Engineering Slack and ask your questions in #github channel.

@engcom-Bravo
Copy link
Contributor

@magento create issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Priority: P2 A defect with this priority could have functionality issues which are not to expectations. Progress: pending review Project: Community Picked PRs upvoted by the community

Projects

Status: Pending Review

Development

Successfully merging this pull request may close these issues.

[Issue] Fix directory path served as file in \Magento\MediaStorage\App\Media Error with get.php (requesting media)

3 participants