Skip to content

Commit

Permalink
[HttpFoundation] Prevent BinaryFileResponse::prepare from adding cont…
Browse files Browse the repository at this point in the history
…ent type if no content is sent
  • Loading branch information
stollr authored and fabpot committed Sep 13, 2022
1 parent 935f796 commit 7acdc97
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 31 deletions.
71 changes: 40 additions & 31 deletions BinaryFileResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,22 +201,25 @@ 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 comment has been minimized.

Copy link
@daniser

daniser Oct 5, 2022

Since parent::prepare() always sets Content-Type header, this check always returns false.

This comment has been minimized.

Copy link
@adrienprioul

adrienprioul Oct 10, 2022

This is actually a breaking change as the content-type will never be set according to file mime type. I have opened an issue about this.

$this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream');
}

$this->offset = 0;
$this->maxlen = -1;

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')) {
Expand Down Expand Up @@ -286,6 +289,10 @@ public function prepare(Request $request)
}
}

if ($request->isMethod('HEAD')) {
$this->maxlen = 0;
}

return $this;
}

Expand All @@ -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;
Expand Down
15 changes: 15 additions & 0 deletions Tests/BinaryFileResponseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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']);
Expand Down

0 comments on commit 7acdc97

Please sign in to comment.