diff --git a/src/Symfony/Component/BrowserKit/Client.php b/src/Symfony/Component/BrowserKit/Client.php index c57b9e37a1..8664f31ab0 100644 --- a/src/Symfony/Component/BrowserKit/Client.php +++ b/src/Symfony/Component/BrowserKit/Client.php @@ -266,7 +266,7 @@ abstract class Client $response = $this->filterResponse($this->response); - $this->cookieJar->updateFromResponse($response); + $this->cookieJar->updateFromResponse($response, $uri); $this->redirect = $response->getHeader('Location'); diff --git a/src/Symfony/Component/BrowserKit/Cookie.php b/src/Symfony/Component/BrowserKit/Cookie.php index b4c3385934..1e2c64ce63 100644 --- a/src/Symfony/Component/BrowserKit/Cookie.php +++ b/src/Symfony/Component/BrowserKit/Cookie.php @@ -95,7 +95,7 @@ class Cookie $cookie .= '; domain='.$this->domain; } - if ('/' !== $this->path) { + if ($this->path) { $cookie .= '; path='.$this->path; } @@ -147,10 +147,9 @@ class Cookie if ((false === $urlParts = parse_url($url)) || !isset($urlParts['host']) || !isset($urlParts['path'])) { throw new \InvalidArgumentException(sprintf('The URL "%s" is not valid.', $url)); } - $parts = array_merge($urlParts, $parts); - $values['domain'] = $parts['host']; - $values['path'] = substr($parts['path'], 0, strrpos($parts['path'], '/')); + $values['domain'] = $urlParts['host']; + $values['path'] = substr($urlParts['path'], 0, strrpos($urlParts['path'], '/')); } foreach ($parts as $part) { diff --git a/src/Symfony/Component/BrowserKit/Tests/ClientTest.php b/src/Symfony/Component/BrowserKit/Tests/ClientTest.php index 32a3889a4b..1bf9e5c844 100644 --- a/src/Symfony/Component/BrowserKit/Tests/ClientTest.php +++ b/src/Symfony/Component/BrowserKit/Tests/ClientTest.php @@ -205,6 +205,15 @@ class ClientTest extends \PHPUnit_Framework_TestCase $this->assertEquals(array('foo' => 'bar'), $client->getCookieJar()->allValues('http://www.example.com/foo/foobar'), '->request() updates the CookieJar'); } + public function testRequestSecureCookies() + { + $client = new TestClient(); + $client->setNextResponse(new Response('foo', 200, array('Set-Cookie' => 'foo=bar; path=/; secure'))); + $client->request('GET', 'https://www.example.com/foo/foobar'); + + $this->assertTrue($client->getCookieJar()->get('foo', '/', 'www.example.com')->isSecure()); + } + public function testClick() { if (!class_exists('Symfony\Component\DomCrawler\Crawler')) { diff --git a/src/Symfony/Component/BrowserKit/Tests/CookieTest.php b/src/Symfony/Component/BrowserKit/Tests/CookieTest.php index be53eea417..606b2e2e91 100644 --- a/src/Symfony/Component/BrowserKit/Tests/CookieTest.php +++ b/src/Symfony/Component/BrowserKit/Tests/CookieTest.php @@ -26,14 +26,14 @@ class CookieTest extends \PHPUnit_Framework_TestCase public function getTestsForToFromString() { return array( - array('foo=bar'), + array('foo=bar; path=/'), array('foo=bar; path=/foo'), - array('foo=bar; domain=google.com'), - array('foo=bar; domain=example.com; secure', 'https://example.com/'), - array('foo=bar; httponly'), + array('foo=bar; domain=google.com; path=/'), + array('foo=bar; domain=example.com; path=/; secure', 'https://example.com/'), + array('foo=bar; path=/; httponly'), array('foo=bar; domain=google.com; path=/foo; secure; httponly', 'https://google.com/'), - array('foo=bar=baz'), - array('foo=bar%3Dbaz'), + array('foo=bar=baz; path=/'), + array('foo=bar%3Dbaz; path=/'), ); } @@ -67,17 +67,17 @@ class CookieTest extends \PHPUnit_Framework_TestCase public function testFromStringWithCapitalization() { - $this->assertEquals('Foo=Bar', (string) Cookie::fromString('Foo=Bar')); - $this->assertEquals('foo=bar; expires=Fri, 31 Dec 2010 23:59:59 GMT', (string) Cookie::fromString('foo=bar; Expires=Fri, 31 Dec 2010 23:59:59 GMT')); - $this->assertEquals('foo=bar; domain=www.example.org; httponly', (string) Cookie::fromString('foo=bar; DOMAIN=www.example.org; HttpOnly')); + $this->assertEquals('Foo=Bar; path=/', (string) Cookie::fromString('Foo=Bar')); + $this->assertEquals('foo=bar; expires=Fri, 31 Dec 2010 23:59:59 GMT; path=/', (string) Cookie::fromString('foo=bar; Expires=Fri, 31 Dec 2010 23:59:59 GMT')); + $this->assertEquals('foo=bar; domain=www.example.org; path=/; httponly', (string) Cookie::fromString('foo=bar; DOMAIN=www.example.org; HttpOnly')); } public function testFromStringWithUrl() { - $this->assertEquals('foo=bar; domain=www.example.com', (string) Cookie::FromString('foo=bar', 'http://www.example.com/')); + $this->assertEquals('foo=bar; domain=www.example.com; path=/', (string) Cookie::FromString('foo=bar', 'http://www.example.com/')); $this->assertEquals('foo=bar; domain=www.example.com; path=/foo', (string) Cookie::FromString('foo=bar', 'http://www.example.com/foo/bar')); - $this->assertEquals('foo=bar; domain=www.example.com', (string) Cookie::FromString('foo=bar; path=/', 'http://www.example.com/foo/bar')); - $this->assertEquals('foo=bar; domain=www.myotherexample.com', (string) Cookie::FromString('foo=bar; domain=www.myotherexample.com', 'http://www.example.com/')); + $this->assertEquals('foo=bar; domain=www.example.com; path=/', (string) Cookie::FromString('foo=bar; path=/', 'http://www.example.com/foo/bar')); + $this->assertEquals('foo=bar; domain=www.myotherexample.com; path=/', (string) Cookie::FromString('foo=bar; domain=www.myotherexample.com', 'http://www.example.com/')); } public function testFromStringThrowsAnExceptionIfCookieIsNotValid() diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckCircularReferencesPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckCircularReferencesPass.php index e24b5b0202..03528fefa9 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/CheckCircularReferencesPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckCircularReferencesPass.php @@ -56,11 +56,13 @@ class CheckCircularReferencesPass implements CompilerPassInterface private function checkOutEdges(array $edges) { foreach ($edges as $edge) { - $node = $edge->getDestNode(); - $this->currentPath[] = $id = $node->getId(); + $node = $edge->getDestNode(); + $id = $node->getId(); + $searchKey = array_search($id, $this->currentPath); + $this->currentPath[] = $id; - if ($this->currentId === $id) { - throw new ServiceCircularReferenceException($this->currentId, $this->currentPath); + if (false !== $searchKey) { + throw new ServiceCircularReferenceException($id, array_slice($this->currentPath, $searchKey)); } $this->checkOutEdges($node->getOutEdges()); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckCircularReferencesPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckCircularReferencesPassTest.php index 25f816b834..085bc519b7 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckCircularReferencesPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckCircularReferencesPassTest.php @@ -24,7 +24,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; class CheckCircularReferencesPassTest extends \PHPUnit_Framework_TestCase { /** - * @expectedException \RuntimeException + * @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException */ public function testProcess() { @@ -36,7 +36,7 @@ class CheckCircularReferencesPassTest extends \PHPUnit_Framework_TestCase } /** - * @expectedException \RuntimeException + * @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException */ public function testProcessWithAliases() { @@ -49,7 +49,7 @@ class CheckCircularReferencesPassTest extends \PHPUnit_Framework_TestCase } /** - * @expectedException \RuntimeException + * @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException */ public function testProcessDetectsIndirectCircularReference() { @@ -61,6 +61,19 @@ class CheckCircularReferencesPassTest extends \PHPUnit_Framework_TestCase $this->process($container); } + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException + */ + public function testDeepCircularReference() + { + $container = new ContainerBuilder(); + $container->register('a')->addArgument(new Reference('b')); + $container->register('b')->addArgument(new Reference('c')); + $container->register('c')->addArgument(new Reference('b')); + + $this->process($container); + } + public function testProcessIgnoresMethodCalls() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/HttpFoundation/Cookie.php b/src/Symfony/Component/HttpFoundation/Cookie.php index fdc33e3679..68fe853b2f 100644 --- a/src/Symfony/Component/HttpFoundation/Cookie.php +++ b/src/Symfony/Component/HttpFoundation/Cookie.php @@ -93,11 +93,11 @@ class Cookie } } - if ('/' !== $this->path) { + if ($this->path) { $str .= '; path='.$this->path; } - if (null !== $this->getDomain()) { + if ($this->getDomain()) { $str .= '; domain='.$this->getDomain(); } diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 448a501321..7d8ace2181 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1489,11 +1489,14 @@ class Request { $requestUri = ''; - if ($this->headers->has('X_ORIGINAL_URL') && false !== stripos(PHP_OS, 'WIN')) { + if ($this->headers->has('X_ORIGINAL_URL')) { // IIS with Microsoft Rewrite Module $requestUri = $this->headers->get('X_ORIGINAL_URL'); $this->headers->remove('X_ORIGINAL_URL'); - } elseif ($this->headers->has('X_REWRITE_URL') && false !== stripos(PHP_OS, 'WIN')) { + $this->server->remove('HTTP_X_ORIGINAL_URL'); + $this->server->remove('UNENCODED_URL'); + $this->server->remove('IIS_WasUrlRewritten'); + } elseif ($this->headers->has('X_REWRITE_URL')) { // IIS with ISAPI_Rewrite $requestUri = $this->headers->get('X_REWRITE_URL'); $this->headers->remove('X_REWRITE_URL'); diff --git a/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php b/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php index 721cc3cd9e..2a3e808909 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php @@ -134,11 +134,12 @@ class CookieTest extends \PHPUnit_Framework_TestCase public function testToString() { $cookie = new Cookie('foo', 'bar', strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true); - - $this->assertEquals('foo=bar; expires=Fri, 20-May-2011 15:25:52 GMT; domain=.myfoodomain.com; secure; httponly', $cookie->__toString(), '->__toString() returns string representation of the cookie'); + $this->assertEquals('foo=bar; expires=Fri, 20-May-2011 15:25:52 GMT; path=/; domain=.myfoodomain.com; secure; httponly', $cookie->__toString(), '->__toString() returns string representation of the cookie'); $cookie = new Cookie('foo', null, 1, '/admin/', '.myfoodomain.com'); - $this->assertEquals('foo=deleted; expires=' . gmdate("D, d-M-Y H:i:s T", time()-31536001) . '; path=/admin/; domain=.myfoodomain.com; httponly', $cookie->__toString(), '->__toString() returns string representation of a cleared cookie if value is NULL'); + + $cookie = new Cookie('foo', 'bar', 0, '/', ''); + $this->assertEquals('foo=bar; path=/; httponly', $cookie->__toString()); } } diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index a1b548fd22..fee7ea0062 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -1391,6 +1391,95 @@ class RequestTest extends \PHPUnit_Framework_TestCase // reset Request::setTrustedProxies(array()); } + + /** + * @dataProvider iisRequestUriProvider + */ + public function testIISRequestUri($headers, $server, $expectedRequestUri) + { + $request = new Request(); + $request->headers->replace($headers); + $request->server->replace($server); + + $this->assertEquals($expectedRequestUri, $request->getRequestUri(), '->getRequestUri() is correct'); + + $subRequestUri = '/bar/foo'; + $subRequest = $request::create($subRequestUri, 'get', array(), array(), array(), $request->server->all()); + $this->assertEquals($subRequestUri, $subRequest->getRequestUri(), '->getRequestUri() is correct in sub request'); + } + + public function iisRequestUriProvider() + { + return array( + array( + array( + 'X_ORIGINAL_URL' => '/foo/bar', + ), + array(), + '/foo/bar' + ), + array( + array( + 'X_REWRITE_URL' => '/foo/bar', + ), + array(), + '/foo/bar' + ), + array( + array(), + array( + 'IIS_WasUrlRewritten' => '1', + 'UNENCODED_URL' => '/foo/bar' + ), + '/foo/bar' + ), + array( + array( + 'X_ORIGINAL_URL' => '/foo/bar', + ), + array( + 'HTTP_X_ORIGINAL_URL' => '/foo/bar' + ), + '/foo/bar' + ), + array( + array( + 'X_ORIGINAL_URL' => '/foo/bar', + ), + array( + 'IIS_WasUrlRewritten' => '1', + 'UNENCODED_URL' => '/foo/bar' + ), + '/foo/bar' + ), + array( + array( + 'X_ORIGINAL_URL' => '/foo/bar', + ), + array( + 'HTTP_X_ORIGINAL_URL' => '/foo/bar', + 'IIS_WasUrlRewritten' => '1', + 'UNENCODED_URL' => '/foo/bar' + ), + '/foo/bar' + ), + array( + array(), + array( + 'ORIG_PATH_INFO' => '/foo/bar', + ), + '/foo/bar' + ), + array( + array(), + array( + 'ORIG_PATH_INFO' => '/foo/bar', + 'QUERY_STRING' => 'foo=bar', + ), + '/foo/bar?foo=bar' + ) + ); + } } class RequestContentProxy extends Request diff --git a/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php index c3dd9a27fc..1cb327860d 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php @@ -114,11 +114,11 @@ class ResponseHeaderBagTest extends \PHPUnit_Framework_TestCase $bag = new ResponseHeaderBag(array()); $bag->setCookie(new Cookie('foo', 'bar')); - $this->assertContains("Set-Cookie: foo=bar; httponly", explode("\r\n", $bag->__toString())); + $this->assertContains("Set-Cookie: foo=bar; path=/; httponly", explode("\r\n", $bag->__toString())); $bag->clearCookie('foo'); - $this->assertContains("Set-Cookie: foo=deleted; expires=".gmdate("D, d-M-Y H:i:s T", time() - 31536001)."; httponly", explode("\r\n", $bag->__toString())); + $this->assertContains("Set-Cookie: foo=deleted; expires=".gmdate("D, d-M-Y H:i:s T", time() - 31536001)."; path=/; httponly", explode("\r\n", $bag->__toString())); } public function testReplace() @@ -158,7 +158,7 @@ class ResponseHeaderBagTest extends \PHPUnit_Framework_TestCase $this->assertContains("Set-Cookie: foo=bar; path=/path/foo; domain=foo.bar; httponly", $headers); $this->assertContains("Set-Cookie: foo=bar; path=/path/foo; domain=foo.bar; httponly", $headers); $this->assertContains("Set-Cookie: foo=bar; path=/path/bar; domain=bar.foo; httponly", $headers); - $this->assertContains("Set-Cookie: foo=bar; httponly", $headers); + $this->assertContains("Set-Cookie: foo=bar; path=/; httponly", $headers); $cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY); $this->assertTrue(isset($cookies['foo.bar']['/path/foo']['foo'])); diff --git a/src/Symfony/Component/Translation/Loader/XliffFileLoader.php b/src/Symfony/Component/Translation/Loader/XliffFileLoader.php index 5e9850d819..0cafc043ac 100644 --- a/src/Symfony/Component/Translation/Loader/XliffFileLoader.php +++ b/src/Symfony/Component/Translation/Loader/XliffFileLoader.php @@ -40,7 +40,7 @@ class XliffFileLoader implements LoaderInterface throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource)); } - $xml = $this->parseFile($resource); + list($xml, $encoding) = $this->parseFile($resource); $xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:1.2'); $catalogue = new MessageCatalogue($locale); @@ -52,7 +52,21 @@ class XliffFileLoader implements LoaderInterface } $source = isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source; - $catalogue->set((string) $source, (string) $translation->target, $domain); + $target = (string) $translation->target; + + // If the xlf file has another encoding specified, try to convert it because + // simple_xml will always return utf-8 encoded values + if ('UTF-8' !== $encoding && !empty($encoding)) { + if (function_exists('mb_convert_encoding')) { + $target = mb_convert_encoding($target, $encoding, 'UTF-8'); + } elseif (function_exists('iconv')) { + $target = iconv('UTF-8', $encoding, $target); + } else { + throw new \RuntimeException('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).'); + } + } + + $catalogue->set((string) $source, $target, $domain); } $catalogue->addResource(new FileResource($resource)); @@ -117,7 +131,7 @@ class XliffFileLoader implements LoaderInterface libxml_use_internal_errors($internalErrors); - return simplexml_import_dom($dom); + return array(simplexml_import_dom($dom), strtoupper($dom->encoding)); } /** diff --git a/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php b/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php index c7fbab2d9c..f68fd5852f 100644 --- a/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php +++ b/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php @@ -50,6 +50,19 @@ class XliffFileLoaderTest extends \PHPUnit_Framework_TestCase $this->assertFalse($catalogue->has('extra', 'domain1')); } + public function testEncoding() + { + if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) { + $this->markTestSkipped('The iconv and mbstring extensions are not available.'); + } + + $loader = $this->createLoader(); + $catalogue = $loader->load(__DIR__.'/../fixtures/encoding.xlf', 'en', 'domain1'); + + $this->assertEquals(utf8_decode('föö'), $catalogue->get('bar', 'domain1')); + $this->assertEquals(utf8_decode('bär'), $catalogue->get('foo', 'domain1')); + } + /** * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException */ diff --git a/src/Symfony/Component/Translation/Tests/fixtures/encoding.xlf b/src/Symfony/Component/Translation/Tests/fixtures/encoding.xlf new file mode 100644 index 0000000000..6be901bd75 --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/fixtures/encoding.xlf @@ -0,0 +1,15 @@ + + + + + + foo + bär + + + bar + föö + + + +