diff --git a/Contracts/UriRenderer.php b/Contracts/UriRenderer.php index ddb746c..f01d454 100644 --- a/Contracts/UriRenderer.php +++ b/Contracts/UriRenderer.php @@ -45,7 +45,7 @@ public function toNormalizedString(): ?string; * * @see https://datatracker.ietf.org/doc/html/rfc3986#section-6.2 */ - public function toDisplayString(): ?string; + public function toDisplayString(): string; /** * Returns the string representation as a URI reference. diff --git a/UriString.php b/UriString.php index 4d0a6b2..e0ba6f4 100644 --- a/UriString.php +++ b/UriString.php @@ -338,40 +338,45 @@ public static function normalizeAuthority(Stringable|string $authority): string */ public static function resolve(Stringable|string $uri, Stringable|string|null $baseUri = null): string { + $uri = (string) $uri; if ('' === $uri) { $uri = $baseUri ?? throw new SyntaxError('The uri can not be the empty string when there\'s no base URI.'); } - $uri = self::parse($uri); - $baseUri = null !== $baseUri ? self::parse($baseUri) : $uri; - if (null === $baseUri['scheme']) { + $uriComponents = self::parse($uri); + $baseUriComponents = $uriComponents; + if (null !== $baseUri && (string) $uri !== (string) $baseUri) { + $baseUriComponents = self::parse($baseUri); + } + + if (null === $baseUriComponents['scheme']) { throw new SyntaxError('The base URI must be an absolute URI or null; If the base URI is null the URI must be an absolute URI.'); } - if (null !== $uri['scheme'] && '' !== $uri['scheme']) { - $uri['path'] = self::removeDotSegments($uri['path']); + if (null !== $uriComponents['scheme'] && '' !== $uriComponents['scheme']) { + $uriComponents['path'] = self::removeDotSegments($uriComponents['path']); - return UriString::build($uri); + return UriString::build($uriComponents); } - if (null !== self::buildAuthority($uri)) { - $uri['scheme'] = $baseUri['scheme']; - $uri['path'] = self::removeDotSegments($uri['path']); + if (null !== self::buildAuthority($uriComponents)) { + $uriComponents['scheme'] = $baseUriComponents['scheme']; + $uriComponents['path'] = self::removeDotSegments($uriComponents['path']); - return UriString::build($uri); + return UriString::build($uriComponents); } - [$path, $query] = self::resolvePathAndQuery($uri, $baseUri); + [$path, $query] = self::resolvePathAndQuery($uriComponents, $baseUriComponents); $path = UriString::removeDotSegments($path); - if ('' !== $path && '/' !== $path[0] && null !== self::buildAuthority($baseUri)) { + if ('' !== $path && '/' !== $path[0] && null !== self::buildAuthority($baseUriComponents)) { $path = '/'.$path; } - $baseUri['path'] = $path; - $baseUri['query'] = $query; - $baseUri['fragment'] = $uri['fragment']; + $baseUriComponents['path'] = $path; + $baseUriComponents['query'] = $query; + $baseUriComponents['fragment'] = $uriComponents['fragment']; - return UriString::build($baseUri); + return UriString::build($baseUriComponents); } /** diff --git a/UriStringTest.php b/UriStringTest.php index 6676ec6..2a0af99 100644 --- a/UriStringTest.php +++ b/UriStringTest.php @@ -1025,10 +1025,11 @@ public function it_fails_parsing_uri_string_with_whitespace(string $uri): void public static function invalidUriWithWhitespaceProvider(): iterable { + yield 'empty string' => ['uri' => '']; yield 'uri containing only whitespaces' => ['uri' => ' ']; - yield 'uri stating with whitespace' => ['uri' => ' https://a/b?c']; - yield 'uri ending with whitespace' => ['uri' => 'https://a/b?c ']; - yield 'uri surrounded with whitespace' => ['uri' => ' https://a/b?c ']; - yield 'uri containing with whitespace' => ['uri' => 'https://a/b ?c']; + yield 'uri starting with whitespaces' => ['uri' => ' https://a/b?c']; + yield 'uri ending with whitespaces' => ['uri' => 'https://a/b?c ']; + yield 'uri surrounded by whitespaces' => ['uri' => ' https://a/b?c ']; + yield 'uri containing with whitespaces' => ['uri' => 'https://a/b ?c']; } }