Skip to content

Commit 6c067aa

Browse files
Work around parse_url() bug (bis)
1 parent 439a278 commit 6c067aa

File tree

9 files changed

+29
-24
lines changed

9 files changed

+29
-24
lines changed

src/Symfony/Component/DomCrawler/UriResolver.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,8 @@ public static function resolve(string $uri, ?string $baseUri): string
3232
{
3333
$uri = trim($uri);
3434

35-
if (false === ($scheme = parse_url($uri, \PHP_URL_SCHEME)) && '/' === ($uri[0] ?? '')) {
36-
$scheme = parse_url($uri.'#', \PHP_URL_SCHEME);
37-
}
38-
3935
// absolute URL?
40-
if (null !== $scheme) {
36+
if (null !== parse_url(\strlen($uri) !== strcspn($uri, '?#') ? $uri : $uri.'#', \PHP_URL_SCHEME)) {
4137
return $uri;
4238
}
4339

src/Symfony/Component/HttpClient/CurlHttpClient.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ private static function createRedirectResolver(array $options, string $host): \C
436436
$redirectHeaders['with_auth'] = array_filter($redirectHeaders['with_auth'], $filterContentHeaders);
437437
}
438438

439-
if ($redirectHeaders && $host = parse_url('http:'.$location['authority'], \PHP_URL_HOST)) {
439+
if ($redirectHeaders && $host = parse_url($location['authority'] ?? '#', \PHP_URL_HOST)) {
440440
$requestHeaders = $redirectHeaders['host'] === $host ? $redirectHeaders['with_auth'] : $redirectHeaders['no_auth'];
441441
curl_setopt($ch, \CURLOPT_HTTPHEADER, $requestHeaders);
442442
} elseif ($noContent && $redirectHeaders) {

src/Symfony/Component/HttpClient/HttpClientTrait.php

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -514,11 +514,10 @@ private static function resolveUrl(array $url, ?array $base, array $queryDefault
514514
*/
515515
private static function parseUrl(string $url, array $query = [], array $allowedSchemes = ['http' => 80, 'https' => 443]): array
516516
{
517-
if (false === $parts = parse_url($url)) {
518-
if ('/' !== ($url[0] ?? '') || false === $parts = parse_url($url.'#')) {
519-
throw new InvalidArgumentException(sprintf('Malformed URL "%s".', $url));
520-
}
521-
unset($parts['fragment']);
517+
$tail = '';
518+
519+
if (false === $parts = parse_url(\strlen($url) !== strcspn($url, '?#') ? $url : $url.$tail = '#')) {
520+
throw new InvalidArgumentException(sprintf('Malformed URL "%s".', $url));
522521
}
523522

524523
if ($query) {
@@ -529,7 +528,7 @@ private static function parseUrl(string $url, array $query = [], array $allowedS
529528

530529
if (null !== $scheme = $parts['scheme'] ?? null) {
531530
if (!isset($allowedSchemes[$scheme = strtolower($scheme)])) {
532-
throw new InvalidArgumentException(sprintf('Unsupported scheme in "%s".', $url));
531+
throw new InvalidArgumentException(sprintf('Unsupported scheme in "%s": "%s" expected.', $url, implode('" or "', array_keys($allowedSchemes))));
533532
}
534533

535534
$port = $allowedSchemes[$scheme] === $port ? 0 : $port;
@@ -564,7 +563,7 @@ private static function parseUrl(string $url, array $query = [], array $allowedS
564563
'authority' => null !== $host ? '//'.(isset($parts['user']) ? $parts['user'].(isset($parts['pass']) ? ':'.$parts['pass'] : '').'@' : '').$host : null,
565564
'path' => isset($parts['path'][0]) ? $parts['path'] : null,
566565
'query' => isset($parts['query']) ? '?'.$parts['query'] : null,
567-
'fragment' => isset($parts['fragment']) ? '#'.$parts['fragment'] : null,
566+
'fragment' => isset($parts['fragment']) && !$tail ? '#'.$parts['fragment'] : null,
568567
];
569568
}
570569

src/Symfony/Component/HttpClient/Response/CurlResponse.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ private static function parseHeaderLine($ch, string $data, array &$info, array &
435435
curl_setopt($ch, \CURLOPT_FOLLOWLOCATION, false);
436436
curl_setopt($ch, \CURLOPT_MAXREDIRS, $options['max_redirects']);
437437
} else {
438-
$url = parse_url($location ?? ':');
438+
$url = parse_url($location.'#');
439439

440440
if (isset($url['host']) && null !== $ip = $multi->dnsCache->hostnames[$url['host'] = strtolower($url['host'])] ?? null) {
441441
// Populate DNS cache for redirects if needed

src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,4 +466,13 @@ public function testMisspelledScheme()
466466

467467
$httpClient->request('GET', 'http:/localhost:8057/');
468468
}
469+
470+
public function testNoRedirectWithInvalidLocation()
471+
{
472+
$client = $this->getHttpClient(__FUNCTION__);
473+
474+
$response = $client->request('GET', 'http://localhost:8057/302-no-scheme');
475+
476+
$this->assertSame(302, $response->getStatusCode());
477+
}
469478
}

src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,14 +127,14 @@ public static function provideResolveUrl(): array
127127
public function testResolveUrlWithoutScheme()
128128
{
129129
$this->expectException(InvalidArgumentException::class);
130-
$this->expectExceptionMessage('Invalid URL: scheme is missing in "//localhost:8080". Did you forget to add "http(s)://"?');
130+
$this->expectExceptionMessage('Unsupported scheme in "localhost:8080": "http" or "https" expected.');
131131
self::resolveUrl(self::parseUrl('localhost:8080'), null);
132132
}
133133

134-
public function testResolveBaseUrlWitoutScheme()
134+
public function testResolveBaseUrlWithoutScheme()
135135
{
136136
$this->expectException(InvalidArgumentException::class);
137-
$this->expectExceptionMessage('Invalid URL: scheme is missing in "//localhost:8081". Did you forget to add "http(s)://"?');
137+
$this->expectExceptionMessage('Unsupported scheme in "localhost:8081": "http" or "https" expected.');
138138
self::resolveUrl(self::parseUrl('/foo'), self::parseUrl('localhost:8081'));
139139
}
140140

src/Symfony/Component/HttpFoundation/Request.php

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -358,12 +358,7 @@ public static function create(string $uri, string $method = 'GET', array $parame
358358
$server['PATH_INFO'] = '';
359359
$server['REQUEST_METHOD'] = strtoupper($method);
360360

361-
if (false === ($components = parse_url($uri)) && '/' === ($uri[0] ?? '')) {
362-
$components = parse_url($uri.'#');
363-
unset($components['fragment']);
364-
}
365-
366-
if (false === $components) {
361+
if (false === $components = parse_url(\strlen($uri) !== strcspn($uri, '?#') ? $uri : $uri.'#')) {
367362
throw new BadRequestException('Invalid URI.');
368363
}
369364

src/Symfony/Component/HttpFoundation/Tests/RequestTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ public function testCreateWithRequestUri()
310310
* ["foo\u0000"]
311311
* [" foo"]
312312
* ["foo "]
313-
* [":"]
313+
* ["//"]
314314
*/
315315
public function testCreateWithBadRequestUri(string $uri)
316316
{

src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@
9898
}
9999
break;
100100

101+
case '/302-no-scheme':
102+
if (!isset($vars['HTTP_AUTHORIZATION'])) {
103+
header('Location: localhost:8067', true, 302);
104+
}
105+
break;
106+
101107
case '/302/relative':
102108
header('Location: ..', true, 302);
103109
break;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy