Skip to content

Commit 99b9cc2

Browse files
committed
feature #21188 [HttpFoundation] Add File\Stream for size-unknown BinaryFileResponse (nicolas-grekas)
This PR was merged into the 3.3-dev branch. Discussion ---------- [HttpFoundation] Add File\Stream for size-unknown BinaryFileResponse | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #19738 | License | MIT | Doc PR | symfony/symfony-docs#7343 Replaces #19740. Native "getSize" is reported to return false on error, so using false as return type doesn't break the signature. Commits ------- 8011209a18 [HttpFoundation] Add File\Stream for size-unknown BinaryFileResponse
2 parents 7a4332a + bcd6c8f commit 99b9cc2

File tree

4 files changed

+51
-8
lines changed

4 files changed

+51
-8
lines changed

BinaryFileResponse.php

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,6 @@ public function setContentDisposition($disposition, $filename = '', $filenameFal
186186
*/
187187
public function prepare(Request $request)
188188
{
189-
$this->headers->set('Content-Length', $this->file->getSize());
190-
191-
if (!$this->headers->has('Accept-Ranges')) {
192-
// Only accept ranges on safe HTTP methods
193-
$this->headers->set('Accept-Ranges', $request->isMethodSafe(false) ? 'bytes' : 'none');
194-
}
195-
196189
if (!$this->headers->has('Content-Type')) {
197190
$this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream');
198191
}
@@ -206,6 +199,16 @@ public function prepare(Request $request)
206199
$this->offset = 0;
207200
$this->maxlen = -1;
208201

202+
if (false === $fileSize = $this->file->getSize()) {
203+
return $this;
204+
}
205+
$this->headers->set('Content-Length', $fileSize);
206+
207+
if (!$this->headers->has('Accept-Ranges')) {
208+
// Only accept ranges on safe HTTP methods
209+
$this->headers->set('Accept-Ranges', $request->isMethodSafe(false) ? 'bytes' : 'none');
210+
}
211+
209212
if (self::$trustXSendfileTypeHeader && $request->headers->has('X-Sendfile-Type')) {
210213
// Use X-Sendfile, do not send any content.
211214
$type = $request->headers->get('X-Sendfile-Type');
@@ -237,7 +240,6 @@ public function prepare(Request $request)
237240
// Process the range headers.
238241
if (!$request->headers->has('If-Range') || $this->hasValidIfRangeHeader($request->headers->get('If-Range'))) {
239242
$range = $request->headers->get('Range');
240-
$fileSize = $this->file->getSize();
241243

242244
list($start, $end) = explode('-', substr($range, 6), 2) + array(0);
243245

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ CHANGELOG
44
3.3.0
55
-----
66

7+
* added `File\Stream`, to be passed to `BinaryFileResponse` when the size of the served file is unknown,
8+
disabling `Range` and `Content-Length` handling, switching to chunked encoding instead
79
* added the `Cookie::fromString()` method that allows to create a cookie from a
810
raw header string
911

File/Stream.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\HttpFoundation\File;
13+
14+
/**
15+
* A PHP stream of unknown size.
16+
*
17+
* @author Nicolas Grekas <[email protected]>
18+
*/
19+
class Stream extends File
20+
{
21+
/**
22+
* {@inheritdoc}
23+
*/
24+
public function getSize()
25+
{
26+
return false;
27+
}
28+
}

Tests/BinaryFileResponseTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\HttpFoundation\Tests;
1313

1414
use Symfony\Component\HttpFoundation\BinaryFileResponse;
15+
use Symfony\Component\HttpFoundation\File\Stream;
1516
use Symfony\Component\HttpFoundation\Request;
1617
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
1718
use Symfony\Component\HttpFoundation\Tests\File\FakeFile;
@@ -97,6 +98,7 @@ public function testRequests($requestRange, $offset, $length, $responseRange)
9798

9899
$this->assertEquals(206, $response->getStatusCode());
99100
$this->assertEquals($responseRange, $response->headers->get('Content-Range'));
101+
$this->assertSame($length, $response->headers->get('Content-Length'));
100102
}
101103

102104
/**
@@ -315,6 +317,15 @@ public function getSampleXAccelMappings()
315317
);
316318
}
317319

320+
public function testStream()
321+
{
322+
$request = Request::create('/');
323+
$response = new BinaryFileResponse(new Stream(__DIR__.'/../README.md'), 200, array('Content-Type' => 'text/plain'));
324+
$response->prepare($request);
325+
326+
$this->assertNull($response->headers->get('Content-Length'));
327+
}
328+
318329
protected function provideResponse()
319330
{
320331
return new BinaryFileResponse(__DIR__.'/../README.md', 200, array('Content-Type' => 'application/octet-stream'));

0 commit comments

Comments
 (0)