Skip to content

Commit 730f1bb

Browse files
bug #58776 [DependencyInjection][HttpClient][Routing] Reject URIs that contain invalid characters (nicolas-grekas)
This PR was merged into the 7.2 branch. Discussion ---------- [DependencyInjection][HttpClient][Routing] Reject URIs that contain invalid characters | Q | A | ------------- | --- | Branch? | 7.2 | Bug fix? | no | New feature? | no | Deprecations? | no | Issues | - | License | MIT The behavior of `parse_url()` doesn't match how browsers parse URLs. This PR ensures we won't accept URLs that are invalid per https://url.spec.whatwg.org/: - URLs that contain a backslash - or start/end with a control-char or a space - or contain a CR/LF/TAB character Commits ------- d73003e3b58 [DependencyInjection][Routing][HttpClient] Reject URIs that contain invalid characters
2 parents b870249 + 1856faf commit 730f1bb

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

HttpClientTrait.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,16 @@ private static function resolveUrl(array $url, ?array $base, array $queryDefault
625625
*/
626626
private static function parseUrl(string $url, array $query = [], array $allowedSchemes = ['http' => 80, 'https' => 443]): array
627627
{
628+
if (false !== ($i = strpos($url, '\\')) && $i < strcspn($url, '?#')) {
629+
throw new InvalidArgumentException(\sprintf('Malformed URL "%s": backslashes are not allowed.', $url));
630+
}
631+
if (\strlen($url) !== strcspn($url, "\r\n\t")) {
632+
throw new InvalidArgumentException(\sprintf('Malformed URL "%s": CR/LF/TAB characters are not allowed.', $url));
633+
}
634+
if ('' !== $url && (\ord($url[0]) <= 32 || \ord($url[-1]) <= 32)) {
635+
throw new InvalidArgumentException(\sprintf('Malformed URL "%s": leading/trailing ASCII control characters or spaces are not allowed.', $url));
636+
}
637+
628638
if (false === $parts = parse_url($url)) {
629639
if ('/' !== ($url[0] ?? '') || false === $parts = parse_url($url.'#')) {
630640
throw new InvalidArgumentException(\sprintf('Malformed URL "%s".', $url));

Tests/HttpClientTraitTest.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,13 +239,32 @@ public function testResolveUrlWithoutScheme()
239239
self::resolveUrl(self::parseUrl('localhost:8080'), null);
240240
}
241241

242-
public function testResolveBaseUrlWitoutScheme()
242+
public function testResolveBaseUrlWithoutScheme()
243243
{
244244
$this->expectException(InvalidArgumentException::class);
245245
$this->expectExceptionMessage('Invalid URL: scheme is missing in "//localhost:8081". Did you forget to add "http(s)://"?');
246246
self::resolveUrl(self::parseUrl('/foo'), self::parseUrl('localhost:8081'));
247247
}
248248

249+
/**
250+
* @testWith ["http://foo.com\\bar"]
251+
* ["\\\\foo.com/bar"]
252+
* ["a\rb"]
253+
* ["a\nb"]
254+
* ["a\tb"]
255+
* ["\u0000foo"]
256+
* ["foo\u0000"]
257+
* [" foo"]
258+
* ["foo "]
259+
* [":"]
260+
*/
261+
public function testParseMalformedUrl(string $url)
262+
{
263+
$this->expectException(InvalidArgumentException::class);
264+
$this->expectExceptionMessage('Malformed URL');
265+
self::parseUrl($url);
266+
}
267+
249268
/**
250269
* @dataProvider provideParseUrl
251270
*/

0 commit comments

Comments
 (0)