From 381bd7e2353f6573b534d8e66f622494da95be4d Mon Sep 17 00:00:00 2001 From: Jakub Zalas Date: Sat, 9 Feb 2013 16:37:25 +0100 Subject: [PATCH] [HttpFoundation] Added support for partial ranges in the BinaryFileResponse. Valid ranges include: * bytes=0-499 * bytes=500-999 * bytes=-500 * bytes=9500- * bytes=0-0 --- .../HttpFoundation/BinaryFileResponse.php | 18 +++++++---- .../Tests/BinaryFileResponseTest.php | 30 +++++++++++++++++-- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php index 5c2bf48877..cb6c8a1e8a 100644 --- a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php +++ b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php @@ -195,19 +195,27 @@ class BinaryFileResponse extends Response // Process the range headers. if (!$request->headers->has('If-Range') || $this->getEtag() == $request->headers->get('If-Range')) { $range = $request->headers->get('Range'); + $fileSize = $this->file->getSize(); - list($start, $end) = array_map('intval', explode('-', substr($range, 6), 2)) + array(0); + list($start, $end) = explode('-', substr($range, 6), 2) + array(0); - if ('' !== $end) { - $this->maxlen = $end - $start + 1; + $end = ('' === $end) ? $fileSize - 1 : (int) $end; + + if ('' === $start) { + $start = $fileSize - $end; + $end = $fileSize - 1; } else { - $end = $this->file->getSize() - 1; + $start = (int) $start; } + $start = max($start, 0); + $end = min($end, $fileSize - 1); + + $this->maxlen = $end < $fileSize ? $end - $start + 1 : -1; $this->offset = $start; $this->setStatusCode(206); - $this->headers->set('Content-Range', sprintf('bytes %s-%s/%s', $start, $end, $this->file->getSize())); + $this->headers->set('Content-Range', sprintf('bytes %s-%s/%s', $start, $end, $fileSize)); } } diff --git a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php index 4f749a1ef0..4d517313f3 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php @@ -47,7 +47,10 @@ class BinaryFileResponseTest extends \PHPUnit_Framework_TestCase $this->assertFalse($response->getContent()); } - public function testRequests() + /** + * @dataProvider provideRanges + */ + public function testRequests($requestRange, $offset, $length, $responseRange) { $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif')->setAutoEtag(); @@ -59,14 +62,35 @@ class BinaryFileResponseTest extends \PHPUnit_Framework_TestCase // prepare a request for a range of the testing file $request = Request::create('/'); $request->headers->set('If-Range', $etag); - $request->headers->set('Range', 'bytes=1-4'); + $request->headers->set('Range', $requestRange); - $this->expectOutputString('IF87'); + $file = fopen(__DIR__.'/File/Fixtures/test.gif', 'r'); + fseek($file, $offset); + $data = fread($file, $length); + fclose($file); + + $this->expectOutputString($data); $response = clone $response; $response->prepare($request); $response->sendContent(); + $this->assertEquals(206, $response->getStatusCode()); $this->assertEquals('binary', $response->headers->get('Content-Transfer-Encoding')); + $this->assertEquals($responseRange, $response->headers->get('Content-Range')); + } + + public function provideRanges() + { + return array( + array('bytes=1-4', 1, 4, 'bytes 1-4/35'), + array('bytes=-5', 30, 5, 'bytes 30-34/35'), + array('bytes=-35', 0, 35, 'bytes 0-34/35'), + array('bytes=-40', 0, 35, 'bytes 0-34/35'), + array('bytes=30-', 30, 5, 'bytes 30-34/35'), + array('bytes=30-30', 30, 1, 'bytes 30-30/35'), + array('bytes=30-34', 30, 5, 'bytes 30-34/35'), + array('bytes=30-40', 30, 5, 'bytes 30-34/35') + ); } public function testXSendfile()