From 4059b3b1f180cae6ebce47445a9c347ddd8aac87 Mon Sep 17 00:00:00 2001 From: ignace nyamagana butera Date: Sun, 2 Jul 2023 22:12:57 +0200 Subject: [PATCH] Deprecate UriInfo class --- BaseUri.php | 127 ++++++++++++++++++++++---- BaseUriTest.php | 210 +++++++++++++++++++++++++++++++++++++++++++ UriInfo.php | 115 +++--------------------- UriInfoTest.php | 231 ------------------------------------------------ 4 files changed, 332 insertions(+), 351 deletions(-) delete mode 100644 UriInfoTest.php diff --git a/BaseUri.php b/BaseUri.php index d537afbe..6f508309 100644 --- a/BaseUri.php +++ b/BaseUri.php @@ -29,20 +29,41 @@ final class BaseUri implements Stringable { + private const WHATWG_SPECIAL_SCHEMES = ['ftp', 'http', 'https', 'ws', 'wss']; + private const REGEXP_ENCODED_CHARS = ',%(2[D|E]|3\d|4[1-9|A-F]|5[\d|AF]|6[1-9|A-F]|7[\d|E]),i'; + /** * @var array */ private const DOT_SEGMENTS = ['.' => 1, '..' => 1]; - public readonly ?UriInterface $origin; + public readonly Psr7UriInterface|UriInterface|null $origin; + private readonly ?string $nullValue; private function __construct( public readonly Psr7UriInterface|UriInterface $value ) { - $origin = UriInfo::getOrigin($this->value); - if (null !== $origin) { - $this->origin = Uri::new($origin); + $this->nullValue = $this->value instanceof Psr7UriInterface ? '' : null; + $this->origin = $this->computeOrigin($this->value, $this->nullValue); + } + + private function computeOrigin(Psr7UriInterface|UriInterface $uri, ?string $nullValue): Psr7UriInterface|UriInterface|null + { + $scheme = $uri->getScheme(); + if ('blob' === $scheme) { + $uri = Uri::new($uri->getPath()); + $scheme = $uri->getScheme(); } + + if (!in_array($scheme, self::WHATWG_SPECIAL_SCHEMES, true)) { + return null; + } + + return $uri + ->withFragment($nullValue) + ->withQuery($nullValue) + ->withPath('') + ->withUserInfo($nullValue); } public static function new(Stringable|string $baseUri): self @@ -55,12 +76,96 @@ public function __toString(): string return $this->value->__toString(); } + public function isAbsolute(): bool + { + return $this->nullValue !== $this->value->getScheme(); + } + + public function isNetworkPath(): bool + { + return $this->nullValue === $this->value->getScheme() + && $this->nullValue !== $this->value->getAuthority(); + } + + public function isAbsolutePath(): bool + { + return $this->nullValue === $this->value->getScheme() + && $this->nullValue === $this->value->getAuthority() + && '/' === ($this->value->getPath()[0] ?? ''); + } + + public function isRelativePath(): bool + { + return $this->nullValue === $this->value->getScheme() + && $this->nullValue === $this->value->getAuthority() + && '/' !== ($this->value->getPath()[0] ?? ''); + } + + /** + * Tells whether both URI refers to the same document. + */ + public function isSameDocument(Stringable|string $uri): bool + { + return self::normalize(self::filterUri($uri)) === self::normalize($this->value); + } + + /** + * Normalizes a URI for comparison. + */ + private static function normalize(Psr7UriInterface|UriInterface $uri): string + { + $null = $uri instanceof Psr7UriInterface ? '' : null; + + $path = $uri->getPath(); + if ('/' === ($path[0] ?? '') || '' !== $uri->getScheme().$uri->getAuthority()) { + $path = BaseUri::new($uri->withPath('')->withQuery($null))->resolve($uri)->value->getPath(); + } + + $query = $uri->getQuery(); + $pairs = null === $query ? [] : explode('&', $query); + sort($pairs); + + $value = preg_replace_callback( + self::REGEXP_ENCODED_CHARS, + static fn (array $matches): string => rawurldecode($matches[0]), + [$path, implode('&', $pairs)] + ); + + if (null !== $value) { + [$path, $query] = $value + ['', $null]; + } + + if ($null !== $uri->getAuthority() && '' === $path) { + $path = '/'; + } + + return $uri + ->withHost(Uri::fromComponents(['host' => $uri->getHost()])->getHost()) + ->withPath($path) + ->withQuery([] === $pairs ? $null : $query) + ->withFragment($null) + ->__toString(); + } + + /** + * Tells whether two URI do not share the same origin. + * + * @see UriInfo::getOrigin() + */ + public function isCrossOrigin(Stringable|string $uri): bool + { + return null === $this->origin + || null === ($uriOrigin = $this->computeOrigin(Uri::new($uri), null)) + || $uriOrigin->__toString() !== $this->origin->__toString(); + } + /** * Input URI normalization to allow Stringable and string URI. */ private static function filterUri(Stringable|string $uri): Psr7UriInterface|UriInterface { return match (true) { + $uri instanceof self => $uri->value, $uri instanceof Psr7UriInterface, $uri instanceof UriInterface => $uri, default => Uri::new($uri), }; @@ -284,7 +389,7 @@ private static function formatHost(Psr7UriInterface|UriInterface $uri): Psr7UriI */ private function isRelativizable(Psr7UriInterface|UriInterface $uri): bool { - return !UriInfo::isRelativePath($uri) + return !self::new($uri)->isRelativePath() && self::componentEquals('scheme', $uri) && self::componentEquals('authority', $uri); } @@ -358,16 +463,4 @@ private static function formatPathWithEmptyBaseQuery(string $path): string return '' === $basename ? './' : $basename; } - - /** - * Tells whether two URI do not share the same origin. - * - * @see UriInfo::getOrigin() - */ - public function isCrossOrigin(Stringable|string $uri): bool - { - return null === $this->origin - || null === ($uriString = UriInfo::getOrigin($uri)) - || $uriString !== $this->origin->toString(); - } } diff --git a/BaseUriTest.php b/BaseUriTest.php index e9bd8aae..f97d1d2e 100644 --- a/BaseUriTest.php +++ b/BaseUriTest.php @@ -12,6 +12,7 @@ namespace League\Uri; use PHPUnit\Framework\TestCase; +use Psr\Http\Message\UriInterface as Psr7UriInterface; /** * @group modifier @@ -166,4 +167,213 @@ public static function relativizeAndResolveProvider(): array 'path with colon' => ['http://a/', 'http://a/d:p', './d:p', 'http://a/d:p'], ]; } + + /** + * @dataProvider uriProvider + * + * @param array $infos + */ + public function testInfo( + Psr7UriInterface|Uri $uri, + Psr7UriInterface|Uri|null $base_uri, + array $infos + ): void { + if (null !== $base_uri) { + self::assertSame($infos['same_document'], BaseUri::new($base_uri)->isSameDocument($uri)); + } + self::assertSame($infos['relative_path'], BaseUri::new($uri)->isRelativePath()); + self::assertSame($infos['absolute_path'], BaseUri::new($uri)->isAbsolutePath()); + self::assertSame($infos['absolute_uri'], BaseUri::new($uri)->isAbsolute()); + self::assertSame($infos['network_path'], BaseUri::new($uri)->isNetworkPath()); + } + + public static function uriProvider(): array + { + return [ + 'absolute uri' => [ + 'uri' => Http::new('http://a/p?q#f'), + 'base_uri' => null, + 'infos' => [ + 'absolute_uri' => true, + 'network_path' => false, + 'absolute_path' => false, + 'relative_path' => false, + 'same_document' => false, + ], + ], + 'network relative uri' => [ + 'uri' => Http::new('//스타벅스코리아.com/p?q#f'), + 'base_uri' => Http::new('//xn--oy2b35ckwhba574atvuzkc.com/p?q#z'), + 'infos' => [ + 'absolute_uri' => false, + 'network_path' => true, + 'absolute_path' => false, + 'relative_path' => false, + 'same_document' => true, + ], + ], + 'path relative uri with non empty path' => [ + 'uri' => Http::new('p?q#f'), + 'base_uri' => null, + 'infos' => [ + 'absolute_uri' => false, + 'network_path' => false, + 'absolute_path' => false, + 'relative_path' => true, + 'same_document' => false, + ], + ], + 'path relative uri with empty' => [ + 'uri' => Http::new('?q#f'), + 'base_uri' => null, + 'infos' => [ + 'absolute_uri' => false, + 'network_path' => false, + 'absolute_path' => false, + 'relative_path' => true, + 'same_document' => false, + ], + ], + ]; + } + + public function testIsFunctionsThrowsTypeError(): void + { + self::assertTrue(BaseUri::new('http://example.com')->isAbsolute()); + self::assertFalse(BaseUri::new('http://example.com')->isNetworkPath()); + self::assertTrue(BaseUri::new('/example.com')->isAbsolutePath()); + self::assertTrue(BaseUri::new('example.com#foobar')->isRelativePath()); + } + + /** + * @dataProvider sameValueAsProvider + */ + public function testSameValueAs(Psr7UriInterface|Uri $uri1, Psr7UriInterface|Uri $uri2, bool $expected): void + { + self::assertSame($expected, BaseUri::new($uri2)->isSameDocument($uri1)); + } + + public static function sameValueAsProvider(): array + { + return [ + '2 disctincts URIs' => [ + Http::new('http://example.com'), + Uri::new('ftp://example.com'), + false, + ], + '2 identical URIs' => [ + Http::new('http://example.com'), + Http::new('http://example.com'), + true, + ], + '2 identical URIs after removing dot segment' => [ + Http::new('http://example.org/~foo/'), + Http::new('http://example.ORG/bar/./../~foo/'), + true, + ], + '2 distincts relative URIs' => [ + Http::new('~foo/'), + Http::new('../~foo/'), + false, + ], + '2 identical relative URIs' => [ + Http::new('../%7efoo/'), + Http::new('../~foo/'), + true, + ], + '2 identical URIs after normalization (1)' => [ + Http::new('HtTp://مثال.إختبار:80/%7efoo/%7efoo/'), + Http::new('http://xn--mgbh0fb.xn--kgbechtv/%7Efoo/~foo/'), + true, + ], + '2 identical URIs after normalization (2)' => [ + Http::new('http://www.example.com'), + Http::new('http://www.example.com/'), + true, + ], + '2 identical URIs after normalization (3)' => [ + Http::new('http://www.example.com'), + Http::new('http://www.example.com:/'), + true, + ], + '2 identical URIs after normalization (4)' => [ + Http::new('http://www.example.com'), + Http::new('http://www.example.com:80/'), + true, + ], + ]; + } + + /** + * @dataProvider getOriginProvider + */ + public function testGetOrigin(Psr7UriInterface|Uri $uri, ?string $expectedOrigin): void + { + self::assertSame($expectedOrigin, BaseUri::new($uri)->origin?->__toString()); + } + + public static function getOriginProvider(): array + { + return [ + 'http uri' => [ + 'uri' => Uri::new('https://example.com/path?query#fragment'), + 'expectedOrigin' => 'https://example.com', + ], + 'http uri with non standard port' => [ + 'uri' => Uri::new('https://example.com:81/path?query#fragment'), + 'expectedOrigin' => 'https://example.com:81', + ], + 'relative uri' => [ + 'uri' => Uri::new('//example.com:81/path?query#fragment'), + 'expectedOrigin' => null, + ], + 'absolute uri with user info' => [ + 'uri' => Uri::new('https://user:pass@example.com:81/path?query#fragment'), + 'expectedOrigin' => 'https://example.com:81', + ], + 'opaque URI' => [ + 'uri' => Uri::new('mailto:info@thephpleague.com'), + 'expectedOrigin' => null, + ], + 'file URI' => [ + 'uri' => Uri::new('file:///usr/bin/test'), + 'expectedOrigin' => null, + ], + 'blob' => [ + 'uri' => Uri::new('blob:https://mozilla.org:443/'), + 'expectedOrigin' => 'https://mozilla.org', + ], + ]; + } + + /** + * @dataProvider getCrossOriginExamples + */ + public function testIsCrossOrigin(string $original, string $modified, bool $expected): void + { + self::assertSame($expected, BaseUri::new($original)->isCrossOrigin($modified)); + } + + /** + * @return array + */ + public static function getCrossOriginExamples(): array + { + return [ + 'different path' => ['http://example.com/123', 'http://example.com/', false], + 'same port with default value (1)' => ['https://example.com/123', 'https://example.com:443/', false], + 'same port with default value (2)' => ['ws://example.com:80/123', 'ws://example.com/', false], + 'same explicit port' => ['wss://example.com:443/123', 'wss://example.com:443/', false], + 'same origin with i18n host' => ['https://xn--bb-bjab.be./path', 'https://Bébé.BE./path', false], + 'same origin using a blob' => ['blob:https://mozilla.org:443/', 'https://mozilla.org/123', false], + 'different scheme' => ['https://example.com/123', 'ftp://example.com/', true], + 'different host' => ['ftp://example.com/123', 'ftp://www.example.com/123', true], + 'different port implicit' => ['https://example.com/123', 'https://example.com:81/', true], + 'different port explicit' => ['https://example.com:80/123', 'https://example.com:81/', true], + 'same scheme different port' => ['https://example.com:443/123', 'https://example.com:444/', true], + 'comparing two opaque URI' => ['ldap://ldap.example.net', 'ldap://ldap.example.net', true], + 'comparing a URI with an origin and one with an opaque origin' => ['https://example.com:443/123', 'ldap://ldap.example.net', true], + 'cross origin using a blob' => ['blob:http://mozilla.org:443/', 'https://mozilla.org/123', true], + ]; + } } diff --git a/UriInfo.php b/UriInfo.php index 33d597fa..aadbbf1c 100644 --- a/UriInfo.php +++ b/UriInfo.php @@ -13,19 +13,15 @@ namespace League\Uri; -use League\Uri\Contracts\UriInterface; -use Psr\Http\Message\UriInterface as Psr7UriInterface; use Stringable; -use function explode; -use function implode; -use function preg_replace_callback; -use function rawurldecode; +/** + * @deprecated since version 7.0.0 + * @codeCoverageIgnore + * @see BaseUri + */ final class UriInfo { - private const REGEXP_ENCODED_CHARS = ',%(2[D|E]|3\d|4[1-9|A-F]|5[\d|AF]|6[1-9|A-F]|7[\d|E]),i'; - private const WHATWG_SPECIAL_SCHEMES = ['ftp', 'http', 'https', 'ws', 'wss']; - /** * @codeCoverageIgnore */ @@ -33,67 +29,12 @@ private function __construct() { } - /** - * Input URI normalization to allow Stringable and string URI. - */ - private static function filterUri(Stringable|string $uri): Psr7UriInterface|UriInterface - { - return match (true) { - $uri instanceof Psr7UriInterface, $uri instanceof UriInterface => $uri, - $uri instanceof BaseUri => $uri->value, - default => Uri::new($uri), - }; - } - - private static function emptyComponentValue(Psr7UriInterface|UriInterface $uri): ?string - { - return $uri instanceof Psr7UriInterface ? '' : null; - } - - /** - * Normalizes a URI for comparison. - */ - private static function normalize(Psr7UriInterface|UriInterface $uri): Psr7UriInterface|UriInterface - { - $null = self::emptyComponentValue($uri); - - $path = $uri->getPath(); - if ('/' === ($path[0] ?? '') || '' !== $uri->getScheme().$uri->getAuthority()) { - $path = BaseUri::new($uri->withPath('')->withQuery($null))->resolve($uri)->value->getPath(); - } - - $query = $uri->getQuery(); - $fragment = $uri->getFragment(); - $fragmentOrig = $fragment; - $pairs = null === $query ? [] : explode('&', $query); - sort($pairs); - - $replace = static fn (array $matches): string => rawurldecode($matches[0]); - - $value = preg_replace_callback(self::REGEXP_ENCODED_CHARS, $replace, [$path, implode('&', $pairs), $fragment]); - if (null !== $value) { - [$path, $query, $fragment] = $value + ['', $null, $null]; - } - - if ($null !== $uri->getAuthority() && '' === $path) { - $path = '/'; - } - - return $uri - ->withHost(Uri::fromComponents(['host' => $uri->getHost()])->getHost()) - ->withPath($path) - ->withQuery([] === $pairs ? $null : $query) - ->withFragment($null === $fragmentOrig ? $fragmentOrig : $fragment); - } - /** * Tells whether the URI represents an absolute URI. */ public static function isAbsolute(Stringable|string $uri): bool { - $uri = self::filterUri($uri); - - return self::emptyComponentValue($uri) !== $uri->getScheme(); + return BaseUri::new($uri)->isAbsolute(); } /** @@ -101,10 +42,7 @@ public static function isAbsolute(Stringable|string $uri): bool */ public static function isNetworkPath(Stringable|string $uri): bool { - $uri = self::filterUri($uri); - $null = self::emptyComponentValue($uri); - - return $null === $uri->getScheme() && $null !== $uri->getAuthority(); + return BaseUri::new($uri)->isNetworkPath(); } /** @@ -112,12 +50,7 @@ public static function isNetworkPath(Stringable|string $uri): bool */ public static function isAbsolutePath(Stringable|string $uri): bool { - $uri = self::filterUri($uri); - $null = self::emptyComponentValue($uri); - - return $null === $uri->getScheme() - && $null === $uri->getAuthority() - && '/' === ($uri->getPath()[0] ?? ''); + return BaseUri::new($uri)->isAbsolutePath(); } /** @@ -126,12 +59,7 @@ public static function isAbsolutePath(Stringable|string $uri): bool */ public static function isRelativePath(Stringable|string $uri): bool { - $uri = self::filterUri($uri); - $null = self::emptyComponentValue($uri); - - return $null === $uri->getScheme() - && $null === $uri->getAuthority() - && '/' !== ($uri->getPath()[0] ?? ''); + return BaseUri::new($uri)->isRelativePath(); } /** @@ -139,11 +67,7 @@ public static function isRelativePath(Stringable|string $uri): bool */ public static function isSameDocument(Stringable|string $uri, Stringable|string $baseUri): bool { - $uri = self::normalize(self::filterUri($uri)); - $baseUri = self::normalize(self::filterUri($baseUri)); - - return (string) $uri->withFragment(self::emptyComponentValue($uri)) - === (string) $baseUri->withFragment(self::emptyComponentValue($baseUri)); + return BaseUri::new($baseUri)->isSameDocument($uri); } /** @@ -157,20 +81,7 @@ public static function isSameDocument(Stringable|string $uri, Stringable|string */ public static function getOrigin(Stringable|string $uri): ?string { - $uri = self::filterUri($uri); - $scheme = $uri->getScheme(); - if ('blob' === $scheme) { - $uri = Uri::new($uri->getPath()); - $scheme = $uri->getScheme(); - } - - if (!in_array($scheme, self::WHATWG_SPECIAL_SCHEMES, true)) { - return null; - } - - $null = self::emptyComponentValue($uri); - - return (string) $uri->withFragment($null)->withQuery($null)->withPath('')->withUserInfo($null); + return BaseUri::new($uri)->origin?->__toString(); } /** @@ -180,8 +91,6 @@ public static function getOrigin(Stringable|string $uri): ?string */ public static function isCrossOrigin(Stringable|string $uri, Stringable|string $baseUri): bool { - return null === ($uriString = self::getOrigin($uri)) - || null === ($baseUriString = self::getOrigin($baseUri)) - || $uriString !== $baseUriString; + return BaseUri::new($baseUri)->isCrossOrigin($uri); } } diff --git a/UriInfoTest.php b/UriInfoTest.php deleted file mode 100644 index f83e4d21..00000000 --- a/UriInfoTest.php +++ /dev/null @@ -1,231 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace League\Uri; - -use PHPUnit\Framework\TestCase; -use Psr\Http\Message\UriInterface as Psr7UriInterface; - -/** - * @group modifier - * @coversDefaultClass \League\Uri\UriInfo - */ -final class UriInfoTest extends TestCase -{ - /** - * @dataProvider uriProvider - * - * @param array $infos - */ - public function testInfo( - Psr7UriInterface|Uri $uri, - Psr7UriInterface|Uri|null $base_uri, - array $infos - ): void { - if (null !== $base_uri) { - self::assertSame($infos['same_document'], UriInfo::isSameDocument($uri, $base_uri)); - } - self::assertSame($infos['relative_path'], UriInfo::isRelativePath($uri)); - self::assertSame($infos['absolute_path'], UriInfo::isAbsolutePath($uri)); - self::assertSame($infos['absolute_uri'], UriInfo::isAbsolute($uri)); - self::assertSame($infos['network_path'], UriInfo::isNetworkPath($uri)); - } - - public static function uriProvider(): array - { - return [ - 'absolute uri' => [ - 'uri' => Http::new('http://a/p?q#f'), - 'base_uri' => null, - 'infos' => [ - 'absolute_uri' => true, - 'network_path' => false, - 'absolute_path' => false, - 'relative_path' => false, - 'same_document' => false, - ], - ], - 'network relative uri' => [ - 'uri' => Http::new('//스타벅스코리아.com/p?q#f'), - 'base_uri' => Http::new('//xn--oy2b35ckwhba574atvuzkc.com/p?q#z'), - 'infos' => [ - 'absolute_uri' => false, - 'network_path' => true, - 'absolute_path' => false, - 'relative_path' => false, - 'same_document' => true, - ], - ], - 'path relative uri with non empty path' => [ - 'uri' => Http::new('p?q#f'), - 'base_uri' => null, - 'infos' => [ - 'absolute_uri' => false, - 'network_path' => false, - 'absolute_path' => false, - 'relative_path' => true, - 'same_document' => false, - ], - ], - 'path relative uri with empty' => [ - 'uri' => Http::new('?q#f'), - 'base_uri' => null, - 'infos' => [ - 'absolute_uri' => false, - 'network_path' => false, - 'absolute_path' => false, - 'relative_path' => true, - 'same_document' => false, - ], - ], - ]; - } - - public function testIsFunctionsThrowsTypeError(): void - { - self::assertTrue(UriInfo::isAbsolute('http://example.com')); - self::assertFalse(UriInfo::isNetworkPath('http://example.com')); - self::assertTrue(UriInfo::isAbsolutePath('/example.com')); - self::assertTrue(UriInfo::isRelativePath('example.com#foobar')); - } - - /** - * @dataProvider sameValueAsProvider - */ - public function testSameValueAs(Psr7UriInterface|Uri $uri1, Psr7UriInterface|Uri $uri2, bool $expected): void - { - self::assertSame($expected, UriInfo::isSameDocument($uri1, $uri2)); - } - - public static function sameValueAsProvider(): array - { - return [ - '2 disctincts URIs' => [ - Http::new('http://example.com'), - Uri::new('ftp://example.com'), - false, - ], - '2 identical URIs' => [ - Http::new('http://example.com'), - Http::new('http://example.com'), - true, - ], - '2 identical URIs after removing dot segment' => [ - Http::new('http://example.org/~foo/'), - Http::new('http://example.ORG/bar/./../~foo/'), - true, - ], - '2 distincts relative URIs' => [ - Http::new('~foo/'), - Http::new('../~foo/'), - false, - ], - '2 identical relative URIs' => [ - Http::new('../%7efoo/'), - Http::new('../~foo/'), - true, - ], - '2 identical URIs after normalization (1)' => [ - Http::new('HtTp://مثال.إختبار:80/%7efoo/%7efoo/'), - Http::new('http://xn--mgbh0fb.xn--kgbechtv/%7Efoo/~foo/'), - true, - ], - '2 identical URIs after normalization (2)' => [ - Http::new('http://www.example.com'), - Http::new('http://www.example.com/'), - true, - ], - '2 identical URIs after normalization (3)' => [ - Http::new('http://www.example.com'), - Http::new('http://www.example.com:/'), - true, - ], - '2 identical URIs after normalization (4)' => [ - Http::new('http://www.example.com'), - Http::new('http://www.example.com:80/'), - true, - ], - ]; - } - - /** - * @dataProvider getOriginProvider - */ - public function testGetOrigin(Psr7UriInterface|Uri $uri, ?string $expectedOrigin): void - { - self::assertSame($expectedOrigin, UriInfo::getOrigin($uri)); - } - - public static function getOriginProvider(): array - { - return [ - 'http uri' => [ - 'uri' => Uri::new('https://example.com/path?query#fragment'), - 'expectedOrigin' => 'https://example.com', - ], - 'http uri with non standard port' => [ - 'uri' => Uri::new('https://example.com:81/path?query#fragment'), - 'expectedOrigin' => 'https://example.com:81', - ], - 'relative uri' => [ - 'uri' => Uri::new('//example.com:81/path?query#fragment'), - 'expectedOrigin' => null, - ], - 'absolute uri with user info' => [ - 'uri' => Uri::new('https://user:pass@example.com:81/path?query#fragment'), - 'expectedOrigin' => 'https://example.com:81', - ], - 'opaque URI' => [ - 'uri' => Uri::new('mailto:info@thephpleague.com'), - 'expectedOrigin' => null, - ], - 'file URI' => [ - 'uri' => Uri::new('file:///usr/bin/test'), - 'expectedOrigin' => null, - ], - 'blob' => [ - 'uri' => Uri::new('blob:https://mozilla.org:443/'), - 'expectedOrigin' => 'https://mozilla.org', - ], - ]; - } - - /** - * @dataProvider getCrossOriginExamples - */ - public function testIsCrossOrigin(string $original, string $modified, bool $expected): void - { - self::assertSame($expected, UriInfo::isCrossOrigin(Uri::new($original), Http::new($modified))); - } - - /** - * @return array - */ - public static function getCrossOriginExamples(): array - { - return [ - 'different path' => ['http://example.com/123', 'http://example.com/', false], - 'same port with default value (1)' => ['https://example.com/123', 'https://example.com:443/', false], - 'same port with default value (2)' => ['ws://example.com:80/123', 'ws://example.com/', false], - 'same explicit port' => ['wss://example.com:443/123', 'wss://example.com:443/', false], - 'same origin with i18n host' => ['https://xn--bb-bjab.be./path', 'https://Bébé.BE./path', false], - 'same origin using a blob' => ['blob:https://mozilla.org:443/', 'https://mozilla.org/123', false], - 'different scheme' => ['https://example.com/123', 'ftp://example.com/', true], - 'different host' => ['ftp://example.com/123', 'ftp://www.example.com/123', true], - 'different port implicit' => ['https://example.com/123', 'https://example.com:81/', true], - 'different port explicit' => ['https://example.com:80/123', 'https://example.com:81/', true], - 'same scheme different port' => ['https://example.com:443/123', 'https://example.com:444/', true], - 'comparing two opaque URI' => ['ldap://ldap.example.net', 'ldap://ldap.example.net', true], - 'comparing a URI with an origin and one with an opaque origin' => ['https://example.com:443/123', 'ldap://ldap.example.net', true], - 'cross origin using a blob' => ['blob:http://mozilla.org:443/', 'https://mozilla.org/123', true], - ]; - } -}