* - Normalise empty title:
* /wiki/ -> /wiki/Main
* /w/index.php?title= -> /wiki/Main
+ * - Normalise non-standard title urls:
+ * /w/index.php?title=Foo_Bar -> /wiki/Foo_Bar
* - Don't redirect anything with query parameters other than 'title' or 'action=view'.
*
+ * @param Title $title
* @return bool True if a redirect was set.
+ * @throws HttpError
*/
- private function tryNormaliseRedirect( $title ) {
+ private function tryNormaliseRedirect( Title $title ) {
$request = $this->context->getRequest();
$output = $this->context->getOutput();
if ( $request->getVal( 'action', 'view' ) != 'view'
|| $request->wasPosted()
- || ( $request->getVal( 'title' ) !== null
- && $title->getPrefixedDBkey() == $request->getVal( 'title' ) )
|| count( $request->getValueNames( array( 'action', 'title' ) ) )
|| !Hooks::run( 'TestCanonicalRedirect', array( $request, $title, $output ) )
) {
}
// Redirect to canonical url, make it a 301 to allow caching
$targetUrl = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
- if ( $targetUrl == $request->getFullRequestURL() ) {
+
+ if ( $targetUrl != $request->getFullRequestURL() ) {
+ $output->setSquidMaxage( 1200 );
+ $output->redirect( $targetUrl, '301' );
+ return true;
+ }
+
+ // If there is no title, or the title is in a non-standard encoding, we demand
+ // a redirect. If cgi somehow changed the 'title' query to be non-standard while
+ // the url is standard, the server is misconfigured.
+ if ( $request->getVal( 'title' ) === null
+ || $title->getPrefixedDBkey() != $request->getVal( 'title' )
+ ) {
$message = "Redirect loop detected!\n\n" .
"This means the wiki got confused about what page was " .
"requested; this sometimes happens when moving a wiki " .
}
throw new HttpError( 500, $message );
}
- $output->setSquidMaxage( 1200 );
- $output->redirect( $targetUrl, '301' );
- return true;
+ return false;
}
/**
$this->context->setWikiPage( $article->getPage() );
}
- // NS_MEDIAWIKI has no redirects.
- // It is also used for CSS/JS, so performance matters here...
- if ( $title->getNamespace() == NS_MEDIAWIKI ) {
+ // Skip some unnecessary code if the content model doesn't support redirects
+ if ( !ContentHandler::getForTitle( $title )->supportsRedirects() ) {
return $article;
}
public function doPreOutputCommit() {
// Either all DBs should commit or none
ignore_user_abort( true );
- wfGetLBFactory()->commitMasterChanges();
+
+ // Commit all changes and record ChronologyProtector positions
+ $factory = wfGetLBFactory();
+ $factory->commitMasterChanges();
+ $factory->shutdown();
+
+ wfDebug( __METHOD__ . ' completed; all transactions committed' );
}
/**
* This function does work that can be done *after* the
* user gets the HTTP response so they don't block on it
*
+ * This manages deferred updates, job insertion,
+ * final commit, and the logging of profiling data
+ *
* @param string $mode Use 'fast' to always skip job running
* @since 1.26
*/
public function doPostOutputShutdown( $mode = 'normal' ) {
- // Show profiling data if enabled
+ // Show visible profiling data if enabled (which cannot be post-send)
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();
+ $that->restInPeace( $mode );
} catch ( Exception $e ) {
MWExceptionHandler::handleException( $e );
}
};
+ // Defer everything else...
if ( function_exists( 'register_postsend_function' ) ) {
// https://github.com/facebook/hhvm/issues/1230
register_postsend_function( $callback );
/**
* Ends this task peacefully
+ * @param string $mode Use 'fast' to always skip job running
*/
- public function restInPeace() {
+ public function restInPeace( $mode = 'fast' ) {
+ // Assure deferred updates are not in the main transaction
+ wfGetLBFactory()->commitMasterChanges();
+
// Ignore things like master queries/connections on GET requests
// as long as they are in deferred updates (which catch errors).
Profiler::instance()->getTransactionProfiler()->resetExpectations();
// Make sure any lazy jobs are pushed
JobQueueGroup::pushLazyJobs();
+ // Now that everything specific to this request is done,
+ // try to occasionally run jobs (if enabled) from the queues
+ if ( $mode === 'normal' ) {
+ $this->triggerJobs();
+ }
+
// Log profiling data, e.g. in the database or UDP
wfLogProfilingData();