Skip to content

Commit

Permalink
Enable opt-out of Uri scheme filtering
Browse files Browse the repository at this point in the history
addresses issue slimphp#282
  • Loading branch information
dakujem committed Aug 21, 2024
1 parent 1c7f012 commit 78c1694
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 2 deletions.
19 changes: 17 additions & 2 deletions src/Factory/UriFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

class UriFactory implements UriFactoryInterface
{
public const URI_CLASS = Uri::class;

/**
* {@inheritdoc}
*/
Expand All @@ -47,7 +49,7 @@ public function createUri(string $uri = ''): UriInterface
$query = $parts['query'] ?? '';
$fragment = $parts['fragment'] ?? '';

return new Uri($scheme, $host, $port, $path, $query, $fragment, $user, $pass);
return $this->makeUriObject($scheme, $host, $port, $path, $query, $fragment, $user, $pass);
}

/**
Expand Down Expand Up @@ -108,6 +110,19 @@ public function createFromGlobals(array $globals): Uri
}

// Build Uri and return
return new Uri($scheme, $host, $port, $requestUri, $queryString, '', $username, $password);
return $this->makeUriObject($scheme, $host, $port, $requestUri, $queryString, '', $username, $password);
}

protected function makeUriObject(
string $scheme,
string $host,
?int $port = null,
string $path = '/',
string $query = '',
string $fragment = '',
string $user = '',
string $password = ''
): Uri {
return new (static::URI_CLASS)($scheme, $host, $port, $path, $query, $fragment, $user, $password);
}
}
8 changes: 8 additions & 0 deletions src/Uri.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ protected function filterScheme($scheme): string
throw new InvalidArgumentException('Uri scheme must be a string.');
}

// In case the supported schemes list is null, do no filtering.
if (null === static::SUPPORTED_SCHEMES) {
return $scheme;
}

$scheme = str_replace('://', '', strtolower($scheme));
if (!key_exists($scheme, static::SUPPORTED_SCHEMES)) {
throw new InvalidArgumentException(
Expand Down Expand Up @@ -286,6 +291,9 @@ public function withPort($port): UriInterface
*/
protected function hasStandardPort(): bool
{
if (!isset(static::SUPPORTED_SCHEMES[$this->scheme])) {
return null === $this->port;
}
return static::SUPPORTED_SCHEMES[$this->scheme] === $this->port;
}

Expand Down
81 changes: 81 additions & 0 deletions tests/Factory/UriFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Interop\Http\Factory\UriFactoryTestCase;
use Slim\Psr7\Environment;
use Slim\Psr7\Factory\UriFactory;
use Slim\Psr7\Uri;

class UriFactoryTest extends UriFactoryTestCase
{
Expand Down Expand Up @@ -240,4 +241,84 @@ public function testUriDistinguishZeroFromEmptyString()
$expected = 'https://0:0@0:1/0?0#0';
$this->assertSame($expected, (string) $this->createUriFactory()->createUri($expected));
}

public function testEnableInheritedUriObjectUsingInheritanceOfFactory()
{
$factory = new class () extends UriFactory {
protected function makeUriObject(
string $scheme,
string $host,
?int $port = null,
string $path = '/',
string $query = '',
string $fragment = '',
string $user = '',
string $password = ''
): Uri {
return new class(
$scheme,
$host,
$port,
$path,
$query,
$fragment,
$user,
$password,
) extends Uri {
};
}
};

$uri = $factory->createUri('');
$this->assertInstanceOf(Uri::class, $uri);
$this->assertNotSame(Uri::class, get_class($uri));
}

public function testEnableNoUriSchemeFilteringThroughInheritance()
{
$factory = new class () extends UriFactory {
protected function makeUriObject(
string $scheme,
string $host,
?int $port = null,
string $path = '/',
string $query = '',
string $fragment = '',
string $user = '',
string $password = ''
): Uri {
return new class(
$scheme,
$host,
$port,
$path,
$query,
$fragment,
$user,
$password,
) extends Uri {
public const SUPPORTED_SCHEMES = null;
};
}
};

// The following are all valid URIs
(function () use ($factory) {
$uri = $factory->createUri('smtp://smtp.dakujem.dev:25');
$this->assertEquals('smtp', $uri->getScheme());
})();
(function () use ($factory) {
$uri = $factory->createUri('tel:+1-816-555-1212');
$this->assertEquals('tel', $uri->getScheme());
$this->assertEquals('+1-816-555-1212', $uri->getPath());
})();
(function () use ($factory) {
$uri = $factory->createUri('ftp://ftp.is.co.za/rfc/rfc1808.txt');
$this->assertEquals('ftp', $uri->getScheme());
})();
(function () use ($factory) {
$uri = $factory->createUri('ldap://[2001:db8::7]/c=GB?objectClass?one');
$this->assertEquals('ldap', $uri->getScheme());
})();
}
}
37 changes: 37 additions & 0 deletions tests/UriTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ public function testSupportOtherSchemes()
$this->assertEquals('ws', $wsUri->getScheme());
}

public function testSupportNoSchemeFilteringUsingInheritance()
{
$uri = new class ('whatever', 'example.com') extends Uri {
public const SUPPORTED_SCHEMES = null;
};
$this->assertEquals('whatever', $uri->getScheme());
}

public function testGetScheme()
{
$this->assertEquals('https', $this->uriFactory()->getScheme());
Expand Down Expand Up @@ -170,6 +178,35 @@ public function testGetPortWithSchemeAndDefaultPort()
$this->assertNull($uriHttps->getPort());
}

public function testGetPortWithoutSchemeOrStandardPort()
{
$uri = new Uri('', 'www.example.com', 80);

$this->assertEquals(80, $uri->getPort());
}

public function testSupportNoSchemeWithStandardPort()
{
$uri = new class ('', 'example.com', 80) extends Uri {
public const SUPPORTED_SCHEMES = [
'' => 80,
];
};

$this->assertNull($uri->getPort());
}

public function testSupportNoSchemeWithoutStandardPort()
{
$uri = new class ('', 'example.com', 1234) extends Uri {
public const SUPPORTED_SCHEMES = [
'' => 80,
];
};

$this->assertEquals(1234, $uri->getPort());
}

public function testGetPortWithoutSchemeAndPort()
{
$uri = new Uri('', 'www.example.com');
Expand Down

0 comments on commit 78c1694

Please sign in to comment.