X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FMediaWiki.php;h=d0e81cffc6d8526e18c582b1a17889cfb1f3d551;hb=f6e5079a6964b10deff40c3224957cab2474dde7;hp=c086a39d1ed8160dac097061129b47b2cf09ffcb;hpb=ac31d0e2ec48971568b65c19f03ceae2e5eb9008;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/MediaWiki.php b/includes/MediaWiki.php index c086a39d1e..7a0d7b7ce3 100644 --- a/includes/MediaWiki.php +++ b/includes/MediaWiki.php @@ -20,6 +20,8 @@ * @file */ +use MediaWiki\Logger\LoggerFactory; + /** * The MediaWiki class is the helper class for the index.php entry point. */ @@ -49,6 +51,7 @@ class MediaWiki { /** * Parse the request to get the Title object * + * @throws MalformedTitleException If a title has been provided by the user, but is invalid. * @return Title Title object to be $wgTitle */ private function parseTitle() { @@ -108,7 +111,10 @@ class MediaWiki { } if ( $ret === null || ( $ret->getDBkey() == '' && !$ret->isExternal() ) ) { - $ret = SpecialPage::getTitleFor( 'Badtitle' ); + // If we get here, we definitely don't have a valid title; throw an exception. + // Try to get detailed invalid title exception first, fall back to MalformedTitleException. + Title::newFromTextThrow( $title ); + throw new MalformedTitleException( 'badtitletext', $title ); } return $ret; @@ -120,7 +126,11 @@ class MediaWiki { */ public function getTitle() { if ( !$this->context->hasTitle() ) { - $this->context->setTitle( $this->parseTitle() ); + try { + $this->context->setTitle( $this->parseTitle() ); + } catch ( MalformedTitleException $ex ) { + $this->context->setTitle( SpecialPage::getTitleFor( 'Badtitle' ) ); + } } return $this->context->getTitle(); } @@ -172,6 +182,11 @@ class MediaWiki { || $title->isSpecial( 'Badtitle' ) ) { $this->context->setTitle( SpecialPage::getTitleFor( 'Badtitle' ) ); + try { + $this->parseTitle(); + } catch ( MalformedTitleException $ex ) { + throw new BadTitleError( $ex ); + } throw new BadTitleError(); } @@ -217,6 +232,11 @@ class MediaWiki { $output->redirect( $url, 301 ); } else { $this->context->setTitle( SpecialPage::getTitleFor( 'Badtitle' ) ); + try { + $this->parseTitle(); + } catch ( MalformedTitleException $ex ) { + throw new BadTitleError( $ex ); + } throw new BadTitleError(); } // Redirect loops, no title in URL, $wgUsePathInfo URLs, and URLs with a variant @@ -402,8 +422,7 @@ class MediaWiki { } /** - * Run the current MediaWiki instance - * index.php just calls this + * Run the current MediaWiki instance; index.php just calls this */ public function run() { try { @@ -414,16 +433,68 @@ class MediaWiki { // Bug 62091: while exceptions are convenient to bubble up GUI errors, // they are not internal application faults. As with normal requests, this // should commit, print the output, do deferred updates, jobs, and profiling. - wfGetLBFactory()->commitMasterChanges(); + $this->doPreOutputCommit(); $e->report(); // display the GUI error } + } catch ( Exception $e ) { + MWExceptionHandler::handleException( $e ); + } + + $this->doPostOutputShutdown( 'normal' ); + } + + /** + * This function commits all DB changes as needed before + * the user can receive a response (in case commit fails) + * + * @since 1.26 + */ + public function doPreOutputCommit() { + // Either all DBs should commit or none + ignore_user_abort( true ); + wfGetLBFactory()->commitMasterChanges(); + } + + /** + * This function does work that can be done *after* the + * user gets the HTTP response so they don't block on it + * + * @param string $mode Use 'fast' to always skip job running + * @since 1.26 + */ + public function doPostOutputShutdown( $mode = 'normal' ) { + // Show profiling data if enabled + Profiler::instance()->logDataPageOutputOnly(); + + $that = $this; + $callback = function () use ( $that, $mode ) { + try { + // Assure deferred updates are not in the main transaction + wfGetLBFactory()->commitMasterChanges(); + // Run jobs occasionally, if enabled + if ( $mode === 'normal' ) { + $that->triggerJobs(); + } + // Do deferred updates and job insertion and final commit + $that->restInPeace(); + } catch ( Exception $e ) { + MWExceptionHandler::handleException( $e ); + } + }; + + if ( function_exists( 'register_postsend_function' ) ) { + // https://github.com/facebook/hhvm/issues/1230 + register_postsend_function( $callback ); + } else { if ( function_exists( 'fastcgi_finish_request' ) ) { fastcgi_finish_request(); + } else { + // Either all DB and deferred updates should happen or none. + // The later should not be cancelled due to client disconnect. + ignore_user_abort( true ); } - $this->triggerJobs(); - $this->restInPeace(); - } catch ( Exception $e ) { - MWExceptionHandler::handleException( $e ); + + $callback(); } } @@ -438,7 +509,7 @@ class MediaWiki { list( $host, $lag ) = wfGetLB()->getMaxLag(); if ( $lag > $maxLag ) { $resp = $this->context->getRequest()->response(); - $resp->header( 'HTTP/1.1 503 Service Unavailable' ); + $resp->statusHeader( 503 ); $resp->header( 'Retry-After: ' . max( intval( $maxLag ), 5 ) ); $resp->header( 'X-Database-Lag: ' . intval( $lag ) ); $resp->header( 'Content-Type: text/plain' ); @@ -455,14 +526,16 @@ class MediaWiki { } private function main() { - global $wgTitle; + global $wgTitle, $wgTrxProfilerLimits; $request = $this->context->getRequest(); // Send Ajax requests to the Ajax dispatcher. if ( $this->config->get( 'UseAjax' ) && $request->getVal( 'action' ) === 'ajax' ) { // Set a dummy title, because $wgTitle == null might break things - $title = Title::makeTitle( NS_MAIN, 'AJAX' ); + $title = Title::makeTitle( NS_SPECIAL, 'Badtitle/performing an AJAX call in ' + . __METHOD__ + ); $this->context->setTitle( $title ); $wgTitle = $title; @@ -478,16 +551,16 @@ class MediaWiki { $wgTitle = $title; $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->setExpectation( 'masterConns', 0, __METHOD__ ); - $trxProfiler->setExpectation( 'writes', 0, __METHOD__ ); + $trxProfiler->setExpectations( $wgTrxProfilerLimits['GET'], __METHOD__ ); } else { - $trxProfiler->setExpectation( 'maxAffected', 500, __METHOD__ ); + $trxProfiler->setExpectations( $wgTrxProfilerLimits['POST'], __METHOD__ ); } // If the user has forceHTTPS set to true, or if the user @@ -526,7 +599,7 @@ class MediaWiki { wfDebugLog( 'RedirectedPosts', "Redirected from HTTP to HTTPS: $oldUrl" ); } // Setup dummy Title, otherwise OutputPage::redirect will fail - $title = Title::newFromText( NS_MAIN, 'REDIR' ); + $title = Title::newFromText( 'REDIR', NS_MAIN ); $this->context->setTitle( $title ); $output = $this->context->getOutput(); // Since we only do this redir to change proto, always send a vary header @@ -560,16 +633,13 @@ class MediaWiki { // Actually do the work of the request and build up any output $this->performRequest(); - // Either all DB and deferred updates should happen or none. - // The later should not be cancelled due to client disconnect. - ignore_user_abort( true ); // Now commit any transactions, so that unreported errors after - // output() don't roll back the whole DB transaction - wfGetLBFactory()->commitMasterChanges(); + // output() don't roll back the whole DB transaction and so that + // we avoid having both success and error text in the response + $this->doPreOutputCommit(); // Output everything! $this->context->getOutput()->output(); - } /** @@ -583,6 +653,9 @@ class MediaWiki { // Do any deferred jobs DeferredUpdates::doUpdates( 'commit' ); + // Make sure any lazy jobs are pushed + JobQueueGroup::pushLazyJobs(); + // Log profiling data, e.g. in the database or UDP wfLogProfilingData(); @@ -599,7 +672,7 @@ class MediaWiki { * to run a specified number of jobs. This registers a callback to cleanup * the socket once it's done. */ - protected function triggerJobs() { + public function triggerJobs() { $jobRunRate = $this->config->get( 'JobRunRate' ); if ( $jobRunRate <= 0 || wfReadOnly() ) { return; @@ -617,7 +690,7 @@ class MediaWiki { $n = intval( $jobRunRate ); } - $runJobsLogger = MWLoggerFactory::getInstance( 'runJobs' ); + $runJobsLogger = LoggerFactory::getInstance( 'runJobs' ); if ( !$this->config->get( 'RunJobsAsync' ) ) { // Fall back to running the job here while the user waits @@ -642,7 +715,7 @@ class MediaWiki { $errno = $errstr = null; $info = wfParseUrl( $this->config->get( 'Server' ) ); - wfSuppressWarnings(); + MediaWiki\suppressWarnings(); $sock = fsockopen( $info['host'], isset( $info['port'] ) ? $info['port'] : 80, @@ -652,7 +725,7 @@ class MediaWiki { // is a problem elsewhere. 0.1 ); - wfRestoreWarnings(); + MediaWiki\restoreWarnings(); if ( !$sock ) { $runJobsLogger->error( "Failed to start cron API (socket error $errno): $errstr" ); // Fall back to running the job here while the user waits @@ -662,7 +735,12 @@ class MediaWiki { } $url = wfAppendQuery( wfScript( 'index' ), $query ); - $req = "POST $url HTTP/1.1\r\nHost: {$info['host']}\r\nConnection: Close\r\nContent-Length: 0\r\n\r\n"; + $req = ( + "POST $url HTTP/1.1\r\n" . + "Host: {$info['host']}\r\n" . + "Connection: Close\r\n" . + "Content-Length: 0\r\n\r\n" + ); $runJobsLogger->info( "Running $n job(s) via '$url'" ); // Send a cron API request to be performed in the background.