$wgDBOracleDRCP = false;
/**
- * Other wikis on this site, can be administered from a single developer
- * account.
+ * Other wikis on this site, can be administered from a single developer account.
+ *
* Array numeric key => database name
*/
$wgLocalDatabases = [];
* subdomain thereof, then no proxy will be used.
* Command-line scripts are not affected by this setting and will always use
* the proxy if it is configured.
- * - ChronologyProtector: Decide to shutdown LBFactory asynchronously instead
- * synchronously if the current response redirects to a local virtual host.
*
* @since 1.25
*/
$request->wasPosted() &&
$output->getRedirect() &&
$lbFactory->hasOrMadeRecentMasterChanges( INF )
- ) ? self::getUrlDomainDistance( $output->getRedirect(), $context ) : false;
+ ) ? self::getUrlDomainDistance( $output->getRedirect() ) : false;
$allowHeaders = !( $output->isDisabled() || headers_sent() );
if ( $urlDomainDistance === 'local' || $urlDomainDistance === 'remote' ) {
/**
* @param string $url
- * @param IContextSource $context
* @return string Either "local", "remote" if in the farm, "external" otherwise
*/
- private static function getUrlDomainDistance( $url, IContextSource $context ) {
- static $relevantKeys = [ 'host' => true, 'port' => true ];
-
- $infoCandidate = wfParseUrl( $url );
- if ( $infoCandidate === false ) {
- return 'external';
- }
-
- $infoCandidate = array_intersect_key( $infoCandidate, $relevantKeys );
- $clusterHosts = array_merge(
- // Local wiki host (the most common case)
- [ $context->getConfig()->get( 'CanonicalServer' ) ],
- // Any local/remote wiki virtual hosts for this wiki farm
- $context->getConfig()->get( 'LocalVirtualHosts' )
- );
-
- foreach ( $clusterHosts as $i => $clusterHost ) {
- $parseUrl = wfParseUrl( $clusterHost );
- if ( !$parseUrl ) {
- continue;
- }
- $infoHost = array_intersect_key( $parseUrl, $relevantKeys );
- if ( $infoCandidate === $infoHost ) {
- return ( $i === 0 ) ? 'local' : 'remote';
- }
+ private static function getUrlDomainDistance( $url ) {
+ $clusterWiki = WikiMap::getWikiFromUrl( $url );
+ if ( $clusterWiki === wfWikiID() ) {
+ return 'local'; // the current wiki
+ } elseif ( $clusterWiki !== false ) {
+ return 'remote'; // another wiki in this cluster/farm
}
return 'external';
* @file
*/
+use MediaWiki\MediaWikiServices;
+
/**
- * Helper tools for dealing with other wikis.
+ * Helper tools for dealing with other locally-hosted wikis.
*/
class WikiMap {
* @return WikiReference|null WikiReference object or null if the wiki was not found
*/
private static function getWikiWikiReferenceFromSites( $wikiID ) {
- $siteLookup = \MediaWiki\MediaWikiServices::getInstance()->getSiteLookup();
+ $siteLookup = MediaWikiServices::getInstance()->getSiteLookup();
$site = $siteLookup->getSite( $wikiID );
if ( !$site instanceof MediaWikiSite ) {
return false;
}
+
+ /**
+ * Get canonical server info for all local wikis in the map that have one
+ *
+ * @return array Map of (local wiki ID => map of (url,parts))
+ * @since 1.30
+ */
+ public static function getCanonicalServerInfoForAllWikis() {
+ $cache = MediaWikiServices::getInstance()->getLocalServerObjectCache();
+
+ return $cache->getWithSetCallback(
+ $cache->makeGlobalKey( 'wikimap', 'canonical-urls' ),
+ $cache::TTL_DAY,
+ function () {
+ global $wgLocalDatabases, $wgCanonicalServer;
+
+ $infoMap = [];
+ // Make sure at least the current wiki is set, for simple configurations.
+ // This also makes it the first in the map, which is useful for common cases.
+ $infoMap[wfWikiID()] = [
+ 'url' => $wgCanonicalServer,
+ 'parts' => wfParseUrl( $wgCanonicalServer )
+ ];
+
+ foreach ( $wgLocalDatabases as $wikiId ) {
+ $wikiReference = self::getWiki( $wikiId );
+ if ( $wikiReference ) {
+ $url = $wikiReference->getCanonicalServer();
+ $infoMap[$wikiId] = [ 'url' => $url, 'parts' => wfParseUrl( $url ) ];
+ }
+ }
+
+ return $infoMap;
+ }
+ );
+ }
+
+ /**
+ * @param string $url
+ * @return bool|string Wiki ID or false
+ * @since 1.30
+ */
+ public static function getWikiFromUrl( $url ) {
+ $urlPartsCheck = wfParseUrl( $url );
+ if ( $urlPartsCheck === false ) {
+ return false;
+ }
+
+ $urlPartsCheck = array_intersect_key( $urlPartsCheck, [ 'host' => 1, 'port' => 1 ] );
+ foreach ( self::getCanonicalServerInfoForAllWikis() as $wikiId => $info ) {
+ $urlParts = $info['parts'];
+ if ( $urlParts === false ) {
+ continue; // sanity
+ }
+
+ $urlParts = array_intersect_key( $urlParts, [ 'host' => 1, 'port' => 1 ] );
+ if ( $urlParts == $urlPartsCheck ) {
+ return $wikiId;
+ }
+ }
+
+ return false;
+ }
}
'enwiki' => 'http://en.example.org',
'ruwiki' => '//ru.example.org',
'nopathwiki' => '//nopath.example.org',
+ 'thiswiki' => '//this.wiki.org'
],
'wgArticlePath' => [
'enwiki' => '/w/$1',
$conf->suffixes = [ 'wiki' ];
$this->setMwGlobals( [
'wgConf' => $conf,
+ 'wgLocalDatabases' => [ 'enwiki', 'ruwiki', 'nopathwiki' ],
+ 'wgCanonicalServer' => '//this.wiki.org',
+ 'wgDBname' => 'thiswiki',
+ 'wgDBprefix' => ''
] );
TestSites::insertIntoDb();
$this->assertEquals( $expected, WikiMap::getForeignURL( $wikiId, $page, $fragment ) );
}
+ /**
+ * @covers WikiMap::getCanonicalServerInfoForAllWikis()
+ */
+ public function testGetCanonicalServerInfoForAllWikis() {
+ $expected = [
+ 'thiswiki' => [
+ 'url' => '//this.wiki.org',
+ 'parts' => [ 'scheme' => '', 'host' => 'this.wiki.org', 'delimiter' => '//' ]
+ ],
+ 'enwiki' => [
+ 'url' => 'http://en.example.org',
+ 'parts' => [
+ 'scheme' => 'http', 'host' => 'en.example.org', 'delimiter' => '://' ]
+ ],
+ 'ruwiki' => [
+ 'url' => '//ru.example.org',
+ 'parts' => [ 'scheme' => '', 'host' => 'ru.example.org', 'delimiter' => '//' ]
+ ]
+ ];
+
+ $this->assertArrayEquals(
+ $expected,
+ WikiMap::getCanonicalServerInfoForAllWikis(),
+ true,
+ true
+ );
+ }
+
+ public function provideGetWikiFromUrl() {
+ return [
+ [ 'http://this.wiki.org', 'thiswiki' ],
+ [ 'https://this.wiki.org', 'thiswiki' ],
+ [ 'http://this.wiki.org/$1', 'thiswiki' ],
+ [ 'https://this.wiki.org/$2', 'thiswiki' ],
+ [ 'http://en.example.org', 'enwiki' ],
+ [ 'https://en.example.org', 'enwiki' ],
+ [ 'http://en.example.org/$1', 'enwiki' ],
+ [ 'https://en.example.org/$2', 'enwiki' ],
+ [ 'http://ru.example.org', 'ruwiki' ],
+ [ 'https://ru.example.org', 'ruwiki' ],
+ [ 'http://ru.example.org/$1', 'ruwiki' ],
+ [ 'https://ru.example.org/$2', 'ruwiki' ],
+ [ 'http://not.defined.org', false ]
+ ];
+ }
+
+ /**
+ * @dataProvider provideGetWikiFromUrl
+ * @covers WikiMap::getWikiFromUrl()
+ */
+ public function testGetWikiFromUrl( $url, $wiki ) {
+ $this->assertEquals( $wiki, WikiMap::getWikiFromUrl( $url ) );
+ }
}