Skip to content

Commit 365992c

Browse files
derrabusnicolas-grekas
authored andcommitted
[HttpFoundation] Fix base URI detection on IIS with UrlRewriteModule
1 parent da86b7d commit 365992c

File tree

2 files changed

+83
-3
lines changed

2 files changed

+83
-3
lines changed

Request.php

+27-3
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@ class Request
246246
self::HEADER_X_FORWARDED_PREFIX => 'X_FORWARDED_PREFIX',
247247
];
248248

249+
/** @var bool */
250+
private $isIisRewrite = false;
251+
249252
/**
250253
* @param array $query The GET parameters
251254
* @param array $request The POST parameters
@@ -1805,11 +1808,10 @@ protected function prepareRequestUri()
18051808
{
18061809
$requestUri = '';
18071810

1808-
if ('1' == $this->server->get('IIS_WasUrlRewritten') && '' != $this->server->get('UNENCODED_URL')) {
1811+
if ($this->isIisRewrite() && '' != $this->server->get('UNENCODED_URL')) {
18091812
// IIS7 with URL Rewrite: make sure we get the unencoded URL (double slash problem)
18101813
$requestUri = $this->server->get('UNENCODED_URL');
18111814
$this->server->remove('UNENCODED_URL');
1812-
$this->server->remove('IIS_WasUrlRewritten');
18131815
} elseif ($this->server->has('REQUEST_URI')) {
18141816
$requestUri = $this->server->get('REQUEST_URI');
18151817

@@ -2012,7 +2014,13 @@ private function setPhpDefaultLocale(string $locale): void
20122014
*/
20132015
private function getUrlencodedPrefix(string $string, string $prefix): ?string
20142016
{
2015-
if (!str_starts_with(rawurldecode($string), $prefix)) {
2017+
if ($this->isIisRewrite()) {
2018+
// ISS with UrlRewriteModule might report SCRIPT_NAME/PHP_SELF with wrong case
2019+
// see https://github.com/php/php-src/issues/11981
2020+
if (0 !== stripos(rawurldecode($string), $prefix)) {
2021+
return null;
2022+
}
2023+
} elseif (!str_starts_with(rawurldecode($string), $prefix)) {
20162024
return null;
20172025
}
20182026

@@ -2145,4 +2153,20 @@ private function normalizeAndFilterClientIps(array $clientIps, string $ip): arra
21452153
// Now the IP chain contains only untrusted proxies and the client IP
21462154
return $clientIps ? array_reverse($clientIps) : [$firstTrustedIp];
21472155
}
2156+
2157+
/**
2158+
* Is this IIS with UrlRewriteModule?
2159+
*
2160+
* This method consumes, caches and removed the IIS_WasUrlRewritten env var,
2161+
* so we don't inherit it to sub-requests.
2162+
*/
2163+
private function isIisRewrite(): bool
2164+
{
2165+
if (1 === $this->server->getInt('IIS_WasUrlRewritten')) {
2166+
$this->isIisRewrite = true;
2167+
$this->server->remove('IIS_WasUrlRewritten');
2168+
}
2169+
2170+
return $this->isIisRewrite;
2171+
}
21482172
}

Tests/RequestTest.php

+56
Original file line numberDiff line numberDiff line change
@@ -1850,6 +1850,62 @@ public static function getBaseUrlData()
18501850
];
18511851
}
18521852

1853+
/**
1854+
* @dataProvider baseUriDetectionOnIisWithRewriteData
1855+
*/
1856+
public function testBaseUriDetectionOnIisWithRewrite(array $server, string $expectedBaseUrl, string $expectedPathInfo)
1857+
{
1858+
$request = new Request([], [], [], [], [], $server);
1859+
1860+
self::assertSame($expectedBaseUrl, $request->getBaseUrl());
1861+
self::assertSame($expectedPathInfo, $request->getPathInfo());
1862+
}
1863+
1864+
public static function baseUriDetectionOnIisWithRewriteData(): \Generator
1865+
{
1866+
yield 'No rewrite' => [
1867+
[
1868+
'PATH_INFO' => '/foo/bar',
1869+
'PHP_SELF' => '/routingtest/index.php/foo/bar',
1870+
'REQUEST_URI' => '/routingtest/index.php/foo/bar',
1871+
'SCRIPT_FILENAME' => 'C:/Users/derrabus/Projects/routing-test/public/index.php',
1872+
'SCRIPT_NAME' => '/routingtest/index.php',
1873+
],
1874+
'/routingtest/index.php',
1875+
'/foo/bar',
1876+
];
1877+
1878+
yield 'Rewrite with correct case' => [
1879+
[
1880+
'IIS_WasUrlRewritten' => '1',
1881+
'PATH_INFO' => '/foo/bar',
1882+
'PHP_SELF' => '/routingtest/index.php/foo/bar',
1883+
'REQUEST_URI' => '/routingtest/foo/bar',
1884+
'SCRIPT_FILENAME' => 'C:/Users/derrabus/Projects/routing-test/public/index.php',
1885+
'SCRIPT_NAME' => '/routingtest/index.php',
1886+
'UNENCODED_URL' => '/routingtest/foo/bar',
1887+
],
1888+
'/routingtest',
1889+
'/foo/bar',
1890+
];
1891+
1892+
// ISS with UrlRewriteModule might report SCRIPT_NAME/PHP_SELF with wrong case
1893+
// see https://github.com/php/php-src/issues/11981
1894+
yield 'Rewrite with case mismatch' => [
1895+
[
1896+
'IIS_WasUrlRewritten' => '1',
1897+
'PATH_INFO' => '/foo/bar',
1898+
'PHP_SELF' => '/routingtest/index.php/foo/bar',
1899+
'REQUEST_URI' => '/RoutingTest/foo/bar',
1900+
'SCRIPT_FILENAME' => 'C:/Users/derrabus/Projects/routing-test/public/index.php',
1901+
'SCRIPT_NAME' => '/routingtest/index.php',
1902+
'UNENCODED_URL' => '/RoutingTest/foo/bar',
1903+
],
1904+
'/RoutingTest',
1905+
'/foo/bar',
1906+
];
1907+
}
1908+
18531909
/**
18541910
* @dataProvider urlencodedStringPrefixData
18551911
*/

0 commit comments

Comments
 (0)