Description
Symfony version(s) affected
5.4.13
Description
Since this PR, it is not possible to let the BinaryFileResponse object guess the Content-Type
header in the prepare
method. The current problem showed up when I updated my project from 5.4.12 to 5.4.13 and this code stopped working:
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class BugController extends AbstractController
{
/**
* @Route(path="/bug", name="bug")
*/
public function bug(): Response
{
$pdfPath = sprintf('%s/pdf/%s', $this->getParameter('kernel.project_dir'), 'demo.pdf'); // I have a pdf folder with a demo.pdf in it
return new BinaryFileResponse($pdfPath);
}
}
Instead of having my PDF displayed in the browser (screen 1), I have a strange result (screen 2).
When I looked at the response's headers, I noticed that in 5.4.13 the Content-Type
is set to text/html; charset=UTF-8
(Cf screen 2). Unlike in 5.4.12, it is set to application/pdf
How to reproduce
symfony new reproduce --version="5.4"
- Ensure that you have "symfony/http-foundation": "5.4.13"
composer require doctrine/annotations
composer require symfony/mime
php -S 127.0.0.1:8080 -t reproduce/public/
- Create a new Controller with the following code :
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class BugController extends AbstractController
{
/**
* @Route(path="/bug", name="bug")
*/
public function bug(): Response
{
$pdfPath = sprintf('%s/pdf/%s', $this->getParameter('kernel.project_dir'), 'demo.pdf');
return new BinaryFileResponse($pdfPath);
}
}
- Browse to 127.0.0.1:8080/bug
You should have the same result as on screen 2
If you try the same steps but with "symfony/http-foundation": "5.4.12" it should work as screen 1
Possible Solution
Here is a quick solution that comes up in my mind :
We just need to change the beginning of the BinaryFileResponse's prepare
method to check if we are in a case where we can guess the Content Type
header, then we call Response::prepare
method. Thanks to this we keep this FIX and also the behavior of guessing the Content Type
of the file to serve.
class BinaryFileResponse extends Response
{
.....
/**
* {@inheritdoc}
*/
public function prepare(Request $request)
{
$isInformativeOrEmpty = $this->isInformational() || $this->isEmpty();
if (!$isInformativeOrEmpty && !$this->headers->has('Content-Type')) {
$this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream');
}
parent::prepare($request);
if ($isInformativeOrEmpty) {
$this->maxlen = 0;
return $this;
}
// We can keep the rest of the method...
}
}