diff --git a/application/loginwebpage.class.inc.php b/application/loginwebpage.class.inc.php index 63de0e5c1..6a1876cc0 100644 --- a/application/loginwebpage.class.inc.php +++ b/application/loginwebpage.class.inc.php @@ -722,7 +722,7 @@ class LoginWebPage extends NiceWebPage public static function HTTPReload() { - $sOriginURL = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; + $sOriginURL = utils::GetCurrentAbsoluteUrl(); if (!utils::StartsWith($sOriginURL, utils::GetAbsoluteUrlAppRoot())) { // If the found URL does not start with the configured AppRoot URL diff --git a/application/utils.inc.php b/application/utils.inc.php index f0ecba113..39a3d3e0f 100644 --- a/application/utils.inc.php +++ b/application/utils.inc.php @@ -860,16 +860,34 @@ class utils // } } + /** + * @return bool The boolean value of the conf. "trust_proxies" (except if there is no REMOTE_ADDR int his case, it return false) + * + * @since 2.7.4 + */ + public static function IsProxyTrusted() + { + if (empty($_SERVER['REMOTE_ADDR'])) { + return false; + } + + $bTrustProxies = (bool) self::GetConfig()->Get('trust_proxies'); + + return $bTrustProxies; + } + /** * Returns the absolute URL to the application root path * - * @param bool $bTrustProxy + * @param bool $bForceTrustProxy * * @return string The absolute URL to the application root, without the first slash * * @throws \Exception + * + * @since 2.7.4 $bForceTrustProxy param added */ - public static function GetAbsoluteUrlAppRoot($bTrustProxy=false) + public static function GetAbsoluteUrlAppRoot($bForceTrustProxy = false) { static $sUrl = null; if ($sUrl === null) @@ -877,7 +895,7 @@ class utils $sUrl = self::GetConfig()->Get('app_root_url'); if ($sUrl == '') { - $sUrl = self::GetDefaultUrlAppRoot($bTrustProxy); + $sUrl = self::GetDefaultUrlAppRoot($bForceTrustProxy); } elseif (strpos($sUrl, SERVER_NAME_PLACEHOLDER) > -1) { @@ -901,33 +919,116 @@ class utils * For most usages, when an root url is needed, use utils::GetAbsoluteUrlAppRoot() instead as uses this only as a fallback when the * app_root_url conf parameter is not defined. * - * @param bool $bTrustProxy - * + * @param bool $bForceTrustProxy + * * @return string * * @throws \Exception - */ - public static function GetDefaultUrlAppRoot($bTrustProxy=false) + * + * @since 2.7.4 $bForceTrustProxy param added + */ + public static function GetDefaultUrlAppRoot($bForceTrustProxy = false) + { + $sAbsoluteUrl = self::GetCurrentAbsoluteUrl($bForceTrustProxy, true); + + $sCurrentScript = realpath($_SERVER['SCRIPT_FILENAME']); + $sAppRoot = realpath(APPROOT); + + return self::GetAppRootUrl($sCurrentScript, $sAppRoot, $sAbsoluteUrl); + } + + + /** + * Build the current absolute URL from the server's variables. + * + * For almost every usage, you should use the more secure utils::GetAbsoluteUrlAppRoot() : instead of reading the current uri, it provide you the configured application's root URL (this is done during the setup and chn be changed in the configuration file) + * + * @see utils::GetAbsoluteUrlAppRoot + * + * @param bool $bForceTrustProxy + * @param bool $bTrimQueryString + * + * @return string + * + * @since 2.7.4 + */ + public static function GetCurrentAbsoluteUrl($bForceTrustProxy = false, $bTrimQueryString = false) { // Build an absolute URL to this page on this server/port - $sServerName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : ''; - $sProtocol = self::IsConnectionSecure($bTrustProxy) ? 'https' : 'http'; - $iPort = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : 80; - if ($sProtocol == 'http') - { + $sServerName = self::GetServerName($bForceTrustProxy); + $bIsSecure = self::IsConnectionSecure($bForceTrustProxy); + $sProtocol = $bIsSecure ? 'https' : 'http'; + $iPort = self::GetServerPort($bForceTrustProxy); + if ($bIsSecure) { + $sPort = ($iPort == 443) ? '' : ':'.$iPort; + } else { $sPort = ($iPort == 80) ? '' : ':'.$iPort; } - else - { - $sPort = ($iPort == 443) ? '' : ':'.$iPort; + + $sPath = self::GetRequestUri($bForceTrustProxy); + + if ($bTrimQueryString) { + // remove all the parameters from the query string + $iQuestionMarkPos = strpos($sPath, '?'); + if ($iQuestionMarkPos !== false) { + $sPath = substr($sPath, 0, $iQuestionMarkPos); + } } + + $sAbsoluteUrl = "$sProtocol://{$sServerName}{$sPort}{$sPath}"; + + return $sAbsoluteUrl; + } + + /** + * @param bool $bForceTrustProxy + * + * @return string + * + * @since 2.7.4 + */ + public static function GetServerName($bForceTrustProxy = false) + { + $bTrustProxy = $bForceTrustProxy || self::IsProxyTrusted(); + + $sServerName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : ''; + + if ($bTrustProxy) { + $sServerName = isset($_SERVER['HTTP_X_FORWARDED_HOST']) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : $sServerName; + } + + return $sServerName; + } + + /** + * @param bool $bForceTrustProxy + * + * @return int|mixed + * @since 2.7.4 + */ + public static function GetServerPort($bForceTrustProxy = false) + { + $bTrustProxy = $bForceTrustProxy || self::IsProxyTrusted(); + + $sServerPort = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : 80; + + if ($bTrustProxy) { + $sServerPort = isset($_SERVER['HTTP_X_FORWARDED_PORT']) ? $_SERVER['HTTP_X_FORWARDED_PORT'] : $sServerPort; + } + + return $sServerPort; + } + + /** + * @return string + * + * @since 2.7.4 + */ + public static function GetRequestUri() + { // $_SERVER['REQUEST_URI'] is empty when running on IIS // Let's use Ivan Tcholakov's fix (found on www.dokeos.com) - if (!empty($_SERVER['REQUEST_URI'])) - { - $sPath = $_SERVER['REQUEST_URI']; - } - else + if (empty($_SERVER['REQUEST_URI'])) { $sPath = $_SERVER['SCRIPT_NAME']; if (!empty($_SERVER['QUERY_STRING'])) @@ -938,18 +1039,7 @@ class utils } $sPath = $_SERVER['REQUEST_URI']; - // remove all the parameters from the query string - $iQuestionMarkPos = strpos($sPath, '?'); - if ($iQuestionMarkPos !== false) - { - $sPath = substr($sPath, 0, $iQuestionMarkPos); - } - $sAbsoluteUrl = "$sProtocol://{$sServerName}{$sPort}{$sPath}"; - - $sCurrentScript = realpath($_SERVER['SCRIPT_FILENAME']); - $sAppRoot = realpath(APPROOT); - - return self::GetAppRootUrl($sCurrentScript, $sAppRoot, $sAbsoluteUrl); + return $sPath; } /** @@ -1015,28 +1105,32 @@ class utils /** * Helper to handle the variety of HTTP servers * See N°286 (fixed in [896]), and N°634 (this fix) - * + * * Though the official specs says 'a non empty string', some servers like IIS do set it to 'off' ! * nginx set it to an empty string - * Others might leave it unset (no array entry) + * Others might leave it unset (no array entry) * - * @param bool $bTrustProxy + * @param bool $bForceTrustProxy * * @return bool - */ - public static function IsConnectionSecure($bTrustProxy=false) + * + * @since 2.7.4 reverse proxies handling + */ + public static function IsConnectionSecure($bForceTrustProxy = false) { $bSecured = false; - if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $bTrustProxy) + $bTrustProxy = $bForceTrustProxy || self::IsProxyTrusted(); + + if ($bTrustProxy && !empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) { $bSecured = ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https'); } - elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTOCOL']) && $bTrustProxy) + elseif ($bTrustProxy && !empty($_SERVER['HTTP_X_FORWARDED_PROTOCOL'])) { $bSecured = ($_SERVER['HTTP_X_FORWARDED_PROTOCOL'] === 'https'); } - elseif (isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS'])) + elseif ((!empty($_SERVER['HTTPS'])) && (strtolower($_SERVER['HTTPS']) != 'off')) { $bSecured = (strcasecmp($_SERVER['HTTPS'], 'off') !== 0); } @@ -2550,10 +2644,10 @@ class utils public static function GetCkeditorPref() { $sLanguage = strtolower(trim(UserRights::GetUserLanguage())); - + $aDefaultConf = array( 'language'=> $sLanguage, - 'contentsLanguage' => $sLanguage, + 'contentsLanguage' => $sLanguage, 'extraPlugins' => 'disabler,codesnippet,mentions', ); @@ -2587,10 +2681,10 @@ HTML; ]; } } - + $aRichTextConfig = json_decode(appUserPreferences::GetPref('richtext_config', '{}'), true); - + return array_merge($aDefaultConf, $aRichTextConfig); } @@ -2601,4 +2695,5 @@ HTML; public static function IsWindowsEnvironment(){ return (substr(PHP_OS,0,3) === 'WIN'); } + } diff --git a/core/config.class.inc.php b/core/config.class.inc.php index a2869c033..d38b0ce1d 100644 --- a/core/config.class.inc.php +++ b/core/config.class.inc.php @@ -1365,7 +1365,16 @@ class Config 'source_of_value' => '', 'show_in_conf_sample' => false, ], - ]; + 'trust_proxies' => [ + 'type' => 'bool', + 'description' => 'If true, then proxies custom header (X-Forwarded-*) are taken into account. Use only if the webserver is not publicly accessible (reachable only by the reverse proxy)', + 'default' => false, + 'value' => false, + 'source_of_value' => '', + 'show_in_conf_sample' => false, + ], + ); + public function IsProperty($sPropCode) diff --git a/datamodels/2.x/itop-attachments/module.itop-attachments.php b/datamodels/2.x/itop-attachments/module.itop-attachments.php index d7a446482..ae80af784 100644 --- a/datamodels/2.x/itop-attachments/module.itop-attachments.php +++ b/datamodels/2.x/itop-attachments/module.itop-attachments.php @@ -81,6 +81,30 @@ if (!class_exists('AttachmentInstaller')) return $oConfiguration; } + /** + * @param string $sTableName + * @param int $iBulkSize + * + * @return array + * @throws \CoreException + * @throws \MySQLException + * @throws \MySQLHasGoneAwayException + */ + public static function GetOrphanAttachmentIds($sTableName, $iBulkSize){ + $sSqlQuery = <<fetch_array()){ + $aIds[] = $aRow['attachment_id']; + } + + return $aIds; + } + /** * Handler called before creating or upgrading the database schema * @param $oConfiguration Config The new configuration of the application @@ -99,9 +123,31 @@ if (!class_exists('AttachmentInstaller')) if ($iCount > 0) { SetupLog::Info("Cleanup of orphan attachments that cannot be migrated to the new ObjKey model: $iCount record(s) must be deleted."); - $sRepairQuery = "DELETE FROM `$sTableName` WHERE (`item_id`='' OR `item_id` IS NULL)"; - $iRet = CMDBSource::Query($sRepairQuery); // Throws an exception in case of error - SetupLog::Info("Cleanup of orphan attachments successfully completed."); + + $iBulkSize = 100; + $iMaxDuration = 30; + $iDeletedCount = 0; + $fStartTime = microtime(true); + $aIds = self::GetOrphanAttachmentIds($sTableName, $iBulkSize); + + while (count($aIds) !== 0) { + $sCleanupQuery = sprintf("DELETE FROM `$sTableName` WHERE `id` IN (%s)", implode(",", $aIds)); + CMDBSource::Query($sCleanupQuery); // Throws an exception in case of error + + $iDeletedCount += count($aIds); + $fElapsed = microtime(true) - $fStartTime; + + if ($fElapsed > $iMaxDuration){ + SetupLog::Info(sprintf("Cleanup of orphan attachments interrupted after %.3f s. $iDeletedCount records were deleted among $iCount.", $fElapsed)); + break; + } + + $aIds = self::GetOrphanAttachmentIds($sTableName, $iBulkSize); + } + + if (count($aIds) === 0){ + SetupLog::Info("Cleanup of orphan attachments successfully completed."); + } } else { @@ -109,7 +155,7 @@ if (!class_exists('AttachmentInstaller')) } } } - + /** * Handler called after the creation/update of the database schema * @param $oConfiguration Config The new configuration of the application @@ -124,6 +170,7 @@ if (!class_exists('AttachmentInstaller')) // Prerequisite: change null into 0 (workaround to the fact that we cannot use IS NULL in OQL) SetupLog::Info("Initializing attachment/item_org_id - null to zero"); $sTableName = MetaModel::DBGetTable('Attachment'); + $sRepair = "UPDATE `$sTableName` SET `item_org_id` = 0 WHERE `item_org_id` IS NULL"; CMDBSource::Query($sRepair); @@ -133,7 +180,13 @@ if (!class_exists('AttachmentInstaller')) $iUpdated = 0; while ($oAttachment = $oSet->Fetch()) { + if (empty($oAttachment->Get('item_class'))) { + //do not treat orphan attachment + continue; + } + $oContainer = MetaModel::GetObject($oAttachment->Get('item_class'), $oAttachment->Get('item_id'), false /* must be found */, true /* allow all data */); + if ($oContainer) { $oAttachment->SetItem($oContainer, true /*updateonchange*/); diff --git a/setup/applicationinstaller.class.inc.php b/setup/applicationinstaller.class.inc.php index c4a4e5412..e7f3a2d75 100644 --- a/setup/applicationinstaller.class.inc.php +++ b/setup/applicationinstaller.class.inc.php @@ -623,7 +623,7 @@ class ApplicationInstaller $oMFCompiler = new MFCompiler($oFactory, $sEnvironment); $oMFCompiler->Compile($sTargetPath, null, $bUseSymbolicLinks); //$aCompilerLog = $oMFCompiler->GetLog(); - //SetupPage::log_info(implode("\n", $aCompilerLog)); + //SetupLog::Info(implode("\n", $aCompilerLog)); SetupLog::Info("Data model successfully compiled to '$sTargetPath'."); $sCacheDir = APPROOT.'/data/cache-'.$sEnvironment.'/'; @@ -727,10 +727,15 @@ class ApplicationInstaller SetupLog::Info("There are $iOrphanCount useless records in {$sDBPrefix}priv_change (".sprintf('%.2f', ((100.0*$iOrphanCount)/$iTotalCount))."%)"); if ($iOrphanCount > 0) { - SetupLog::Info("Removing the orphan records..."); - $sCleanup = "DELETE FROM `{$sDBPrefix}priv_change` USING `{$sDBPrefix}priv_change` LEFT JOIN `{$sDBPrefix}priv_changeop` ON `{$sDBPrefix}priv_change`.id = `{$sDBPrefix}priv_changeop`.changeid WHERE `{$sDBPrefix}priv_changeop`.id IS NULL;"; - CMDBSource::Query($sCleanup); - SetupLog::Info("Cleanup completed successfully."); + if ($iOrphanCount > 100000) + { + SetupLog::Info("There are too much useless records ($iOrphanCount) in {$sDBPrefix}priv_change. Cleanup cannot be done during setup."); + } else { + SetupLog::Info("Removing the orphan records..."); + $sCleanup = "DELETE FROM `{$sDBPrefix}priv_change` USING `{$sDBPrefix}priv_change` LEFT JOIN `{$sDBPrefix}priv_changeop` ON `{$sDBPrefix}priv_change`.id = `{$sDBPrefix}priv_changeop`.changeid WHERE `{$sDBPrefix}priv_changeop`.id IS NULL;"; + CMDBSource::Query($sCleanup); + SetupLog::Info("Cleanup completed successfully."); + } } else { diff --git a/setup/wizardsteps.class.inc.php b/setup/wizardsteps.class.inc.php index 03eda054e..a8e85b425 100644 --- a/setup/wizardsteps.class.inc.php +++ b/setup/wizardsteps.class.inc.php @@ -987,14 +987,14 @@ class WizStepMiscParams extends WizardStep $oPage->add('
'); $oPage->add('Application URL'); $oPage->add(''); - $oPage->add(''); - $oPage->add(''); + $oPage->add(''); + $oPage->add(''); $oPage->add('
URL:
Change the value above if the end-users will be accessing the application by another path due to a specific configuration of the web server.
URL:
Change the value above if the end-users will be accessing the application by another path due to a specific configuration of the web server.
'); $oPage->add('
'); $oPage->add('
'); $oPage->add('Path to Graphviz\' dot application'); $oPage->add(''); - $oPage->add(''); + $oPage->add(''); $oPage->add(''); $oPage->add(''); $oPage->add('
Path:
Path:
Graphviz is required to display the impact analysis graph (i.e. impacts / depends on).
'); @@ -1126,21 +1126,21 @@ class WizStepUpgradeMiscParams extends WizardStep public function Display(WebPage $oPage) { - $sApplicationURL = $this->oWizard->GetParameter('application_url', utils::GetDefaultUrlAppRoot(true)); + $sApplicationURL = $this->oWizard->GetParameter('application_url', utils::GetAbsoluteUrlAppRoot(true)); //Preserve existing configuration. $sDefaultGraphvizPath = (strtolower(substr(PHP_OS, 0, 3)) === 'win') ? 'C:\\Program Files\\Graphviz\\bin\\dot.exe' : '/usr/bin/dot'; $sGraphvizPath = $this->oWizard->GetParameter('graphviz_path', $sDefaultGraphvizPath); $oPage->add('

Additional parameters

'); $oPage->add('
'); $oPage->add('Application URL'); $oPage->add(''); - $oPage->add(''); - $oPage->add(''); + $oPage->add(''); + $oPage->add(''); $oPage->add('
URL:
Change the value above if the end-users will be accessing the application by another path due to a specific configuration of the web server.
URL:
Change the value above if the end-users will be accessing the application by another path due to a specific configuration of the web server.
'); $oPage->add('
'); $oPage->add('
'); $oPage->add('Path to Graphviz\' dot application'); $oPage->add(''); - $oPage->add(''); + $oPage->add(''); $oPage->add(''); $oPage->add(''); $oPage->add('
Path:
Path:
Graphviz is required to display the impact analysis graph (i.e. impacts / depends on).
'); diff --git a/test/application/UtilsTest.php b/test/application/UtilsTest.php index 04f6e9463..02a9bd8c1 100644 --- a/test/application/UtilsTest.php +++ b/test/application/UtilsTest.php @@ -168,4 +168,151 @@ class UtilsTest extends \Combodo\iTop\Test\UnitTest\ItopTestCase ); } + /** + * @dataProvider GetDefaultUrlAppRootProvider + */ + public function testGetDefaultUrlAppRoot($bForceTrustProxy, $bConfTrustProxy, $aServerVars, $sExpectedAppRootUrl) + { + $_SERVER = $aServerVars; + utils::GetConfig()->Set('trust_proxies', $bConfTrustProxy); + $sAppRootUrl = utils::GetDefaultUrlAppRoot($bForceTrustProxy); + $this->assertEquals($sExpectedAppRootUrl, $sAppRootUrl); + } + + public function GetDefaultUrlAppRootProvider() + { + $this->setUp(); + + $baseServerVar = [ + 'REMOTE_ADDR' => '127.0.0.1', //is not set, disable IsProxyTrusted + 'SERVER_NAME' => 'example.com', + 'HTTP_X_FORWARDED_HOST' => null, + 'SERVER_PORT' => '80', + 'HTTP_X_FORWARDED_PORT' => null, + 'REQUEST_URI' => '/index.php?baz=1', + 'SCRIPT_NAME' => '/index.php', + 'SCRIPT_FILENAME' => APPROOT.'index.php', + 'QUERY_STRING' => 'baz=1', + 'HTTP_X_FORWARDED_PROTO' => null, + 'HTTP_X_FORWARDED_PROTOCOL' => null, + 'HTTPS' => null, + ]; + + return [ + 'no proxy, http' => [ + 'bForceTrustProxy' => false, + 'bConfTrustProxy' => false, + 'aServerVars' => array_merge($baseServerVar, []), + 'sExpectedAppRootUrl' => 'http://example.com/', + ], + 'no proxy, subPath, http' => [ + 'bForceTrustProxy' => false, + 'bConfTrustProxy' => false, + 'aServerVars' => array_merge($baseServerVar, [ + 'REQUEST_URI' => '/foo/index.php?baz=1', + ]), + 'sExpectedAppRootUrl' => 'http://example.com/foo/', + ], + 'IIS lack REQUEST_URI' => [ + 'bForceTrustProxy' => false, + 'bConfTrustProxy' => false, + 'aServerVars' => array_merge($baseServerVar, [ + 'REQUEST_URI' => null, + 'SCRIPT_NAME' => '/foo/index.php', + ]), + 'sExpectedAppRootUrl' => 'http://example.com/foo/', + ], + 'no proxy, https' => [ + 'bForceTrustProxy' => false, + 'bConfTrustProxy' => false, + 'aServerVars' => array_merge($baseServerVar, [ + 'SERVER_PORT' => '443', + 'HTTPS' => 'on', + ]), + 'sExpectedAppRootUrl' => 'https://example.com/', + ], + 'no proxy, https on 4443' => [ + 'bForceTrustProxy' => false, + 'bConfTrustProxy' => false, + 'aServerVars' => array_merge($baseServerVar, [ + 'SERVER_PORT' => '4443', + 'HTTPS' => 'on', + ]), + 'sExpectedAppRootUrl' => 'https://example.com:4443/', + ], + 'with proxy, not enabled' => [ + 'bForceTrustProxy' => false, + 'bConfTrustProxy' => false, + 'aServerVars' => array_merge($baseServerVar, [ + 'HTTP_X_FORWARDED_HOST' => 'proxy.com', + 'HTTP_X_FORWARDED_PORT' => '4443', + 'HTTP_X_FORWARDED_PROTO' => 'https', + ]), + 'sExpectedAppRootUrl' => 'http://example.com/', + ], + 'with proxy, enabled' => [ + 'bForceTrustProxy' => false, + 'bConfTrustProxy' => true, + 'aServerVars' => array_merge($baseServerVar, [ + 'HTTP_X_FORWARDED_HOST' => 'proxy.com', + 'HTTP_X_FORWARDED_PORT' => '4443', + 'HTTP_X_FORWARDED_PROTO' => 'https', + ]), + 'sExpectedAppRootUrl' => 'https://proxy.com:4443/', + ], + 'with proxy, enabled - alt' => [ + 'bForceTrustProxy' => false, + 'bConfTrustProxy' => true, + 'aServerVars' => array_merge($baseServerVar, [ + 'HTTP_X_FORWARDED_HOST' => 'proxy.com', + 'HTTP_X_FORWARDED_PORT' => '4443', + 'HTTP_X_FORWARDED_PROTOCOL' => 'https', + ]), + 'sExpectedAppRootUrl' => 'https://proxy.com:4443/', + ], + 'with proxy, disabled, forced' => [ + 'bForceTrustProxy' => true, + 'bConfTrustProxy' => false, + 'aServerVars' => array_merge($baseServerVar, [ + 'HTTP_X_FORWARDED_HOST' => 'proxy.com', + 'HTTP_X_FORWARDED_PORT' => '4443', + 'HTTP_X_FORWARDED_PROTO' => 'https', + ]), + 'sExpectedAppRootUrl' => 'https://proxy.com:4443/', + ], + 'with proxy, enabled, forced' => [ + 'bForceTrustProxy' => true, + 'bConfTrustProxy' => true, + 'aServerVars' => array_merge($baseServerVar, [ + 'HTTP_X_FORWARDED_HOST' => 'proxy.com', + 'HTTP_X_FORWARDED_PORT' => '4443', + 'HTTP_X_FORWARDED_PROTO' => 'https', + ]), + 'sExpectedAppRootUrl' => 'https://proxy.com:4443/', + ], + + 'with proxy, disabled, forced, no remote addr' => [ + 'bForceTrustProxy' => true, + 'bConfTrustProxy' => false, + 'aServerVars' => array_merge($baseServerVar, [ + 'REMOTE_ADDR' => null, + 'HTTP_X_FORWARDED_HOST' => 'proxy.com', + 'HTTP_X_FORWARDED_PORT' => '4443', + 'HTTP_X_FORWARDED_PROTO' => 'https', + ]), + 'sExpectedAppRootUrl' => 'https://proxy.com:4443/', + ], + 'with proxy, enabled, no remote addr' => [ + 'bForceTrustProxy' => false, + 'bConfTrustProxy' => true, + 'aServerVars' => array_merge($baseServerVar, [ + 'REMOTE_ADDR' => null, + 'HTTP_X_FORWARDED_HOST' => 'proxy.com', + 'HTTP_X_FORWARDED_PORT' => '4443', + 'HTTP_X_FORWARDED_PROTO' => 'https', + ]), + 'sExpectedAppRootUrl' => 'http://example.com/', + ], + ]; + } }