$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() ?: [];
+ $query = $specialPage->getRedirectQuery( $subpage ) ?: [];
$request = new DerivativeRequest( $this->context->getRequest(), $query );
$request->setRequestURL( $this->context->getRequest()->getRequestURL() );
$this->context->setRequest( $request );
if ( $request->getVal( 'action', 'view' ) != 'view'
|| $request->wasPosted()
- || ( $request->getVal( 'title' ) !== null
+ || ( $request->getCheck( 'title' )
&& $title->getPrefixedDBkey() == $request->getVal( 'title' ) )
|| count( $request->getValueNames( [ 'action', 'title' ] ) )
|| !Hooks::run( 'TestCanonicalRedirect', [ $request, $title, $output ] )
if ( !$ignoreRedirect && ( $target || $page->isRedirect() ) ) {
// Is the target already set by an extension?
$target = $target ?: $page->followRedirect();
- if ( is_string( $target ) ) {
- if ( !$this->config->get( 'DisableHardRedirects' ) ) {
- // we'll need to redirect
- return $target;
- }
+ if ( is_string( $target ) && !$this->config->get( 'DisableHardRedirects' ) ) {
+ // we'll need to redirect
+ return $target;
}
if ( is_object( $target ) ) {
// Rewrite environment to redirected article
}
/**
- * This function commits all DB changes as needed before
- * the user can receive a response (in case commit fails)
+ * This function commits all DB and session changes as needed *before* the
+ * client can receive a response (in case DB commit fails) and thus also before
+ * the response can trigger a subsequent related request by the client
+ *
+ * If there is a significant amount of content to flush, it can be done in $postCommitWork
*
* @param IContextSource $context
* @param callable|null $postCommitWork [default: null]
// Run updates that need to block the user or affect output (this is the last chance)
DeferredUpdates::doUpdates( 'enqueue', DeferredUpdates::PRESEND );
wfDebug( __METHOD__ . ': pre-send deferred updates completed' );
+ // T214471: persist the session to avoid race conditions on subsequent requests
+ $request->getSession()->save();
// Should the client return, their request should observe the new ChronologyProtector
// DB positions. This request might be on a foreign wiki domain, so synchronously update
) {
if ( $config->get( 'StatsdServer' ) && $stats->hasData() ) {
try {
- $statsdServer = explode( ':', $config->get( 'StatsdServer' ) );
+ $statsdServer = explode( ':', $config->get( 'StatsdServer' ), 2 );
$statsdHost = $statsdServer[0];
$statsdPort = $statsdServer[1] ?? 8125;
$statsdSender = new SocketSender( $statsdHost, $statsdPort );