Skip to content

Commit

Permalink
Fix download over SSL using IE < 8 and binary file response
Browse files Browse the repository at this point in the history
  • Loading branch information
nlegoff committed Apr 12, 2013
1 parent 972bde7 commit 4c51ec7
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 80 deletions.
2 changes: 2 additions & 0 deletions src/Symfony/Component/HttpFoundation/BinaryFileResponse.php
Expand Up @@ -166,6 +166,8 @@ public function prepare(Request $request)
$this->setProtocolVersion('1.1');
}

$this->ensureIEOverSSLCompatibility($request);

$this->offset = 0;
$this->maxlen = -1;

Expand Down
24 changes: 15 additions & 9 deletions src/Symfony/Component/HttpFoundation/Response.php
Expand Up @@ -253,15 +253,7 @@ public function prepare(Request $request)
$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;
}
Expand Down Expand Up @@ -1179,4 +1171,18 @@ public function isEmpty()
{
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');
}
}
}
}
Expand Up @@ -15,7 +15,7 @@
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;

class BinaryFileResponseTest extends \PHPUnit_Framework_TestCase
class BinaryFileResponseTest extends ResponseTestCase
{
public function testConstruction()
{
Expand Down Expand Up @@ -145,4 +145,9 @@ public function getSampleXAccelMappings()
array('/home/foo/bar.txt', '/files/=/var/www/,/baz/=/home/foo/', '/baz/bar.txt'),
);
}

protected function provideResponse()
{
return new BinaryFileResponse('README.md');
}
}
76 changes: 6 additions & 70 deletions src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php
Expand Up @@ -14,7 +14,7 @@
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class ResponseTest extends \PHPUnit_Framework_TestCase
class ResponseTest extends ResponseTestCase
{
public function testCreate()
{
Expand Down Expand Up @@ -326,75 +326,6 @@ public function testContentTypeCharset()
$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');
Expand Down Expand Up @@ -770,6 +701,11 @@ protected function createDateTimeNow()
{
return new \DateTime();
}

protected function provideResponse()
{
return new Response();
}
}

class StringableObject
Expand Down
79 changes: 79 additions & 0 deletions src/Symfony/Component/HttpFoundation/Tests/ResponseTestCase.php
@@ -0,0 +1,79 @@
<?php

namespace Symfony\Component\HttpFoundation\Tests;

use Symfony\Component\HttpFoundation\Request;

abstract class ResponseTestCase extends \PHPUnit_Framework_TestCase
{
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 = $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();
}

0 comments on commit 4c51ec7

Please sign in to comment.