diff --git a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php index c2f66d6952..0a43b8ac71 100644 --- a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php +++ b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php @@ -239,33 +239,36 @@ class BinaryFileResponse extends Response $this->headers->set($type, $path); $this->maxlen = 0; } - } elseif ($request->headers->has('Range')) { + } elseif ($request->headers->has('Range') && $request->isMethod('GET')) { // Process the range headers. if (!$request->headers->has('If-Range') || $this->hasValidIfRangeHeader($request->headers->get('If-Range'))) { $range = $request->headers->get('Range'); - list($start, $end) = explode('-', substr($range, 6), 2) + [0]; + if (0 === strpos($range, 'bytes=')) { + list($start, $end) = explode('-', substr($range, 6), 2) + [0]; - $end = ('' === $end) ? $fileSize - 1 : (int) $end; + $end = ('' === $end) ? $fileSize - 1 : (int) $end; - if ('' === $start) { - $start = $fileSize - $end; - $end = $fileSize - 1; - } else { - $start = (int) $start; - } + if ('' === $start) { + $start = $fileSize - $end; + $end = $fileSize - 1; + } else { + $start = (int) $start; + } - if ($start <= $end) { - if ($start < 0 || $end > $fileSize - 1) { - $this->setStatusCode(416); - $this->headers->set('Content-Range', sprintf('bytes */%s', $fileSize)); - } elseif (0 !== $start || $end !== $fileSize - 1) { - $this->maxlen = $end < $fileSize ? $end - $start + 1 : -1; - $this->offset = $start; + if ($start <= $end) { + $end = min($end, $fileSize - 1); + if ($start < 0 || $start > $end) { + $this->setStatusCode(416); + $this->headers->set('Content-Range', sprintf('bytes */%s', $fileSize)); + } elseif ($end - $start < $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, $fileSize)); - $this->headers->set('Content-Length', $end - $start + 1); + $this->setStatusCode(206); + $this->headers->set('Content-Range', sprintf('bytes %s-%s/%s', $start, $end, $fileSize)); + $this->headers->set('Content-Length', $end - $start + 1); + } } } } diff --git a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php index 31916fc7d6..38cc84420c 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php @@ -149,6 +149,7 @@ class BinaryFileResponseTest extends ResponseTestCase ['bytes=30-', 30, 5, 'bytes 30-34/35'], ['bytes=30-30', 30, 1, 'bytes 30-30/35'], ['bytes=30-34', 30, 5, 'bytes 30-34/35'], + ['bytes=30-40', 30, 5, 'bytes 30-34/35'], ]; } @@ -203,9 +204,31 @@ class BinaryFileResponseTest extends ResponseTestCase // Syntactical invalid range-request should also return the full resource ['bytes=20-10'], ['bytes=50-40'], + // range units other than bytes must be ignored + ['unknown=10-20'], ]; } + public function testRangeOnPostMethod() + { + $request = Request::create('/', 'POST'); + $request->headers->set('Range', 'bytes=10-20'); + $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, ['Content-Type' => 'application/octet-stream']); + + $file = fopen(__DIR__.'/File/Fixtures/test.gif', 'r'); + $data = fread($file, 35); + fclose($file); + + $this->expectOutputString($data); + $response = clone $response; + $response->prepare($request); + $response->sendContent(); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame('35', $response->headers->get('Content-Length')); + $this->assertNull($response->headers->get('Content-Range')); + } + public function testUnpreparedResponseSendsFullFile() { $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200); @@ -242,7 +265,7 @@ class BinaryFileResponseTest extends ResponseTestCase { return [ ['bytes=-40'], - ['bytes=30-40'], + ['bytes=40-50'], ]; }