From 8011209a182e95375a36bbb9e21436d3e099e9a4 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 6 Jan 2017 20:16:16 +0100 Subject: [PATCH] [HttpFoundation] Add File\Stream for size-unknown BinaryFileResponse --- .../HttpFoundation/BinaryFileResponse.php | 18 ++++++------ .../Component/HttpFoundation/CHANGELOG.md | 2 ++ .../Component/HttpFoundation/File/Stream.php | 28 +++++++++++++++++++ .../Tests/BinaryFileResponseTest.php | 11 ++++++++ 4 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 src/Symfony/Component/HttpFoundation/File/Stream.php diff --git a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php index 825c78fedeb30..65f1529207e9f 100644 --- a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php +++ b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php @@ -186,13 +186,6 @@ public function setContentDisposition($disposition, $filename = '', $filenameFal */ public function prepare(Request $request) { - $this->headers->set('Content-Length', $this->file->getSize()); - - if (!$this->headers->has('Accept-Ranges')) { - // Only accept ranges on safe HTTP methods - $this->headers->set('Accept-Ranges', $request->isMethodSafe(false) ? 'bytes' : 'none'); - } - if (!$this->headers->has('Content-Type')) { $this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream'); } @@ -206,6 +199,16 @@ public function prepare(Request $request) $this->offset = 0; $this->maxlen = -1; + if (false === $fileSize = $this->file->getSize()) { + return $this; + } + $this->headers->set('Content-Length', $fileSize); + + if (!$this->headers->has('Accept-Ranges')) { + // Only accept ranges on safe HTTP methods + $this->headers->set('Accept-Ranges', $request->isMethodSafe(false) ? 'bytes' : 'none'); + } + if (self::$trustXSendfileTypeHeader && $request->headers->has('X-Sendfile-Type')) { // Use X-Sendfile, do not send any content. $type = $request->headers->get('X-Sendfile-Type'); @@ -237,7 +240,6 @@ public function prepare(Request $request) // Process the range headers. if (!$request->headers->has('If-Range') || $this->hasValidIfRangeHeader($request->headers->get('If-Range'))) { $range = $request->headers->get('Range'); - $fileSize = $this->file->getSize(); list($start, $end) = explode('-', substr($range, 6), 2) + array(0); diff --git a/src/Symfony/Component/HttpFoundation/CHANGELOG.md b/src/Symfony/Component/HttpFoundation/CHANGELOG.md index 2ac7204a5f494..9acffbbe7d342 100644 --- a/src/Symfony/Component/HttpFoundation/CHANGELOG.md +++ b/src/Symfony/Component/HttpFoundation/CHANGELOG.md @@ -4,6 +4,8 @@ CHANGELOG 3.3.0 ----- + * added `File\Stream`, to be passed to `BinaryFileResponse` when the size of the served file is unknown, + disabling `Range` and `Content-Length` handling, switching to chunked encoding instead * added the `Cookie::fromString()` method that allows to create a cookie from a raw header string diff --git a/src/Symfony/Component/HttpFoundation/File/Stream.php b/src/Symfony/Component/HttpFoundation/File/Stream.php new file mode 100644 index 0000000000000..69ae74c110bb8 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/File/Stream.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\File; + +/** + * A PHP stream of unknown size. + * + * @author Nicolas Grekas + */ +class Stream extends File +{ + /** + * {@inheritdoc} + */ + public function getSize() + { + return false; + } +} diff --git a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php index e4607201a2151..89e078ca2a935 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\HttpFoundation\Tests; use Symfony\Component\HttpFoundation\BinaryFileResponse; +use Symfony\Component\HttpFoundation\File\Stream; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\ResponseHeaderBag; use Symfony\Component\HttpFoundation\Tests\File\FakeFile; @@ -97,6 +98,7 @@ public function testRequests($requestRange, $offset, $length, $responseRange) $this->assertEquals(206, $response->getStatusCode()); $this->assertEquals($responseRange, $response->headers->get('Content-Range')); + $this->assertSame($length, $response->headers->get('Content-Length')); } /** @@ -315,6 +317,15 @@ public function getSampleXAccelMappings() ); } + public function testStream() + { + $request = Request::create('/'); + $response = new BinaryFileResponse(new Stream(__DIR__.'/../README.md'), 200, array('Content-Type' => 'text/plain')); + $response->prepare($request); + + $this->assertNull($response->headers->get('Content-Length')); + } + protected function provideResponse() { return new BinaryFileResponse(__DIR__.'/../README.md', 200, array('Content-Type' => 'application/octet-stream'));