8000 Work around parse_url() bug (bis) · symfony/symfony@0cbc0dd · GitHub
[go: up one dir, main page]

Skip to content

Commit 0cbc0dd

Browse files
Work around parse_url() bug (bis)
1 parent 439a278 commit 0cbc0dd

File tree

11 files changed

+35
-26
lines changed

11 files changed

+35
-26
lines changed

src/Symfony/Component/DomCrawler/Tests/UriResolverTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ public static function provideResolverTests()
8787

8888
['http://', 'http://localhost', 'http://'],
8989
['/foo:123', 'http://localhost', 'http://localhost/foo:123'],
90+
['foo:123', 'http://localhost/', 'foo:123'],
9091
];
9192
}
9293
}

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/HttpClient/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"php": ">=7.2.5",
2626
"psr/log": "^1|^2|^3",
2727
"symfony/deprecation-contracts": "^2.1|^3",
28-
"symfony/http-client-contracts": "^2.5.3",
28+
"symfony/http-client-contracts": "^2.5.4",
2929
"symfony/polyfill-php73": "^1.11",
3030
"symfony/polyfill-php80": "^1.16",
3131
"symfony/service-contracts": "^1.0|^2|^3"

src/Symfony/Component/HttpFoundation/Request.php

Lines changed: 4 additions & 7 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

@@ -386,9 +381,11 @@ public static function create(string $uri, string $method = 'GET', array $parame
386381
if ('https' === $components['scheme']) {
387382
$server['HTTPS'] = 'on';
388383
$server['SERVER_PORT'] = 443;
389-
} else {
384+
} elseif ('http' === $components['scheme']) {
390385
unset($server['HTTPS']);
391386
$server['SERVER_PORT'] = 80;
387+
} else {
388+
throw new BadRequestException('Invalid URI: http(s) scheme expected.');
392389
}
393390
}
394391

src/Symfo E4A7 ny/Component/HttpFoundation/Tests/RequestTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,8 @@ public function testCreateWithRequestUri()
310310
* ["foo\u0000"]
311311
* [" foo"]
312312
* ["foo "]
313-
* [":"]
313+
* ["//"]
314+
* ["foo:bar"]
314315
*/
315316
public function testCreateWithBadRequestUri(string $uri)
316317
{

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)
0