Skip to content

Commit

Permalink
[HttpFoundation] Fix Range Requests
Browse files Browse the repository at this point in the history
  • Loading branch information
BattleRattle authored and nicolas-grekas committed Oct 14, 2020
1 parent 350ce8a commit f445ee1
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 21 deletions.
43 changes: 23 additions & 20 deletions BinaryFileResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -239,33 +239,36 @@ public function prepare(Request $request)
$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;

$this->setStatusCode(206);
$this->headers->set('Content-Range', sprintf('bytes %s-%s/%s', $start, $end, $fileSize));
$this->headers->set('Content-Length', $end - $start + 1);
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);
}
}
}
}
Expand Down
25 changes: 24 additions & 1 deletion Tests/BinaryFileResponseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ public function provideRanges()
['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'],
];
}

Expand Down Expand Up @@ -203,9 +204,31 @@ public function provideFullFileRanges()
// 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);
Expand Down Expand Up @@ -242,7 +265,7 @@ public function provideInvalidRanges()
{
return [
['bytes=-40'],
['bytes=30-40'],
['bytes=40-50'],
];
}

Expand Down

0 comments on commit f445ee1

Please sign in to comment.