Skip to content

Commit

Permalink
[HttpFoundation] Fix base URI detection on IIS with UrlRewriteModule
Browse files Browse the repository at this point in the history
  • Loading branch information
derrabus authored and nicolas-grekas committed Aug 21, 2023
1 parent da86b7d commit 365992c
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 3 deletions.
30 changes: 27 additions & 3 deletions Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ class Request
self::HEADER_X_FORWARDED_PREFIX => 'X_FORWARDED_PREFIX',
];

/** @var bool */
private $isIisRewrite = false;

/**
* @param array $query The GET parameters
* @param array $request The POST parameters
Expand Down Expand Up @@ -1805,11 +1808,10 @@ protected function prepareRequestUri()
{
$requestUri = '';

if ('1' == $this->server->get('IIS_WasUrlRewritten') && '' != $this->server->get('UNENCODED_URL')) {
if ($this->isIisRewrite() && '' != $this->server->get('UNENCODED_URL')) {
// IIS7 with URL Rewrite: make sure we get the unencoded URL (double slash problem)
$requestUri = $this->server->get('UNENCODED_URL');
$this->server->remove('UNENCODED_URL');
$this->server->remove('IIS_WasUrlRewritten');
} elseif ($this->server->has('REQUEST_URI')) {
$requestUri = $this->server->get('REQUEST_URI');

Expand Down Expand Up @@ -2012,7 +2014,13 @@ private function setPhpDefaultLocale(string $locale): void
*/
private function getUrlencodedPrefix(string $string, string $prefix): ?string
{
if (!str_starts_with(rawurldecode($string), $prefix)) {
if ($this->isIisRewrite()) {
// ISS with UrlRewriteModule might report SCRIPT_NAME/PHP_SELF with wrong case
// see https://github.com/php/php-src/issues/11981
if (0 !== stripos(rawurldecode($string), $prefix)) {
return null;
}
} elseif (!str_starts_with(rawurldecode($string), $prefix)) {
return null;
}

Expand Down Expand Up @@ -2145,4 +2153,20 @@ private function normalizeAndFilterClientIps(array $clientIps, string $ip): arra
// Now the IP chain contains only untrusted proxies and the client IP
return $clientIps ? array_reverse($clientIps) : [$firstTrustedIp];
}

/**
* Is this IIS with UrlRewriteModule?
*
* This method consumes, caches and removed the IIS_WasUrlRewritten env var,
* so we don't inherit it to sub-requests.
*/
private function isIisRewrite(): bool
{
if (1 === $this->server->getInt('IIS_WasUrlRewritten')) {
$this->isIisRewrite = true;
$this->server->remove('IIS_WasUrlRewritten');
}

return $this->isIisRewrite;
}
}
56 changes: 56 additions & 0 deletions Tests/RequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1850,6 +1850,62 @@ public static function getBaseUrlData()
];
}

/**
* @dataProvider baseUriDetectionOnIisWithRewriteData
*/
public function testBaseUriDetectionOnIisWithRewrite(array $server, string $expectedBaseUrl, string $expectedPathInfo)
{
$request = new Request([], [], [], [], [], $server);

self::assertSame($expectedBaseUrl, $request->getBaseUrl());
self::assertSame($expectedPathInfo, $request->getPathInfo());
}

public static function baseUriDetectionOnIisWithRewriteData(): \Generator
{
yield 'No rewrite' => [
[
'PATH_INFO' => '/foo/bar',
'PHP_SELF' => '/routingtest/index.php/foo/bar',
'REQUEST_URI' => '/routingtest/index.php/foo/bar',
'SCRIPT_FILENAME' => 'C:/Users/derrabus/Projects/routing-test/public/index.php',
'SCRIPT_NAME' => '/routingtest/index.php',
],
'/routingtest/index.php',
'/foo/bar',
];

yield 'Rewrite with correct case' => [
[
'IIS_WasUrlRewritten' => '1',
'PATH_INFO' => '/foo/bar',
'PHP_SELF' => '/routingtest/index.php/foo/bar',
'REQUEST_URI' => '/routingtest/foo/bar',
'SCRIPT_FILENAME' => 'C:/Users/derrabus/Projects/routing-test/public/index.php',
'SCRIPT_NAME' => '/routingtest/index.php',
'UNENCODED_URL' => '/routingtest/foo/bar',
],
'/routingtest',
'/foo/bar',
];

// ISS with UrlRewriteModule might report SCRIPT_NAME/PHP_SELF with wrong case
// see https://github.com/php/php-src/issues/11981
yield 'Rewrite with case mismatch' => [
[
'IIS_WasUrlRewritten' => '1',
'PATH_INFO' => '/foo/bar',
'PHP_SELF' => '/routingtest/index.php/foo/bar',
'REQUEST_URI' => '/RoutingTest/foo/bar',
'SCRIPT_FILENAME' => 'C:/Users/derrabus/Projects/routing-test/public/index.php',
'SCRIPT_NAME' => '/routingtest/index.php',
'UNENCODED_URL' => '/RoutingTest/foo/bar',
],
'/RoutingTest',
'/foo/bar',
];
}

/**
* @dataProvider urlencodedStringPrefixData
*/
Expand Down

0 comments on commit 365992c

Please sign in to comment.