You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
330 lines
11 KiB
330 lines
11 KiB
<?php |
|
|
|
/* |
|
* This file is part of the Symfony package. |
|
* |
|
* (c) Fabien Potencier <fabien@symfony.com> |
|
* |
|
* For the full copyright and license information, please view the LICENSE |
|
* file that was distributed with this source code. |
|
*/ |
|
|
|
namespace Symfony\Component\HttpFoundation\Tests; |
|
|
|
use Symfony\Component\HttpFoundation\BinaryFileResponse; |
|
use Symfony\Component\HttpFoundation\Request; |
|
use Symfony\Component\HttpFoundation\ResponseHeaderBag; |
|
use Symfony\Component\HttpFoundation\Tests\File\FakeFile; |
|
|
|
class BinaryFileResponseTest extends ResponseTestCase |
|
{ |
|
public function testConstruction() |
|
{ |
|
$file = __DIR__.'/../README.md'; |
|
$response = new BinaryFileResponse($file, 404, array('X-Header' => 'Foo'), true, null, true, true); |
|
$this->assertEquals(404, $response->getStatusCode()); |
|
$this->assertEquals('Foo', $response->headers->get('X-Header')); |
|
$this->assertTrue($response->headers->has('ETag')); |
|
$this->assertTrue($response->headers->has('Last-Modified')); |
|
$this->assertFalse($response->headers->has('Content-Disposition')); |
|
|
|
$response = BinaryFileResponse::create($file, 404, array(), true, ResponseHeaderBag::DISPOSITION_INLINE); |
|
$this->assertEquals(404, $response->getStatusCode()); |
|
$this->assertFalse($response->headers->has('ETag')); |
|
$this->assertEquals('inline; filename="README.md"', $response->headers->get('Content-Disposition')); |
|
} |
|
|
|
public function testConstructWithNonAsciiFilename() |
|
{ |
|
touch(sys_get_temp_dir().'/fööö.html'); |
|
|
|
$response = new BinaryFileResponse(sys_get_temp_dir().'/fööö.html', 200, array(), true, 'attachment'); |
|
|
|
@unlink(sys_get_temp_dir().'/fööö.html'); |
|
|
|
$this->assertSame('fööö.html', $response->getFile()->getFilename()); |
|
} |
|
|
|
/** |
|
* @expectedException \LogicException |
|
*/ |
|
public function testSetContent() |
|
{ |
|
$response = new BinaryFileResponse(__FILE__); |
|
$response->setContent('foo'); |
|
} |
|
|
|
public function testGetContent() |
|
{ |
|
$response = new BinaryFileResponse(__FILE__); |
|
$this->assertFalse($response->getContent()); |
|
} |
|
|
|
public function testSetContentDispositionGeneratesSafeFallbackFilename() |
|
{ |
|
$response = new BinaryFileResponse(__FILE__); |
|
$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, 'föö.html'); |
|
|
|
$this->assertSame('attachment; filename="f__.html"; filename*=utf-8\'\'f%C3%B6%C3%B6.html', $response->headers->get('Content-Disposition')); |
|
} |
|
|
|
/** |
|
* @dataProvider provideRanges |
|
*/ |
|
public function testRequests($requestRange, $offset, $length, $responseRange) |
|
{ |
|
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'))->setAutoEtag(); |
|
|
|
// do a request to get the ETag |
|
$request = Request::create('/'); |
|
$response->prepare($request); |
|
$etag = $response->headers->get('ETag'); |
|
|
|
// prepare a request for a range of the testing file |
|
$request = Request::create('/'); |
|
$request->headers->set('If-Range', $etag); |
|
$request->headers->set('Range', $requestRange); |
|
|
|
$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($responseRange, $response->headers->get('Content-Range')); |
|
} |
|
|
|
/** |
|
* @dataProvider provideRanges |
|
*/ |
|
public function testRequestsWithoutEtag($requestRange, $offset, $length, $responseRange) |
|
{ |
|
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream')); |
|
|
|
// do a request to get the LastModified |
|
$request = Request::create('/'); |
|
$response->prepare($request); |
|
$lastModified = $response->headers->get('Last-Modified'); |
|
|
|
// prepare a request for a range of the testing file |
|
$request = Request::create('/'); |
|
$request->headers->set('If-Range', $lastModified); |
|
$request->headers->set('Range', $requestRange); |
|
|
|
$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($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=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'), |
|
); |
|
} |
|
|
|
public function testRangeRequestsWithoutLastModifiedDate() |
|
{ |
|
// prevent auto last modified |
|
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'), true, null, false, false); |
|
|
|
// prepare a request for a range of the testing file |
|
$request = Request::create('/'); |
|
$request->headers->set('If-Range', date('D, d M Y H:i:s').' GMT'); |
|
$request->headers->set('Range', 'bytes=1-4'); |
|
|
|
$this->expectOutputString(file_get_contents(__DIR__.'/File/Fixtures/test.gif')); |
|
$response = clone $response; |
|
$response->prepare($request); |
|
$response->sendContent(); |
|
|
|
$this->assertEquals(200, $response->getStatusCode()); |
|
$this->assertNull($response->headers->get('Content-Range')); |
|
} |
|
|
|
/** |
|
* @dataProvider provideFullFileRanges |
|
*/ |
|
public function testFullFileRequests($requestRange) |
|
{ |
|
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'))->setAutoEtag(); |
|
|
|
// prepare a request for a range of the testing file |
|
$request = Request::create('/'); |
|
$request->headers->set('Range', $requestRange); |
|
|
|
$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->assertEquals(200, $response->getStatusCode()); |
|
} |
|
|
|
public function provideFullFileRanges() |
|
{ |
|
return array( |
|
array('bytes=0-'), |
|
array('bytes=0-34'), |
|
array('bytes=-35'), |
|
// Syntactical invalid range-request should also return the full resource |
|
array('bytes=20-10'), |
|
array('bytes=50-40'), |
|
); |
|
} |
|
|
|
/** |
|
* @dataProvider provideInvalidRanges |
|
*/ |
|
public function testInvalidRequests($requestRange) |
|
{ |
|
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'))->setAutoEtag(); |
|
|
|
// prepare a request for a range of the testing file |
|
$request = Request::create('/'); |
|
$request->headers->set('Range', $requestRange); |
|
|
|
$response = clone $response; |
|
$response->prepare($request); |
|
$response->sendContent(); |
|
|
|
$this->assertEquals(416, $response->getStatusCode()); |
|
$this->assertEquals('bytes */35', $response->headers->get('Content-Range')); |
|
} |
|
|
|
public function provideInvalidRanges() |
|
{ |
|
return array( |
|
array('bytes=-40'), |
|
array('bytes=30-40'), |
|
); |
|
} |
|
|
|
/** |
|
* @dataProvider provideXSendfileFiles |
|
*/ |
|
public function testXSendfile($file) |
|
{ |
|
$request = Request::create('/'); |
|
$request->headers->set('X-Sendfile-Type', 'X-Sendfile'); |
|
|
|
BinaryFileResponse::trustXSendfileTypeHeader(); |
|
$response = BinaryFileResponse::create($file, 200, array('Content-Type' => 'application/octet-stream')); |
|
$response->prepare($request); |
|
|
|
$this->expectOutputString(''); |
|
$response->sendContent(); |
|
|
|
$this->assertContains('README.md', $response->headers->get('X-Sendfile')); |
|
} |
|
|
|
public function provideXSendfileFiles() |
|
{ |
|
return array( |
|
array(__DIR__.'/../README.md'), |
|
array('file://'.__DIR__.'/../README.md'), |
|
); |
|
} |
|
|
|
/** |
|
* @dataProvider getSampleXAccelMappings |
|
*/ |
|
public function testXAccelMapping($realpath, $mapping, $virtual) |
|
{ |
|
$request = Request::create('/'); |
|
$request->headers->set('X-Sendfile-Type', 'X-Accel-Redirect'); |
|
$request->headers->set('X-Accel-Mapping', $mapping); |
|
|
|
$file = new FakeFile($realpath, __DIR__.'/File/Fixtures/test'); |
|
|
|
BinaryFileResponse::trustXSendfileTypeHeader(); |
|
$response = new BinaryFileResponse($file, 200, array('Content-Type' => 'application/octet-stream')); |
|
$reflection = new \ReflectionObject($response); |
|
$property = $reflection->getProperty('file'); |
|
$property->setAccessible(true); |
|
$property->setValue($response, $file); |
|
|
|
$response->prepare($request); |
|
$this->assertEquals($virtual, $response->headers->get('X-Accel-Redirect')); |
|
} |
|
|
|
public function testDeleteFileAfterSend() |
|
{ |
|
$request = Request::create('/'); |
|
|
|
$path = __DIR__.'/File/Fixtures/to_delete'; |
|
touch($path); |
|
$realPath = realpath($path); |
|
$this->assertFileExists($realPath); |
|
|
|
$response = new BinaryFileResponse($realPath, 200, array('Content-Type' => 'application/octet-stream')); |
|
$response->deleteFileAfterSend(true); |
|
|
|
$response->prepare($request); |
|
$response->sendContent(); |
|
|
|
$this->assertFileNotExists($path); |
|
} |
|
|
|
public function testAcceptRangeOnUnsafeMethods() |
|
{ |
|
$request = Request::create('/', 'POST'); |
|
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream')); |
|
$response->prepare($request); |
|
|
|
$this->assertEquals('none', $response->headers->get('Accept-Ranges')); |
|
} |
|
|
|
public function testAcceptRangeNotOverriden() |
|
{ |
|
$request = Request::create('/', 'POST'); |
|
$response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream')); |
|
$response->headers->set('Accept-Ranges', 'foo'); |
|
$response->prepare($request); |
|
|
|
$this->assertEquals('foo', $response->headers->get('Accept-Ranges')); |
|
} |
|
|
|
public function getSampleXAccelMappings() |
|
{ |
|
return array( |
|
array('/var/www/var/www/files/foo.txt', '/var/www/=/files/', '/files/var/www/files/foo.txt'), |
|
array('/home/foo/bar.txt', '/var/www/=/files/,/home/foo/=/baz/', '/baz/bar.txt'), |
|
); |
|
} |
|
|
|
protected function provideResponse() |
|
{ |
|
return new BinaryFileResponse(__DIR__.'/../README.md', 200, array('Content-Type' => 'application/octet-stream')); |
|
} |
|
|
|
public static function tearDownAfterClass() |
|
{ |
|
$path = __DIR__.'/../Fixtures/to_delete'; |
|
if (file_exists($path)) { |
|
@unlink($path); |
|
} |
|
} |
|
}
|
|
|