X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FMediaWiki.php;h=8385a0670dd846cb8afc4485caded403ac6e5b0d;hb=9cd484dc3ba80da7b1537c7465f3ed7a9df9c3b8;hp=fe1bb8ec4dc82eedc047f08d4cb8acfcdc556edf;hpb=ec12adf649b522ea0bbf72833cd109f9c5377302;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/MediaWiki.php b/includes/MediaWiki.php index fe1bb8ec4d..8385a0670d 100644 --- a/includes/MediaWiki.php +++ b/includes/MediaWiki.php @@ -36,6 +36,11 @@ class MediaWiki { */ private $config; + /** + * @var String Cache what action this request is + */ + private $action; + /** * @param IContextSource|null $context */ @@ -141,13 +146,11 @@ class MediaWiki { * @return string Action */ public function getAction() { - static $action = null; - - if ( $action === null ) { - $action = Action::getActionName( $this->context ); + if ( $this->action === null ) { + $this->action = Action::getActionName( $this->context ); } - return $action; + return $this->action; } /** @@ -241,8 +244,37 @@ class MediaWiki { // Handle any other redirects. // Redirect loops, titleless URL, $wgUsePathInfo URLs, and URLs with a variant } elseif ( !$this->tryNormaliseRedirect( $title ) ) { + // Prevent information leak via Special:MyPage et al (T109724) + if ( $title->isSpecialPage() ) { + $specialPage = SpecialPageFactory::getPage( $title->getDBKey() ); + if ( $specialPage instanceof RedirectSpecialPage + && $this->config->get( 'HideIdentifiableRedirects' ) + && $specialPage->personallyIdentifiableTarget() + ) { + list( , $subpage ) = SpecialPageFactory::resolveAlias( $title->getDBKey() ); + $target = $specialPage->getRedirect( $subpage ); + // target can also be true. We let that case fall through to normal processing. + if ( $target instanceof Title ) { + $query = $specialPage->getRedirectQuery() ?: array(); + $request = new DerivativeRequest( $this->context->getRequest(), $query ); + $request->setRequestURL( $this->context->getRequest()->getRequestURL() ); + $this->context->setRequest( $request ); + // Do not varnish cache these. May vary even for anons + $this->context->getOutput()->lowerCdnMaxage( 0 ); + $this->context->setTitle( $target ); + $wgTitle = $target; + // Reset action type cache. (Special pages have only view) + $this->action = null; + $title = $target; + $output->addJsConfigVars( array( + 'wgInternalRedirectTargetUrl' => $target->getFullURL( $query ), + ) ); + $output->addModules( 'mediawiki.action.view.redirect' ); + } + } + } - // Special pages + // Special pages ($title may have changed since if statement above) if ( NS_SPECIAL == $title->getNamespace() ) { // Actions that need to be made when we have a special pages SpecialPageFactory::executePath( $title, $this->context ); @@ -347,23 +379,26 @@ class MediaWiki { * Initialize the main Article object for "standard" actions (view, etc) * Create an Article object for the page, following redirects if needed. * - * @return mixed An Article, or a string to redirect to another URL + * @return Article|string An Article, or a string to redirect to another URL */ private function initializeArticle() { - $title = $this->context->getTitle(); if ( $this->context->canUseWikiPage() ) { // Try to use request context wiki page, as there // is already data from db saved in per process // cache there from this->getAction() call. $page = $this->context->getWikiPage(); - $article = Article::newFromWikiPage( $page, $this->context ); } else { // This case should not happen, but just in case. - $article = Article::newFromTitle( $title, $this->context ); - $this->context->setWikiPage( $article->getPage() ); + // @TODO: remove this or use an exception + $page = WikiPage::factory( $title ); + $this->context->setWikiPage( $page ); + wfWarn( "RequestContext::canUseWikiPage() returned false" ); } + // Make GUI wrapper for the WikiPage + $article = Article::newFromWikiPage( $page, $this->context ); + // Skip some unnecessary code if the content model doesn't support redirects if ( !ContentHandler::getForTitle( $title )->supportsRedirects() ) { return $article; @@ -374,7 +409,7 @@ class MediaWiki { // Namespace might change when using redirects // Check for redirects ... $action = $request->getVal( 'action', 'view' ); - $file = ( $title->getNamespace() == NS_FILE ) ? $article->getFile() : null; + $file = ( $page instanceof WikiFilePage ) ? $page->getFile() : null; if ( ( $action == 'view' || $action == 'render' ) // ... for actions that show content && !$request->getVal( 'oldid' ) // ... and are not old revisions && !$request->getVal( 'diff' ) // ... and not when showing diff @@ -387,12 +422,13 @@ class MediaWiki { Hooks::run( 'InitializeArticleMaybeRedirect', array( &$title, &$request, &$ignoreRedirect, &$target, &$article ) ); + $page = $article->getPage(); // reflect any hook changes // Follow redirects only for... redirects. // If $target is set, then a hook wanted to redirect. - if ( !$ignoreRedirect && ( $target || $article->isRedirect() ) ) { + if ( !$ignoreRedirect && ( $target || $page->isRedirect() ) ) { // Is the target already set by an extension? - $target = $target ? $target : $article->followRedirect(); + $target = $target ? $target : $page->followRedirect(); if ( is_string( $target ) ) { if ( !$this->config->get( 'DisableHardRedirects' ) ) { // we'll need to redirect @@ -401,16 +437,19 @@ class MediaWiki { } if ( is_object( $target ) ) { // Rewrite environment to redirected article - $rarticle = Article::newFromTitle( $target, $this->context ); - $rarticle->loadPageData(); - if ( $rarticle->exists() || ( is_object( $file ) && !$file->isLocal() ) ) { + $rpage = WikiPage::factory( $target ); + $rpage->loadPageData(); + if ( $rpage->exists() || ( is_object( $file ) && !$file->isLocal() ) ) { + $rarticle = Article::newFromWikiPage( $rpage, $this->context ); $rarticle->setRedirectedFrom( $title ); + $article = $rarticle; $this->context->setTitle( $target ); $this->context->setWikiPage( $article->getPage() ); } } } else { + // Article may have been changed by hook $this->context->setTitle( $article->getTitle() ); $this->context->setWikiPage( $article->getPage() ); } @@ -426,7 +465,6 @@ class MediaWiki { * @param Title $requestTitle The original title, before any redirects were applied */ private function performAction( Page $page, Title $requestTitle ) { - $request = $this->context->getRequest(); $output = $this->context->getOutput(); $title = $this->context->getTitle(); @@ -439,10 +477,16 @@ class MediaWiki { } $act = $this->getAction(); - $action = Action::factory( $act, $page, $this->context ); if ( $action instanceof Action ) { + // Narrow DB query expectations for this HTTP request + $trxLimits = $this->config->get( 'TrxProfilerLimits' ); + $trxProfiler = Profiler::instance()->getTransactionProfiler(); + if ( $request->wasPosted() && !$action->doesWrites() ) { + $trxProfiler->setExpectations( $trxLimits['POST-nonwrite'], __METHOD__ ); + } + # Let CDN cache things if we can purge them. if ( $this->config->get( 'UseSquid' ) && in_array( @@ -462,7 +506,6 @@ class MediaWiki { $output->setStatusCode( 404 ); $output->showErrorPage( 'nosuchaction', 'nosuchactiontext' ); } - } /** @@ -508,21 +551,12 @@ class MediaWiki { $config = $context->getConfig(); $factory = wfGetLBFactory(); - // Check if any transaction was too big - $limit = $config->get( 'MaxUserDBWriteDuration' ); - $factory->forEachLB( function ( LoadBalancer $lb ) use ( $limit ) { - $lb->forEachOpenConnection( function ( IDatabase $db ) use ( $limit ) { - $time = $db->pendingWriteQueryDuration(); - if ( $limit > 0 && $time > $limit ) { - throw new DBTransactionError( - $db, - wfMessage( 'transaction-duration-limit-exceeded', $time, $limit )->plain() - ); - } - } ); - } ); // Commit all changes - $factory->commitMasterChanges(); + $factory->commitMasterChanges( + __METHOD__, + // Abort if any transaction was too big + array( 'maxWriteDuration' => $config->get( 'MaxUserDBWriteDuration' ) ) + ); // Record ChronologyProtector positions $factory->shutdown(); wfDebug( __METHOD__ . ': all transactions committed' ); @@ -530,15 +564,19 @@ class MediaWiki { DeferredUpdates::doUpdates( 'enqueue', DeferredUpdates::PRESEND ); wfDebug( __METHOD__ . ': pre-send deferred updates completed' ); - // Set a cookie to tell all CDN edge nodes to "stick" the user to the - // DC that handles this POST request (e.g. the "master" data center) + // Set a cookie to tell all CDN edge nodes to "stick" the user to the DC that handles this + // POST request (e.g. the "master" data center). Also have the user briefly bypass CDN so + // ChronologyProtector works for cacheable URLs. $request = $context->getRequest(); if ( $request->wasPosted() && $factory->hasOrMadeRecentMasterChanges() ) { $expires = time() + $config->get( 'DataCenterUpdateStickTTL' ); - $request->response()->setCookie( 'UseDC', 'master', $expires, array( 'prefix' => '' ) ); + $options = array( 'prefix' => '' ); + $request->response()->setCookie( 'UseDC', 'master', $expires, $options ); + $request->response()->setCookie( 'UseCDNCache', 'false', $expires, $options ); } - // Avoid letting a few seconds of slave lag cause a month of stale data + // Avoid letting a few seconds of slave lag cause a month of stale data. This logic is + // also intimately related to the value of $wgCdnReboundPurgeDelay. if ( $factory->laggedSlaveUsed() ) { $maxAge = $config->get( 'CdnMaxageLagged' ); $context->getOutput()->lowerCdnMaxage( $maxAge ); @@ -591,7 +629,7 @@ class MediaWiki { } private function main() { - global $wgTitle, $wgTrxProfilerLimits; + global $wgTitle; $request = $this->context->getRequest(); @@ -615,13 +653,14 @@ class MediaWiki { $action = $this->getAction(); $wgTitle = $title; + // Set DB query expectations for this HTTP request + $trxLimits = $this->config->get( 'TrxProfilerLimits' ); $trxProfiler = Profiler::instance()->getTransactionProfiler(); $trxProfiler->setLogger( LoggerFactory::getInstance( 'DBPerformance' ) ); - if ( $request->wasPosted() ) { - $trxProfiler->setExpectations( $wgTrxProfilerLimits['POST'], __METHOD__ ); + $trxProfiler->setExpectations( $trxLimits['POST'], __METHOD__ ); } else { - $trxProfiler->setExpectations( $wgTrxProfilerLimits['GET'], __METHOD__ ); + $trxProfiler->setExpectations( $trxLimits['GET'], __METHOD__ ); } // If the user has forceHTTPS set to true, or if the user @@ -632,8 +671,10 @@ class MediaWiki { if ( $request->getProtocol() == 'http' && ( + $request->getSession()->shouldForceHTTPS() || + // Check the cookie manually, for paranoia $request->getCookie( 'forceHTTPS', '' ) || - // check for prefixed version for currently logged in users + // check for prefixed version that was used for a time in older MW versions $request->getCookie( 'forceHTTPS' ) || // Avoid checking the user and groups unless it's enabled. ( @@ -709,7 +750,7 @@ class MediaWiki { */ public function restInPeace( $mode = 'fast' ) { // Assure deferred updates are not in the main transaction - wfGetLBFactory()->commitMasterChanges(); + wfGetLBFactory()->commitMasterChanges( __METHOD__ ); // Ignore things like master queries/connections on GET requests // as long as they are in deferred updates (which catch errors). @@ -732,7 +773,7 @@ class MediaWiki { // Commit and close up! $factory = wfGetLBFactory(); - $factory->commitMasterChanges(); + $factory->commitMasterChanges( __METHOD__ ); $factory->shutdown( LBFactory::SHUTDOWN_NO_CHRONPROT ); wfDebug( "Request ended normally\n" );