SessionManager: Use existing backend for the ID if one is loaded
[lhc/web/wiklou.git] / includes / session / SessionManager.php
index b1d5d77..da7bc57 100644 (file)
@@ -197,12 +197,17 @@ final class SessionManager implements SessionManagerInterface {
                }
 
                $session = null;
+               $info = new SessionInfo( SessionInfo::MIN_PRIORITY, [ 'id' => $id, 'idIsSafe' => true ] );
 
-               // Test this here to provide a better log message for the common case
-               // of "no such ID"
+               // If we already have the backend loaded, use it directly
+               if ( isset( $this->allSessionBackends[$id] ) ) {
+                       return $this->getSessionFromInfo( $info, $request );
+               }
+
+               // Test if the session is in storage, and if so try to load it.
                $key = wfMemcKey( 'MWSession', $id );
                if ( is_array( $this->store->get( $key ) ) ) {
-                       $info = new SessionInfo( SessionInfo::MIN_PRIORITY, [ 'id' => $id, 'idIsSafe' => true ] );
+                       $create = false; // If loading fails, don't bother creating because it probably will fail too.
                        if ( $this->loadSessionInfoFromStore( $info, $request ) ) {
                                $session = $this->getSessionFromInfo( $info, $request );
                        }
@@ -286,7 +291,7 @@ final class SessionManager implements SessionManagerInterface {
                // Make sure there's exactly one
                if ( count( $infos ) > 1 ) {
                        throw new \UnexpectedValueException(
-                               'Multiple empty sessions tied for top priority: ' . join( ', ', $infos )
+                               'Multiple empty sessions tied for top priority: ' . implode( ', ', $infos )
                        );
                } elseif ( count( $infos ) < 1 ) {
                        throw new \UnexpectedValueException( 'No provider could provide an empty session!' );
@@ -296,9 +301,11 @@ final class SessionManager implements SessionManagerInterface {
        }
 
        public function getVaryHeaders() {
+               // @codeCoverageIgnoreStart
                if ( defined( 'MW_NO_SESSION' ) && MW_NO_SESSION !== 'warn' ) {
                        return [];
                }
+               // @codeCoverageIgnoreEnd
                if ( $this->varyHeaders === null ) {
                        $headers = [];
                        foreach ( $this->getProviders() as $provider ) {
@@ -317,9 +324,11 @@ final class SessionManager implements SessionManagerInterface {
        }
 
        public function getVaryCookies() {
+               // @codeCoverageIgnoreStart
                if ( defined( 'MW_NO_SESSION' ) && MW_NO_SESSION !== 'warn' ) {
                        return [];
                }
+               // @codeCoverageIgnoreEnd
                if ( $this->varyCookies === null ) {
                        $cookies = [];
                        foreach ( $this->getProviders() as $provider ) {
@@ -513,12 +522,14 @@ final class SessionManager implements SessionManagerInterface {
                }
 
                # Notify AuthPlugin
+               // @codeCoverageIgnoreStart
                $tmpUser = $user;
                $wgAuth->initUser( $tmpUser, true );
                if ( $tmpUser !== $user ) {
                        $logger->warning( __METHOD__ . ': ' .
                                get_class( $wgAuth ) . '::initUser() replaced the user object' );
                }
+               // @codeCoverageIgnoreEnd
 
                # Notify hooks (e.g. Newuserlog)
                \Hooks::run( 'AuthPluginAutoCreate', [ $user ] );
@@ -530,7 +541,7 @@ final class SessionManager implements SessionManagerInterface {
                \DeferredUpdates::addUpdate( new \SiteStatsUpdate( 0, 0, 0, 0, 1 ) );
 
                # Watch user's userpage and talk page
-               $user->addWatch( $user->getUserPage(), \WatchedItem::IGNORE_USER_RIGHTS );
+               $user->addWatch( $user->getUserPage(), User::IGNORE_USER_RIGHTS );
 
                return true;
        }
@@ -657,14 +668,20 @@ final class SessionManager implements SessionManagerInterface {
                                                // This is going to error out below, but we want to
                                                // provide a complete list.
                                                $retInfos[] = $info;
+                                       } else {
+                                               // Session load failed, so unpersist it from this request
+                                               $info->getProvider()->unpersistSession( $request );
                                        }
                                }
+                       } else {
+                               // Session load failed, so unpersist it from this request
+                               $info->getProvider()->unpersistSession( $request );
                        }
                }
 
                if ( count( $retInfos ) > 1 ) {
                        $ex = new \OverflowException(
-                               'Multiple sessions for this request tied for top priority: ' . join( ', ', $retInfos )
+                               'Multiple sessions for this request tied for top priority: ' . implode( ', ', $retInfos )
                        );
                        $ex->sessionInfos = $retInfos;
                        throw $ex;
@@ -957,14 +974,18 @@ final class SessionManager implements SessionManagerInterface {
         * @return Session
         */
        public function getSessionFromInfo( SessionInfo $info, WebRequest $request ) {
+               // @codeCoverageIgnoreStart
                if ( defined( 'MW_NO_SESSION' ) ) {
                        if ( MW_NO_SESSION === 'warn' ) {
                                // Undocumented safety case for converting existing entry points
-                               $this->logger->error( 'Sessions are supposed to be disabled for this entry point' );
+                               $this->logger->error( 'Sessions are supposed to be disabled for this entry point', [
+                                       'exception' => new \BadMethodCallException( 'Sessions are disabled for this entry point' ),
+                               ] );
                        } else {
                                throw new \BadMethodCallException( 'Sessions are disabled for this entry point' );
                        }
                }
+               // @codeCoverageIgnoreEnd
 
                $id = $info->getId();