Backport range parsing resiliancy fixes from 3.x

Refs #8723
This commit is contained in:
mark_story 2016-04-28 22:27:07 -04:00
parent cbd54256e0
commit cf55767fa0
2 changed files with 69 additions and 31 deletions

View file

@ -1406,11 +1406,16 @@ class CakeResponse {
* @return void * @return void
*/ */
protected function _fileRange($file, $httpRange) { protected function _fileRange($file, $httpRange) {
list(, $range) = explode('=', $httpRange);
list($start, $end) = explode('-', $range);
$fileSize = $file->size(); $fileSize = $file->size();
$lastByte = $fileSize - 1; $lastByte = $fileSize - 1;
$start = 0;
$end = $lastByte;
preg_match('/^bytes\s*=\s*(\d+)?\s*-\s*(\d+)?$/', $httpRange, $matches);
if ($matches) {
$start = $matches[1];
$end = isset($matches[2]) ? $matches[2] : '';
}
if ($start === '') { if ($start === '') {
$start = $fileSize - $end; $start = $fileSize - $end;

View file

@ -1705,48 +1705,81 @@ class CakeResponseTest extends CakeTestCase {
$this->assertNotSame(false, $result); $this->assertNotSame(false, $result);
} }
/**
* Provider for invalid range header values.
*
* @return array
*/
public function invalidFileRangeProvider() {
return array(
// malformed range
array(
'bytes=0,38'
),
// malformed punctuation
array(
'bytes: 0 - 32'
),
array(
'garbage: poo - poo'
),
);
}
/** /**
* Test invalid file ranges. * Test invalid file ranges.
* *
* @dataProvider invalidFileRangeProvider
* @return void * @return void
*/ */
public function testFileRangeInvalid() { public function testFileRangeInvalid($range) {
$_SERVER['HTTP_RANGE'] = 'bytes=30-2'; $_SERVER['HTTP_RANGE'] = $range;
$response = $this->getMock('CakeResponse', array( $response = $this->getMock('CakeResponse', [
'header',
'type',
'_sendHeader', '_sendHeader',
'_setContentType',
'_isActive', '_isActive',
'_clearBuffer', ]);
'_flushBuffer'
));
$response->expects($this->at(1))
->method('header')
->with('Content-Disposition', 'attachment; filename="test_asset.css"');
$response->expects($this->at(2))
->method('header')
->with('Content-Transfer-Encoding', 'binary');
$response->expects($this->at(3))
->method('header')
->with('Accept-Ranges', 'bytes');
$response->expects($this->at(4))
->method('header')
->with(array(
'Content-Range' => 'bytes 0-37/38',
));
$response->file( $response->file(
CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS . 'test_asset.css', CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS . 'test_asset.css',
array('download' => true) array('download' => true)
); );
$expected = array(
'Content-Disposition' => 'attachment; filename="test_asset.css"',
'Content-Transfer-Encoding' => 'binary',
'Accept-Ranges' => 'bytes',
'Content-Range' => 'bytes 0-37/38',
'Content-Length' => 38,
);
$this->assertEquals($expected, $response->header());
}
/**
* Test backwards file range
*
* @return void
*/
public function testFileRangeReversed() {
$_SERVER['HTTP_RANGE'] = 'bytes=30-5';
$response = $this->getMock('CakeResponse', [
'_sendHeader',
'_isActive',
]);
$response->file(
CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS . 'test_asset.css',
array('download' => true)
);
$expected = array(
'Content-Disposition' => 'attachment; filename="test_asset.css"',
'Content-Transfer-Encoding' => 'binary',
'Accept-Ranges' => 'bytes',
'Content-Range' => 'bytes 0-37/38',
);
$this->assertEquals($expected, $response->header());
$this->assertEquals(416, $response->statusCode()); $this->assertEquals(416, $response->statusCode());
$response->send();
} }
/** /**