Skip to content

Commit

Permalink
bug #32000 [Routing] fix absolute url generation when scheme is not k…
Browse files Browse the repository at this point in the history
…nown (Tobion)

This PR was merged into the 3.4 branch.

Discussion
----------

[Routing] fix absolute url generation when scheme is not known

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no     <!-- see https://symfony.com/bc -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tests pass?   | yes    <!-- please add some, will be required by reviewers -->
| Fixed tickets | #25491
| License       | MIT
| Doc PR        |

This fixes two edge cases in the url generator:
1. when the context scheme is not known (empty) generating an absolute url would return an invalid url starting with `://host/path`. #25491 handled the case when the host is unknown which makes sense. but the way it was done, created this new problem.
2. non-http(s) urls do not require a host. e.g. typical `file:///path` urls. url generator is fixed to be in line with rfc3986

Commits
-------

8e04222 [Routing] fix absolute url generation when scheme is not known
  • Loading branch information
fabpot committed Jun 13, 2019
2 parents faf7b30 + 8e04222 commit bd9d0a4
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 17 deletions.
20 changes: 11 additions & 9 deletions src/Symfony/Component/Routing/Generator/UrlGenerator.php
Expand Up @@ -222,16 +222,18 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa
}
}

if ((self::ABSOLUTE_URL === $referenceType || self::NETWORK_PATH === $referenceType) && !empty($host)) {
$port = '';
if ('http' === $scheme && 80 != $this->context->getHttpPort()) {
$port = ':'.$this->context->getHttpPort();
} elseif ('https' === $scheme && 443 != $this->context->getHttpsPort()) {
$port = ':'.$this->context->getHttpsPort();
}
if (self::ABSOLUTE_URL === $referenceType || self::NETWORK_PATH === $referenceType) {
if ('' !== $host || ('' !== $scheme && 'http' !== $scheme && 'https' !== $scheme)) {
$port = '';
if ('http' === $scheme && 80 !== $this->context->getHttpPort()) {
$port = ':'.$this->context->getHttpPort();
} elseif ('https' === $scheme && 443 !== $this->context->getHttpsPort()) {
$port = ':'.$this->context->getHttpsPort();
}

$schemeAuthority = self::NETWORK_PATH === $referenceType ? '//' : "$scheme://";
$schemeAuthority .= $host.$port;
$schemeAuthority = self::NETWORK_PATH === $referenceType || '' === $scheme ? '//' : "$scheme://";
$schemeAuthority .= $host.$port;
}
}

if (self::RELATIVE_PATH === $referenceType) {
Expand Down
48 changes: 40 additions & 8 deletions src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php
Expand Up @@ -480,28 +480,27 @@ public function testHostIsCaseInsensitive()

public function testDefaultHostIsUsedWhenContextHostIsEmpty()
{
$routes = $this->getRoutes('test', new Route('/route', ['domain' => 'my.fallback.host'], ['domain' => '.+'], [], '{domain}', ['http']));
$routes = $this->getRoutes('test', new Route('/path', ['domain' => 'my.fallback.host'], ['domain' => '.+'], [], '{domain}'));

$generator = $this->getGenerator($routes);
$generator->getContext()->setHost('');

$this->assertSame('http://my.fallback.host/app.php/route', $generator->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL));
$this->assertSame('http://my.fallback.host/app.php/path', $generator->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL));
}

public function testDefaultHostIsUsedWhenContextHostIsEmptyAndSchemeIsNot()
public function testDefaultHostIsUsedWhenContextHostIsEmptyAndPathReferenceType()
{
$routes = $this->getRoutes('test', new Route('/route', ['domain' => 'my.fallback.host'], ['domain' => '.+'], [], '{domain}', ['http', 'https']));
$routes = $this->getRoutes('test', new Route('/path', ['domain' => 'my.fallback.host'], ['domain' => '.+'], [], '{domain}'));

$generator = $this->getGenerator($routes);
$generator->getContext()->setHost('');
$generator->getContext()->setScheme('https');

$this->assertSame('https://my.fallback.host/app.php/route', $generator->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL));
$this->assertSame('//my.fallback.host/app.php/path', $generator->generate('test', [], UrlGeneratorInterface::ABSOLUTE_PATH));
}

public function testAbsoluteUrlFallbackToRelativeIfHostIsEmptyAndSchemeIsNot()
public function testAbsoluteUrlFallbackToPathIfHostIsEmptyAndSchemeIsHttp()
{
$routes = $this->getRoutes('test', new Route('/route', [], [], [], '', ['http', 'https']));
$routes = $this->getRoutes('test', new Route('/route'));

$generator = $this->getGenerator($routes);
$generator->getContext()->setHost('');
Expand All @@ -510,6 +509,39 @@ public function testAbsoluteUrlFallbackToRelativeIfHostIsEmptyAndSchemeIsNot()
$this->assertSame('/app.php/route', $generator->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL));
}

public function testAbsoluteUrlFallbackToNetworkIfSchemeIsEmptyAndHostIsNot()
{
$routes = $this->getRoutes('test', new Route('/path'));

$generator = $this->getGenerator($routes);
$generator->getContext()->setHost('example.com');
$generator->getContext()->setScheme('');

$this->assertSame('//example.com/app.php/path', $generator->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL));
}

public function testAbsoluteUrlFallbackToPathIfSchemeAndHostAreEmpty()
{
$routes = $this->getRoutes('test', new Route('/path'));

$generator = $this->getGenerator($routes);
$generator->getContext()->setHost('');
$generator->getContext()->setScheme('');

$this->assertSame('/app.php/path', $generator->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL));
}

public function testAbsoluteUrlWithNonHttpSchemeAndEmptyHost()
{
$routes = $this->getRoutes('test', new Route('/path', [], [], [], '', ['file']));

$generator = $this->getGenerator($routes);
$generator->getContext()->setBaseUrl('');
$generator->getContext()->setHost('');

$this->assertSame('file:///path', $generator->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL));
}

public function testGenerateNetworkPath()
{
$routes = $this->getRoutes('test', new Route('/{name}', [], [], [], '{locale}.example.com', ['http']));
Expand Down

0 comments on commit bd9d0a4

Please sign in to comment.