S3 File System Module Not Working with Media Entity Download Module? Here's the Fix
June 18, 2024Drupal Odyssey is supported by it's readers. When you purchase products or services using the links on this site, we may earn a small commission at no additional cost to you. Learn more
Recently, I was working on a project where we needed to integrate Amazon S3 to store the files uploaded to a Drupal site. Luckily, there is a well supported community module to do this already; S3 File System (also referred to as s3fs). However, the site also uses the Media Entity Download module and that is where things started going to hell in a handbasket.
The s3fs integration went as expected with no serious issues when rendering Media entities in Drupal as normal using the entity displays. However, when trying to download a media entity file that is stored in S3 using the Media Entity Download module according to the documentation, you get a WSOD or 500 error.
Before explaining the problem, we need to understand the actors in the play.
Core Media Module
The official Drupal documentation defines the Media Module in the following way.
"The core Media module manages the creation, editing, deletion, settings, and display of media entities. Media items are typically images, documents, slideshows, YouTube videos, tweets, Instagram photos, etc."
While a solid understanding of what constitutes "media" is a broad discussion, this is simple enough for our purposes. The key is that a Media Entity contains a file field and possibly other fields to further describe the media type.
S3 File System Module
The S3 File System Module lets you use any S3-compatible storage service to replace the local Drupal file storage. When this module is installed and the user uploads files to Media entities, the actual files are transparently uploaded to a S3 bucket behind the scenes. This module is suitable for both large and small sites and I find it extremely valuable for sites hosted on lower end shared hosting with limited disk space.
Media Entity Download Module
The Media Entity Download module was designed to prevent links from breaking when updating or adding new files to a Media entity. It does this by creating a specific path for the Media entity such as /media/{media_id}/download
. I've found this extremely useful when using revisions with Media entities.
The Problem
At the core of the issue is how the Media Entity Download module loads the file for the response. The module attempts to load the file in a BinaryFileResponse object. Internally, the BinaryFileResponse object looks for the file on the local system uri and not a remote url. For Drupal sites that use the S3 File System Module, this causes a 500 internal server error because the files are all on remote systems.
My Solution
Once I figured out wtf was going on, I started looking for another type of response that could be used instead of the BinaryFileResponse. In theory, as long as the Drupal controller returns a Response object or child of the Response class, it should work fine.
After searching the interweb, I came across an article on Medium by Oleksii Marakhin that discussed exactly what I was needing to do. After reading the article and thinking about how to apply it to the Media Entity Download module's download controller, the bug fix was pretty straight forward. I simply added a conditional to detect if the file scheme was a remote scheme or not. If the scheme is for a known remote file system, the controller creates a StreamedResponse object as in Oleksii's article.
The only real difference in his code and what I wrote to fix this bug was the way I added the additional headers. I had to do this because the StreamedResponse class does not have a setContentDisposition() method. We need the additional headers so we can either display the file in the browser window or force download it to the user's computer.
Current Status
I have created an issue in the project issue queue and a fork of the Media Entity Download module where I implemented the fix described above. As of the time of this post, the issue is in "needs review" status.
Questions or Ideas For Improving The Solution?
There is always more than one way to solve a problem and my solution may not be the best. If you have questions or comments about how this could be improved, I'd love to hear them. Submit them in the comments below or directly to the issue queue.
0 Comments
Login or Register to post comments.