*/
private $config;
+ /**
+ * @var String Cache what action this request is
+ */
+ private $action;
+
/**
* @param IContextSource|null $context
*/
* @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;
}
/**
// 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 );
$targetUrl = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
if ( $targetUrl != $request->getFullRequestURL() ) {
- $output->setSquidMaxage( 1200 );
+ $output->setCdnMaxage( 1200 );
$output->redirect( $targetUrl, '301' );
return true;
}
$action = Action::factory( $act, $page, $this->context );
if ( $action instanceof Action ) {
- # Let Squid cache things if we can purge them.
+ # Let CDN cache things if we can purge them.
if ( $this->config->get( 'UseSquid' ) &&
in_array(
- // Use PROTO_INTERNAL because that's what getSquidURLs() uses
+ // Use PROTO_INTERNAL because that's what getCdnUrls() uses
wfExpandUrl( $request->getRequestURL(), PROTO_INTERNAL ),
- $requestTitle->getSquidURLs()
+ $requestTitle->getCdnUrls()
)
) {
- $output->setSquidMaxage( $this->config->get( 'SquidMaxage' ) );
+ $output->setCdnMaxage( $this->config->get( 'SquidMaxage' ) );
}
$action->show();
// Either all DBs should commit or none
ignore_user_abort( true );
- // Commit all changes and record ChronologyProtector positions
+ $config = $context->getConfig();
+
$factory = wfGetLBFactory();
- $factory->commitMasterChanges();
+ // 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 )->text()
+ );
+ }
+ } );
+ } );
+ // Commit all changes
+ $factory->commitMasterChanges( __METHOD__ );
+ // Record ChronologyProtector positions
$factory->shutdown();
wfDebug( __METHOD__ . ': all transactions committed' );
// 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)
$request = $context->getRequest();
- $config = $context->getConfig();
if ( $request->wasPosted() && $factory->hasOrMadeRecentMasterChanges() ) {
$expires = time() + $config->get( 'DataCenterUpdateStickTTL' );
$request->response()->setCookie( 'UseDC', 'master', $expires, array( 'prefix' => '' ) );
$trxProfiler = Profiler::instance()->getTransactionProfiler();
$trxProfiler->setLogger( LoggerFactory::getInstance( 'DBPerformance' ) );
- // Aside from rollback, master queries should not happen on GET requests.
- // Periodic or "in passing" updates on GET should use the job queue.
- if ( !$request->wasPosted()
- && in_array( $action, array( 'view', 'edit', 'history' ) )
- ) {
- $trxProfiler->setExpectations( $wgTrxProfilerLimits['GET'], __METHOD__ );
- } else {
+ if ( $request->wasPosted() ) {
$trxProfiler->setExpectations( $wgTrxProfilerLimits['POST'], __METHOD__ );
+ } else {
+ $trxProfiler->setExpectations( $wgTrxProfilerLimits['GET'], __METHOD__ );
}
// If the user has forceHTTPS set to true, or if the user
*/
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).
// Commit and close up!
$factory = wfGetLBFactory();
- $factory->commitMasterChanges();
+ $factory->commitMasterChanges( __METHOD__ );
$factory->shutdown( LBFactory::SHUTDOWN_NO_CHRONPROT );
wfDebug( "Request ended normally\n" );