From 7acdc97f28a48b96def93af1efd77cfc5e8776dd Mon Sep 17 00:00:00 2001 From: naitsirch Date: Wed, 7 Sep 2022 21:28:33 +0200 Subject: [PATCH] [HttpFoundation] Prevent BinaryFileResponse::prepare from adding content type if no content is sent --- BinaryFileResponse.php | 71 ++++++++++++++++++-------------- Tests/BinaryFileResponseTest.php | 15 +++++++ 2 files changed, 55 insertions(+), 31 deletions(-) diff --git a/BinaryFileResponse.php b/BinaryFileResponse.php index f44eb6daf..2cd105c3b 100644 --- a/BinaryFileResponse.php +++ b/BinaryFileResponse.php @@ -201,15 +201,17 @@ public function setContentDisposition($disposition, $filename = '', $filenameFal */ public function prepare(Request $request) { - if (!$this->headers->has('Content-Type')) { - $this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream'); - } + parent::prepare($request); - if ('HTTP/1.0' !== $request->server->get('SERVER_PROTOCOL')) { - $this->setProtocolVersion('1.1'); + if ($this->isInformational() || $this->isEmpty()) { + $this->maxlen = 0; + + return $this; } - $this->ensureIEOverSSLCompatibility($request); + if (!$this->headers->has('Content-Type')) { + $this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream'); + } $this->offset = 0; $this->maxlen = -1; @@ -217,6 +219,7 @@ public function prepare(Request $request) if (false === $fileSize = $this->file->getSize()) { return $this; } + $this->headers->remove('Transfer-Encoding'); $this->headers->set('Content-Length', $fileSize); if (!$this->headers->has('Accept-Ranges')) { @@ -286,6 +289,10 @@ public function prepare(Request $request) } } + if ($request->isMethod('HEAD')) { + $this->maxlen = 0; + } + return $this; } @@ -309,40 +316,42 @@ private function hasValidIfRangeHeader(?string $header): bool */ public function sendContent() { - if (!$this->isSuccessful()) { - return parent::sendContent(); - } + try { + if (!$this->isSuccessful()) { + return parent::sendContent(); + } - if (0 === $this->maxlen) { - return $this; - } + if (0 === $this->maxlen) { + return $this; + } - $out = fopen('php://output', 'w'); - $file = fopen($this->file->getPathname(), 'r'); + $out = fopen('php://output', 'w'); + $file = fopen($this->file->getPathname(), 'r'); - ignore_user_abort(true); + ignore_user_abort(true); - if (0 !== $this->offset) { - fseek($file, $this->offset); - } + if (0 !== $this->offset) { + fseek($file, $this->offset); + } - $length = $this->maxlen; - while ($length && !feof($file)) { - $read = ($length > $this->chunkSize) ? $this->chunkSize : $length; - $length -= $read; + $length = $this->maxlen; + while ($length && !feof($file)) { + $read = ($length > $this->chunkSize) ? $this->chunkSize : $length; + $length -= $read; - stream_copy_to_stream($file, $out, $read); + stream_copy_to_stream($file, $out, $read); - if (connection_aborted()) { - break; + if (connection_aborted()) { + break; + } } - } - fclose($out); - fclose($file); - - if ($this->deleteFileAfterSend && file_exists($this->file->getPathname())) { - unlink($this->file->getPathname()); + fclose($out); + fclose($file); + } finally { + if ($this->deleteFileAfterSend && file_exists($this->file->getPathname())) { + unlink($this->file->getPathname()); + } } return $this; diff --git a/Tests/BinaryFileResponseTest.php b/Tests/BinaryFileResponseTest.php index f88c8a48d..4e4ddbf44 100644 --- a/Tests/BinaryFileResponseTest.php +++ b/Tests/BinaryFileResponseTest.php @@ -373,6 +373,21 @@ public function testStream() $this->assertNull($response->headers->get('Content-Length')); } + public function testPrepareNotAddingContentTypeHeaderIfNoContentResponse() + { + $request = Request::create('/'); + $request->headers->set('If-Modified-Since', date('D, d M Y H:i:s').' GMT'); + + $response = new BinaryFileResponse(__DIR__.'/File/Fixtures/test.gif', 200, ['Content-Type' => 'application/octet-stream']); + $response->setLastModified(new \DateTimeImmutable('-1 day')); + $response->isNotModified($request); + + $response->prepare($request); + + $this->assertSame(BinaryFileResponse::HTTP_NOT_MODIFIED, $response->getStatusCode()); + $this->assertFalse($response->headers->has('Content-Type')); + } + protected function provideResponse() { return new BinaryFileResponse(__DIR__.'/../README.md', 200, ['Content-Type' => 'application/octet-stream']);