diff --git a/src/infrastructure/markup/markuprule/PhutilRemarkupDocumentLinkRule.php b/src/infrastructure/markup/markuprule/PhutilRemarkupDocumentLinkRule.php --- a/src/infrastructure/markup/markuprule/PhutilRemarkupDocumentLinkRule.php +++ b/src/infrastructure/markup/markuprule/PhutilRemarkupDocumentLinkRule.php @@ -76,7 +76,19 @@ return $name; } - $same_window = $engine->getConfig('uri.same-window', false); + $same_window = $engine->getConfig('uri.same-window', null); + + if ($same_window === null) { + // TODO: + // Instead of assuming every link as external, + // assume that only external links should be opened + // externally. This still probably creates lot of + // external links than needed, but less than before. + // https://we.phorge.it/T15161 +// $same_window = $this->isInternalGeneralURI($link); + $same_window = false; + } + if ($same_window) { $target = null; } else { diff --git a/src/infrastructure/markup/markuprule/PhutilRemarkupHyperlinkRule.php b/src/infrastructure/markup/markuprule/PhutilRemarkupHyperlinkRule.php --- a/src/infrastructure/markup/markuprule/PhutilRemarkupHyperlinkRule.php +++ b/src/infrastructure/markup/markuprule/PhutilRemarkupHyperlinkRule.php @@ -116,7 +116,19 @@ $engine = $this->getEngine(); - $same_window = $engine->getConfig('uri.same-window', false); + $same_window = $engine->getConfig('uri.same-window', null); + + if ($same_window === null) { + // TODO: + // Instead of assuming every link as external, + // assume that only external links should be opened + // externally. This still probably creates lot of + // external links than needed, but less than before. + // https://we.phorge.it/T15161 +// $same_window = $this->isInternalAbsoluteURI($link); + $same_window = false; + } + if ($same_window) { $target = null; } else { diff --git a/src/infrastructure/markup/markuprule/PhutilRemarkupRule.php b/src/infrastructure/markup/markuprule/PhutilRemarkupRule.php --- a/src/infrastructure/markup/markuprule/PhutilRemarkupRule.php +++ b/src/infrastructure/markup/markuprule/PhutilRemarkupRule.php @@ -130,4 +130,54 @@ return strncmp($uri, '/', 1) == 0; } + /** + * Check if a generic URI points to an internal destination + * + * The URI can be relative or absolute + * + * @param string $uri Example '/bar/' or 'http://example.com/bar/' + * @return bool + */ + protected function isInternalGenericURI($uri) { + return $this->isURIAnchor($uri) + || $this->isURIRelativePath($uri) + || $this->isInternalAbsoluteURI($uri); + } + + /** + * Check if an absolute URI points to Phorge/Phabricator itself + * + * @param string $uri Example 'http://example.com/bar/' + * @return bool + */ + protected function isInternalAbsoluteURI($uri) { + + // Get the Base URI - full URI with protocol and ending with '/' + // It's difficult to imagine a case where this config is not defined, + // but better to be nice here + $base_uri = + PhabricatorEnv::getEnvConfigIfExists('phabricator.base-uri', null); + + // Assume a safe default + if (!$base_uri) { + return false; + } + + return $this->isURIStartingWith($uri, $base_uri); + } + + /** + * Check whenever an URI starts with a specific prefix + * + * @param $uri string Example 'http://example.com/bar/' + * @param $prefix string Example 'http://example.com/' + * @return bool True if the first is contained in the second + */ + private function isURIStartingWith($uri, $prefix) { + // I know that PHP 8 has 'str_starts_with()' + // but that is not the minimum version + // https://stackoverflow.com/a/2790919 + return substr($uri, 0, strlen($prefix)) === $prefix; + } + }