return $this->getService( 'TitleParser' );
}
+ /**
+ * @since 1.28
+ * @return \BagOStuff
+ */
+ public function getMainObjectStash() {
+ return $this->getService( 'MainObjectStash' );
+ }
+
+ /**
+ * @since 1.28
+ * @return \WANObjectCache
+ */
+ public function getMainWANObjectCache() {
+ return $this->getService( 'MainWANObjectCache' );
+ }
+
+ /**
+ * @since 1.28
+ * @return \BagOStuff
+ */
+ public function getLocalServerObjectCache() {
+ return $this->getService( 'LocalServerObjectCache' );
+ }
+
/**
* @since 1.28
* @return VirtualRESTServiceClient
| url\s*\(
| image\s*\(
| image-set\s*\(
+ | attr\s*\([^)]+[\s,]+url
!ix', $value ) ) {
return '/* insecure input */';
}
return $services->getService( '_MediaWikiTitleCodec' );
},
+ 'MainObjectStash' => function( MediaWikiServices $services ) {
+ $mainConfig = $services->getMainConfig();
+
+ $id = $mainConfig->get( 'MainStash' );
+ if ( !isset( $mainConfig->get( 'ObjectCaches' )[$id] ) ) {
+ throw new UnexpectedValueException(
+ "Cache type \"$id\" is not present in \$wgObjectCaches." );
+ }
+
+ return \ObjectCache::newFromParams( $mainConfig->get( 'ObjectCaches' )[$id] );
+ },
+
+ 'MainWANObjectCache' => function( MediaWikiServices $services ) {
+ $mainConfig = $services->getMainConfig();
+
+ $id = $mainConfig->get( 'MainWANCache' );
+ if ( !isset( $mainConfig->get( 'WANObjectCaches' )[$id] ) ) {
+ throw new UnexpectedValueException(
+ "WAN cache type \"$id\" is not present in \$wgWANObjectCaches." );
+ }
+
+ $params = $mainConfig->get( 'WANObjectCaches' )[$id];
+ $objectCacheId = $params['cacheId'];
+ if ( !isset( $mainConfig->get( 'ObjectCaches' )[$objectCacheId] ) ) {
+ throw new UnexpectedValueException(
+ "Cache type \"$objectCacheId\" is not present in \$wgObjectCaches." );
+ }
+ $params['store'] = $mainConfig->get( 'ObjectCaches' )[$objectCacheId];
+
+ return \ObjectCache::newWANCacheFromParams( $params );
+ },
+
+ 'LocalServerObjectCache' => function( MediaWikiServices $services ) {
+ $mainConfig = $services->getMainConfig();
+
+ if ( function_exists( 'apc_fetch' ) ) {
+ $id = 'apc';
+ } elseif ( function_exists( 'xcache_get' ) && wfIniGetBool( 'xcache.var_size' ) ) {
+ $id = 'xcache';
+ } elseif ( function_exists( 'wincache_ucache_get' ) ) {
+ $id = 'wincache';
+ } else {
+ $id = CACHE_NONE;
+ }
+
+ if ( !isset( $mainConfig->get( 'ObjectCaches' )[$id] ) ) {
+ throw new UnexpectedValueException(
+ "Cache type \"$id\" is not present in \$wgObjectCaches." );
+ }
+
+ return \ObjectCache::newFromParams( $mainConfig->get( 'ObjectCaches' )[$id] );
+ },
+
'VirtualRESTServiceClient' => function( MediaWikiServices $services ) {
$config = $services->getMainConfig()->get( 'VirtualRestConfig' );
private $continuationData = [];
private $generatorContinuationData = [];
+ private $generatorNonContinuationData = [];
private $generatorParams = [];
private $generatorDone = false;
$this->continuationData[$name][$paramName] = $paramValue;
}
+ /**
+ * Set the non-continuation parameter for the generator module
+ *
+ * In case the generator isn't going to be continued, this sets the fields
+ * to return.
+ *
+ * @since 1.28
+ * @param ApiBase $module
+ * @param string $paramName
+ * @param string|array $paramValue
+ */
+ public function addGeneratorNonContinueParam( ApiBase $module, $paramName, $paramValue ) {
+ $name = $module->getModuleName();
+ $paramName = $module->encodeParamName( $paramName );
+ if ( is_array( $paramValue ) ) {
+ $paramValue = implode( '|', $paramValue );
+ }
+ $this->generatorNonContinuationData[$name][$paramName] = $paramValue;
+ }
+
/**
* Set the continuation parameter for the generator module
* @param ApiBase $module
return array_merge_recursive( $this->continuationData, $this->generatorContinuationData );
}
+ /**
+ * Fetch raw non-continuation data
+ * @since 1.28
+ * @return array
+ */
+ public function getRawNonContinuation() {
+ return $this->generatorNonContinuationData;
+ }
+
/**
* Fetch continuation result data
* @return array [ (array)$data, (bool)$batchcomplete ]
foreach ( $continuationData as $module => $kvp ) {
$data += $kvp;
}
- $data += $this->generatorParams;
- $generatorKeys = implode( '|', array_keys( $this->generatorParams ) );
+ $generatorParams = [];
+ foreach ( $this->generatorNonContinuationData as $kvp ) {
+ $generatorParams += $kvp;
+ }
+ $generatorParams += $this->generatorParams;
+ $data += $generatorParams;
+ $generatorKeys = implode( '|', array_keys( $generatorParams ) );
} elseif ( $this->generatorContinuationData ) {
// All the generator-using modules are complete, but the
// generator isn't. Continue the generator and restart the
// Write the continuation data into the result
$this->setContinuationManager( null );
if ( $this->mParams['rawcontinue'] ) {
+ $data = $continuationManager->getRawNonContinuation();
+ if ( $data ) {
+ $this->getResult()->addValue( null, 'query-noncontinue', $data,
+ ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK );
+ }
$data = $continuationManager->getRawContinuation();
if ( $data ) {
$this->getResult()->addValue( null, 'query-continue', $data,
$nextIndex = 0;
$generated = [];
foreach ( $res as $row ) {
+ if ( $count === 0 && $resultPageSet !== null ) {
+ // Set the non-continue since the list of all revisions is
+ // prone to having entries added at the start frequently.
+ $this->getContinuationManager()->addGeneratorNonContinueParam(
+ $this, 'continue', "$row->rev_timestamp|$row->rev_id"
+ );
+ }
if ( ++$count > $this->limit ) {
// We've had enough
$this->setContinueEnumParameter( 'continue', "$row->rev_timestamp|$row->rev_id" );
/* Iterate through the rows, adding data extracted from them to our query result. */
foreach ( $res as $row ) {
+ if ( $count === 0 && $resultPageSet !== null ) {
+ // Set the non-continue since the list of recentchanges is
+ // prone to having entries added at the start frequently.
+ $this->getContinuationManager()->addGeneratorNonContinueParam(
+ $this, 'continue', "$row->rc_timestamp|$row->rc_id"
+ );
+ }
if ( ++$count > $params['limit'] ) {
// We've reached the one extra which shows that there are
// additional pages to be had. Stop here...
* // From $wgObjectCaches via newFromParams()
* ObjectCache::getLocalServerInstance( [ 'fallback' => $fallbackType ] );
*
- * @param int|string|array $fallback Fallback cache or parameter map with 'fallback'
+ * @param int|string $fallback Fallback cache ID
* @return BagOStuff
* @throws InvalidArgumentException
* @since 1.27
+ * @deprecated Since 1.28; use MediaWikiServices::getLocalServerObjectCache
*/
public static function getLocalServerInstance( $fallback = CACHE_NONE ) {
- if ( function_exists( 'apc_fetch' ) ) {
- $id = 'apc';
- } elseif ( function_exists( 'xcache_get' ) && wfIniGetBool( 'xcache.var_size' ) ) {
- $id = 'xcache';
- } elseif ( function_exists( 'wincache_ucache_get' ) ) {
- $id = 'wincache';
- } else {
- if ( is_array( $fallback ) ) {
- $id = isset( $fallback['fallback'] ) ? $fallback['fallback'] : CACHE_NONE;
- } else {
- $id = $fallback;
- }
- }
+ $cache = MediaWikiServices::getInstance()->getLocalServerObjectCache();
- return self::getInstance( $id );
+ return ( $cache instanceof EmptyBagOStuff )
+ ? self::getInstance( $fallback )
+ : $cache;
}
/**
*
* @since 1.26
* @return WANObjectCache
+ * @deprecated Since 1.28 Use MediaWikiServices::getMainWANCache()
*/
public static function getMainWANInstance() {
- global $wgMainWANCache;
-
- return self::getWANInstance( $wgMainWANCache );
+ return MediaWikiServices::getInstance()->getMainWANObjectCache();
}
/**
*
* @return BagOStuff
* @since 1.26
+ * @deprecated Since 1.28 Use MediaWikiServices::getMainObjectStash
*/
public static function getMainStashInstance() {
- global $wgMainStash;
-
- return self::getInstance( $wgMainStash );
+ return MediaWikiServices::getInstance()->getMainObjectStash();
}
/**
*/
use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\MediaWikiServices;
// This endpoint is supposed to be independent of request cookies and other
// details of the session. Enforce this constraint with respect to session use.
return;
}
+// Don't initialise ChronologyProtector from object cache, and
+// don't wait for unrelated MediaWiki writes when querying ResourceLoader.
+MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->setRequestInfo( [
+ 'ChronologyProtection' => 'false',
+] );
+
// Set up ResourceLoader
$resourceLoader = new ResourceLoader(
ConfigFactory::getDefaultInstance()->makeConfig( 'main' ),
JobQueueGroup::destroySingletons();
ObjectCache::clear();
+ $services = MediaWikiServices::getInstance();
+ $services->resetServiceForTesting( 'MainObjectStash' );
+ $services->resetServiceForTesting( 'LocalServerObjectCache' );
+ $services->getMainWANObjectCache()->clearProcessCache();
FileBackendGroup::destroySingleton();
// TODO: move global state into MediaWikiServices
'_MediaWikiTitleCodec' => [ '_MediaWikiTitleCodec', MediaWikiTitleCodec::class ],
'TitleFormatter' => [ 'TitleFormatter', TitleFormatter::class ],
'TitleParser' => [ 'TitleParser', TitleParser::class ],
- 'VirtualRESTServiceClient' => [ 'VirtualRESTServiceClient', VirtualRESTServiceClient::class ],
- 'ProxyLookup' => [ 'ProxyLookup', ProxyLookup::class ]
+ 'ProxyLookup' => [ 'ProxyLookup', ProxyLookup::class ],
+ 'MainObjectStash' => [ 'MainObjectStash', BagOStuff::class ],
+ 'MainWANObjectCache' => [ 'MainWANObjectCache', WANObjectCache::class ],
+ 'LocalServerObjectCache' => [ 'LocalServerObjectCache', BagOStuff::class ],
+ 'VirtualRESTServiceClient' => [ 'VirtualRESTServiceClient', VirtualRESTServiceClient::class ]
];
}
'/* insecure input */',
'background-image: -moz-image-set("asdf.png" 1x, "asdf.png" 2x);'
],
+ [ '/* insecure input */', 'foo: attr( title, url );' ],
+ [ '/* insecure input */', 'foo: attr( title url );' ],
];
}