Skip to content

Commit

Permalink
Add support for RFC8089 (#131)
Browse files Browse the repository at this point in the history
Add support for RFC8089
  • Loading branch information
nyamsprod committed Nov 20, 2023
1 parent ea373a5 commit 13108c5
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 1 deletion.
32 changes: 32 additions & 0 deletions BaseUri.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,38 @@ public function windowsPath(): ?string
};
}

/**
* Returns a string representation of a File URI according to RFC8089.
*
* The method will return null if the URI scheme is not the `file` scheme
*/
public function toRfc8089(): ?string
{
$path = $this->uri->getPath();

return match (true) {
'file' !== $this->uri->getScheme() => null,
in_array($this->uri->getAuthority(), ['', null, 'localhost'], true) => 'file:'.match (true) {
'' === $path,
'/' === $path[0] => $path,
default => '/'.$path,
},
default => (string) $this->uri,
};
}

/**
* Tells whether the `file` scheme base URI represents a local file.
*/
public function isLocalFile(): bool
{
return match (true) {
'file' !== $this->uri->getScheme() => false,
in_array($this->uri->getAuthority(), ['', null, 'localhost'], true) => true,
default => false,
};
}

/**
* Tells whether two URI do not share the same origin.
*/
Expand Down
30 changes: 29 additions & 1 deletion BaseUriTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,6 @@ public function testReturnsWindowsPath(?string $expected, string $input): void
{
self::assertSame($expected, BaseUri::from($input)->windowsPath());
self::assertSame($expected, BaseUri::from(Utils::uriFor($input))->windowsPath());

}

public static function windowLocalPathProvider(): array
Expand Down Expand Up @@ -575,4 +574,33 @@ public static function windowLocalPathProvider(): array
],
];
}

/** @dataProvider rfc8089UriProvider */
public function testReturnsRFC8089UriString(?string $expected, string $input): void
{
self::assertSame($expected, BaseUri::from($input)->toRfc8089());
self::assertSame($expected, BaseUri::from(Utils::uriFor($input))->toRfc8089());
}

public static function rfc8089UriProvider(): iterable
{
return [
'localhost' => [
'expected' => 'file:/etc/fstab',
'input' => 'file://localhost/etc/fstab',
],
'empty authority' => [
'expected' => 'file:/etc/fstab',
'input' => 'file:///etc/fstab',
],
'file with authority' => [
'expected' => 'file://yesman/etc/fstab',
'input' => 'file://yesman/etc/fstab',
],
'invalid scheme' => [
'expected' => null,
'input' => 'foobar://yesman/etc/fstab',
],
];
}
}
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ All Notable changes to `League\Uri` will be documented in this file
### Added

- `Uri::fromData`
- `Uri::fromRfc8089`
- `BaseUri::unixPath`
- `BaseUri::windowsPath`
- `BaseUri::toRfc8089`

### Fixed

Expand Down
44 changes: 44 additions & 0 deletions FactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,50 @@ public static function windowLocalPathProvider(): array
];
}

/** @dataProvider rfc8089UriProvider */
public function testCreateFromRfc8089(string $expected, string $uri): void
{
self::assertSame($expected, Uri::fromRfc8089($uri)->toString());
}

public static function rfc8089UriProvider(): iterable
{
return [
'empty authority' => [
'expected' => 'file:///etc/fstab',
'uri' => 'file:/etc/fstab',
],
'localhost' => [
'expected' => 'file:///etc/fstab',
'uri' => 'file://localhost/etc/fstab',
],
'file with authority' => [
'expected' => 'file://yesman/etc/fstab',
'uri' => 'file://yesman/etc/fstab',
],
];
}

/** @dataProvider invalidRfc8089UriProvider */
public function testIfFailsToGenerateAnUriFromRfc8089(string $invalidUri): void
{
$this->expectException(SyntaxError::class);

Uri::fromRfc8089($invalidUri);
}

public static function invalidRfc8089UriProvider(): iterable
{
return [
'unsupported scheme' => [
'invalidUri' => 'http://www.example.com',
],
'missing scheme' => [
'invalidUri' => '//localhost/etc/fstab',
],
];
}

public function testCreateFromUri(): void
{
$expected = 'https://login:[email protected]:443/test/query.php?kingkong=toto#doc3';
Expand Down
17 changes: 17 additions & 0 deletions Uri.php
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,23 @@ public static function fromWindowsPath(Stringable|string $path): self
return Uri::fromComponents(['host' => $host, 'path' => '/'.$path, 'scheme' => 'file']);
}

/**
* Creates a new instance from a RFC8089 compatible URI.
*
* @see https://datatracker.ietf.org/doc/html/rfc8089
*/
public static function fromRfc8089(Stringable|string $uri): UriInterface
{
$fileUri = self::new((string) preg_replace(',^(file:/)([^/].*)$,i', 'file:///$2', (string) $uri));
$scheme = $fileUri->getScheme();

return match (true) {
'file' !== $scheme => throw new SyntaxError('As per RFC8089, the URI scheme must be `file`.'),
'localhost' === $fileUri->getAuthority() => $fileUri->withHost(''),
default => $fileUri,
};
}

/**
* Create a new instance from the environment.
*/
Expand Down

0 comments on commit 13108c5

Please sign in to comment.