From 4c51ec78663ad28e1bd4bf553be4f38afd86fd8d Mon Sep 17 00:00:00 2001 From: Nicolas Le Goff Date: Fri, 12 Apr 2013 15:45:42 +0200 Subject: [PATCH] Fix download over SSL using IE < 8 and binary file response --- .../HttpFoundation/BinaryFileResponse.php | 2 + .../Component/HttpFoundation/Response.php | 24 +++--- .../Tests/BinaryFileResponseTest.php | 7 +- .../HttpFoundation/Tests/ResponseTest.php | 76 ++---------------- .../HttpFoundation/Tests/ResponseTestCase.php | 79 +++++++++++++++++++ 5 files changed, 108 insertions(+), 80 deletions(-) create mode 100644 src/Symfony/Component/HttpFoundation/Tests/ResponseTestCase.php diff --git a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php index cb6c8a1e8a..ea46117262 100644 --- a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php +++ b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php @@ -166,6 +166,8 @@ class BinaryFileResponse extends Response $this->setProtocolVersion('1.1'); } + $this->ensureIEOverSSLCompatibility($request); + $this->offset = 0; $this->maxlen = -1; diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php index 7ac4e80056..248eef3089 100644 --- a/src/Symfony/Component/HttpFoundation/Response.php +++ b/src/Symfony/Component/HttpFoundation/Response.php @@ -253,15 +253,7 @@ class Response $this->headers->set('expires', -1); } - /** - * Check if we need to remove Cache-Control for ssl encrypted downloads when using IE < 9 - * @link http://support.microsoft.com/kb/323308 - */ - if (false !== stripos($this->headers->get('Content-Disposition'), 'attachment') && preg_match('/MSIE (.*?);/i', $request->server->get('HTTP_USER_AGENT'), $match) == 1 && true === $request->isSecure()) { - if (intval(preg_replace("/(MSIE )(.*?);/", "$2", $match[0])) < 9) { - $this->headers->remove('Cache-Control'); - } - } + $this->ensureIEOverSSLCompatibility($request); return $this; } @@ -1179,4 +1171,18 @@ class Response { return in_array($this->statusCode, array(201, 204, 304)); } + + /** + * Check if we need to remove Cache-Control for ssl encrypted downloads when using IE < 9 + * + * @link http://support.microsoft.com/kb/323308 + */ + protected function ensureIEOverSSLCompatibility(Request $request) + { + if (false !== stripos($this->headers->get('Content-Disposition'), 'attachment') && preg_match('/MSIE (.*?);/i', $request->server->get('HTTP_USER_AGENT'), $match) == 1 && true === $request->isSecure()) { + if (intval(preg_replace("/(MSIE )(.*?);/", "$2", $match[0])) < 9) { + $this->headers->remove('Cache-Control'); + } + } + } } diff --git a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php index 4d517313f3..c3d324fa9f 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php @@ -15,7 +15,7 @@ use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\ResponseHeaderBag; -class BinaryFileResponseTest extends \PHPUnit_Framework_TestCase +class BinaryFileResponseTest extends ResponseTestCase { public function testConstruction() { @@ -145,4 +145,9 @@ class BinaryFileResponseTest extends \PHPUnit_Framework_TestCase array('/home/foo/bar.txt', '/files/=/var/www/,/baz/=/home/foo/', '/baz/bar.txt'), ); } + + protected function provideResponse() + { + return new BinaryFileResponse('README.md'); + } } diff --git a/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php index 28b9d53732..3a084954c4 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php @@ -14,7 +14,7 @@ namespace Symfony\Component\HttpFoundation\Tests; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -class ResponseTest extends \PHPUnit_Framework_TestCase +class ResponseTest extends ResponseTestCase { public function testCreate() { @@ -326,75 +326,6 @@ class ResponseTest extends \PHPUnit_Framework_TestCase $this->assertEquals('text/css; charset=UTF-8', $response->headers->get('Content-Type')); } - public function testNoCacheControlHeaderOnAttachmentUsingHTTPSAndMSIE() - { - // Check for HTTPS and IE 8 - $request = new Request(); - $request->server->set('HTTPS', true); - $request->server->set('HTTP_USER_AGENT', 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)'); - - $response = new Response(); - $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); - $response->prepare($request); - - $this->assertFalse($response->headers->has('Cache-Control')); - - // Check for IE 10 and HTTPS - $request->server->set('HTTP_USER_AGENT', 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)'); - - $response = new Response(); - $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); - $response->prepare($request); - - $this->assertTrue($response->headers->has('Cache-Control')); - - // Check for IE 9 and HTTPS - $request->server->set('HTTP_USER_AGENT', 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 7.1; Trident/5.0)'); - - $response = new Response(); - $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); - $response->prepare($request); - - $this->assertTrue($response->headers->has('Cache-Control')); - - // Check for IE 9 and HTTP - $request->server->set('HTTPS', false); - - $response = new Response(); - $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); - $response->prepare($request); - - $this->assertTrue($response->headers->has('Cache-Control')); - - // Check for IE 8 and HTTP - $request->server->set('HTTP_USER_AGENT', 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)'); - - $response = new Response(); - $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); - $response->prepare($request); - - $this->assertTrue($response->headers->has('Cache-Control')); - - // Check for non-IE and HTTPS - $request->server->set('HTTPS', true); - $request->server->set('HTTP_USER_AGENT', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.60 Safari/537.17'); - - $response = new Response(); - $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); - $response->prepare($request); - - $this->assertTrue($response->headers->has('Cache-Control')); - - // Check for non-IE and HTTP - $request->server->set('HTTPS', false); - - $response = new Response(); - $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); - $response->prepare($request); - - $this->assertTrue($response->headers->has('Cache-Control')); - } - public function testPrepareDoesNothingIfContentTypeIsSet() { $response = new Response('foo'); @@ -770,6 +701,11 @@ class ResponseTest extends \PHPUnit_Framework_TestCase { return new \DateTime(); } + + protected function provideResponse() + { + return new Response(); + } } class StringableObject diff --git a/src/Symfony/Component/HttpFoundation/Tests/ResponseTestCase.php b/src/Symfony/Component/HttpFoundation/Tests/ResponseTestCase.php new file mode 100644 index 0000000000..2728106629 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/ResponseTestCase.php @@ -0,0 +1,79 @@ +server->set('HTTPS', true); + $request->server->set('HTTP_USER_AGENT', 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)'); + + $response = $this->provideResponse(); + $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); + $response->prepare($request); + + $this->assertFalse($response->headers->has('Cache-Control')); + + // Check for IE 10 and HTTPS + $request->server->set('HTTP_USER_AGENT', 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)'); + + $response = $this->provideResponse(); + $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); + $response->prepare($request); + + $this->assertTrue($response->headers->has('Cache-Control')); + + // Check for IE 9 and HTTPS + $request->server->set('HTTP_USER_AGENT', 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 7.1; Trident/5.0)'); + + $response = $this->provideResponse(); + $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); + $response->prepare($request); + + $this->assertTrue($response->headers->has('Cache-Control')); + + // Check for IE 9 and HTTP + $request->server->set('HTTPS', false); + + $response = $this->provideResponse(); + $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); + $response->prepare($request); + + $this->assertTrue($response->headers->has('Cache-Control')); + + // Check for IE 8 and HTTP + $request->server->set('HTTP_USER_AGENT', 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)'); + + $response = $this->provideResponse(); + $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); + $response->prepare($request); + + $this->assertTrue($response->headers->has('Cache-Control')); + + // Check for non-IE and HTTPS + $request->server->set('HTTPS', true); + $request->server->set('HTTP_USER_AGENT', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.60 Safari/537.17'); + + $response = $this->provideResponse(); + $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); + $response->prepare($request); + + $this->assertTrue($response->headers->has('Cache-Control')); + + // Check for non-IE and HTTP + $request->server->set('HTTPS', false); + + $response = $this->provideResponse(); + $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); + $response->prepare($request); + + $this->assertTrue($response->headers->has('Cache-Control')); + } + + abstract protected function provideResponse(); +}