diff options
Diffstat (limited to 'includes/context')
-rw-r--r-- | includes/context/ContextSource.php | 17 | ||||
-rw-r--r-- | includes/context/DerivativeContext.php | 18 | ||||
-rw-r--r-- | includes/context/IContextSource.php | 38 | ||||
-rw-r--r-- | includes/context/RequestContext.php | 88 |
4 files changed, 126 insertions, 35 deletions
diff --git a/includes/context/ContextSource.php b/includes/context/ContextSource.php index 076504ec..d526d84b 100644 --- a/includes/context/ContextSource.php +++ b/includes/context/ContextSource.php @@ -1,7 +1,5 @@ <?php /** - * Request-dependant objects containers. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,8 +15,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @since 1.18 - * * @author Happy-melon * @file */ @@ -26,6 +22,8 @@ /** * The simplest way of implementing IContextSource is to hold a RequestContext as a * member variable and provide accessors to it. + * + * @since 1.18 */ abstract class ContextSource implements IContextSource { /** @@ -155,6 +153,17 @@ abstract class ContextSource implements IContextSource { } /** + * Get the Stats object + * + * @since 1.25 + * @return BufferingStatsdDataFactory + */ + public function getStats() { + return $this->getContext()->getStats(); + } + + + /** * Get a Message object with context set * Parameters are the same as wfMessage() * diff --git a/includes/context/DerivativeContext.php b/includes/context/DerivativeContext.php index b8966f0c..00323cae 100644 --- a/includes/context/DerivativeContext.php +++ b/includes/context/DerivativeContext.php @@ -1,7 +1,5 @@ <?php /** - * Request-dependant objects containers. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,8 +15,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @since 1.19 - * * @author Daniel Friesen * @file */ @@ -28,6 +24,7 @@ * but allow individual pieces of context to be changed locally * eg: A ContextSource that can inherit from the main RequestContext but have * a different Title instance set on it. + * @since 1.19 */ class DerivativeContext extends ContextSource { /** @@ -101,6 +98,19 @@ class DerivativeContext extends ContextSource { } /** + * Get the stats object + * + * @return BufferingStatsdDataFactory + */ + public function getStats() { + if ( !is_null( $this->stats ) ) { + return $this->stats; + } else { + return $this->getContext()->getStats(); + } + } + + /** * Set the WebRequest object * * @param WebRequest $r diff --git a/includes/context/IContextSource.php b/includes/context/IContextSource.php index f718103d..713c5cbf 100644 --- a/includes/context/IContextSource.php +++ b/includes/context/IContextSource.php @@ -1,7 +1,5 @@ <?php /** - * Request-dependant objects containers. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -24,7 +22,33 @@ */ /** - * Interface for objects which can provide a context on request. + * Interface for objects which can provide a MediaWiki context on request + * + * Context objects contain request-dependent objects that manage the core + * web request/response logic for essentially all requests to MediaWiki. + * The contained objects include: + * a) Key objects that depend (for construction/loading) on the HTTP request + * b) Key objects used for response building and PHP session state control + * c) Performance metric deltas accumulated from request execution + * d) The site configuration object + * All of the objects are useful for the vast majority of MediaWiki requests. + * The site configuration object is included on grounds of extreme + * utility, even though it should not actually depend on the web request. + * + * More specifically, the scope of the context includes: + * a) Objects that represent the HTTP request/response and PHP session state + * b) Object representing the MediaWiki user (as determined by the HTTP request) + * c) Primary MediaWiki output builder objects (OutputPage, user skin object) + * d) The language object for the user/request + * e) The title and wiki page objects requested via URL (if any) + * f) Performance metric deltas accumulated from request execution + * g) The site configuration object + * + * This class is not intended as a service-locator nor a service singleton. + * Objects that only depend on site configuration do not belong here (aside + * from Config itself). Objects that represent persistent data stores do not + * belong here either. Session state changes should only be propagated on + * shutdown by separate persistence handler objects, for example. */ interface IContextSource { /** @@ -100,6 +124,14 @@ interface IContextSource { public function getConfig(); /** + * Get the stats object + * + * @since 1.25 + * @return BufferingStatsdDataFactory + */ + public function getStats(); + + /** * Get a Message object with context set * * @return Message diff --git a/includes/context/RequestContext.php b/includes/context/RequestContext.php index ede10fe9..4e790c04 100644 --- a/includes/context/RequestContext.php +++ b/includes/context/RequestContext.php @@ -1,7 +1,5 @@ <?php /** - * Request-dependant objects containers. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -64,6 +62,11 @@ class RequestContext implements IContextSource { private $skin; /** + * @var StatsdDataFactory + */ + private $stats; + + /** * @var Config */ private $config; @@ -121,6 +124,22 @@ class RequestContext implements IContextSource { } /** + * Get the Stats object + * + * @return BufferingStatsdDataFactory + */ + public function getStats() { + if ( $this->stats === null ) { + $config = $this->getConfig(); + $prefix = $config->has( 'StatsdMetricPrefix' ) + ? rtrim( $config->get( 'StatsdMetricPrefix' ), '.' ) + : 'MediaWiki'; + $this->stats = new BufferingStatsdDataFactory( $prefix ); + } + return $this->stats; + } + + /** * Set the Title object * * @param Title $title @@ -140,12 +159,23 @@ class RequestContext implements IContextSource { if ( $this->title === null ) { global $wgTitle; # fallback to $wg till we can improve this $this->title = $wgTitle; + wfDebugLog( 'GlobalTitleFail', __METHOD__ . ' called by ' . wfGetAllCallers( 5 ) . ' with no title set.' ); } return $this->title; } /** + * Check, if a Title object is set + * + * @since 1.25 + * @return bool + */ + public function hasTitle() { + return $this->title !== null; + } + + /** * Check whether a WikiPage object can be get with getWikiPage(). * Callers should expect that an exception is thrown from getWikiPage() * if this method returns false. @@ -171,9 +201,8 @@ class RequestContext implements IContextSource { * @param WikiPage $p */ public function setWikiPage( WikiPage $p ) { - $contextTitle = $this->getTitle(); $pageTitle = $p->getTitle(); - if ( !$contextTitle || !$pageTitle->equals( $contextTitle ) ) { + if ( !$this->hasTitle() || !$pageTitle->equals( $this->getTitle() ) ) { $this->setTitle( $pageTitle ); } // Defer this to the end since setTitle sets it to null. @@ -287,8 +316,8 @@ class RequestContext implements IContextSource { /** * Get the Language object. * Initialization of user or request objects can depend on this. - * * @return Language + * @throws Exception * @since 1.19 */ public function getLanguage() { @@ -308,10 +337,13 @@ class RequestContext implements IContextSource { $request = $this->getRequest(); $user = $this->getUser(); - $code = $request->getVal( 'uselang', $user->getOption( 'language' ) ); + $code = $request->getVal( 'uselang', 'user' ); + if ( $code === 'user' ) { + $code = $user->getOption( 'language' ); + } $code = self::sanitizeLangCode( $code ); - wfRunHooks( 'UserGetLanguageObject', array( $user, &$code, $this ) ); + Hooks::run( 'UserGetLanguageObject', array( $user, &$code, $this ) ); if ( $code === $this->getConfig()->get( 'LanguageCode' ) ) { $this->lang = $wgContLang; @@ -348,10 +380,9 @@ class RequestContext implements IContextSource { */ public function getSkin() { if ( $this->skin === null ) { - wfProfileIn( __METHOD__ . '-createskin' ); $skin = null; - wfRunHooks( 'RequestContextCreateSkin', array( $this, &$skin ) ); + Hooks::run( 'RequestContextCreateSkin', array( $this, &$skin ) ); $factory = SkinFactory::getDefaultInstance(); // If the hook worked try to set a skin from it @@ -386,7 +417,6 @@ class RequestContext implements IContextSource { // After all that set a context on whatever skin got created $this->skin->setContext( $this ); - wfProfileOut( __METHOD__ . '-createskin' ); } return $this->skin; @@ -463,10 +493,14 @@ class RequestContext implements IContextSource { } /** - * Import the resolved user IP, HTTP headers, user ID, and session ID. + * Import an client IP address, HTTP headers, user ID, and session ID + * * This sets the current session and sets $wgUser and $wgRequest. * Once the return value falls out of scope, the old context is restored. - * This function can only be called within CLI mode scripts. + * This method should only be called in contexts (CLI or HTTP job runners) + * where there is no session ID or end user receiving the response. This + * is partly enforced, and is done so to avoid leaking cookies if certain + * error conditions arise. * * This will setup the session from the given ID. This is useful when * background scripts inherit context when acting on behalf of a user. @@ -479,11 +513,12 @@ class RequestContext implements IContextSource { * @since 1.21 */ public static function importScopedSession( array $params ) { - if ( PHP_SAPI !== 'cli' ) { - // Don't send random private cookies or turn $wgRequest into FauxRequest - throw new MWException( "Sessions can only be imported in cli mode." ); - } elseif ( !strlen( $params['sessionId'] ) ) { - throw new MWException( "No session ID was specified." ); + if ( session_id() != '' && strlen( $params['sessionId'] ) ) { + // Sanity check to avoid sending random cookies for the wrong users. + // This method should only called by CLI scripts or by HTTP job runners. + throw new MWException( "Sessions can only be imported when none is active." ); + } elseif ( !IP::isValid( $params['ip'] ) ) { + throw new MWException( "Invalid client IP address '{$params['ip']}'." ); } if ( $params['userId'] ) { // logged-in user @@ -492,13 +527,11 @@ class RequestContext implements IContextSource { if ( !$user->getId() ) { throw new MWException( "No user with ID '{$params['userId']}'." ); } - } elseif ( !IP::isValid( $params['ip'] ) ) { - throw new MWException( "Could not load user '{$params['ip']}'." ); } else { // anon user $user = User::newFromName( $params['ip'], false ); } - $importSessionFunction = function ( User $user, array $params ) { + $importSessionFunc = function ( User $user, array $params ) { global $wgRequest, $wgUser; $context = RequestContext::getMain(); @@ -531,12 +564,19 @@ class RequestContext implements IContextSource { // Stash the old session and load in the new one $oUser = self::getMain()->getUser(); $oParams = self::getMain()->exportSession(); - $importSessionFunction( $user, $params ); + $oRequest = self::getMain()->getRequest(); + $importSessionFunc( $user, $params ); // Set callback to save and close the new session and reload the old one - return new ScopedCallback( function () use ( $importSessionFunction, $oUser, $oParams ) { - $importSessionFunction( $oUser, $oParams ); - } ); + return new ScopedCallback( + function () use ( $importSessionFunc, $oUser, $oParams, $oRequest ) { + global $wgRequest; + $importSessionFunc( $oUser, $oParams ); + // Restore the exact previous Request object (instead of leaving FauxRequest) + RequestContext::getMain()->setRequest( $oRequest ); + $wgRequest = RequestContext::getMain()->getRequest(); // b/c + } + ); } /** |