summaryrefslogtreecommitdiff
path: root/includes/context
diff options
context:
space:
mode:
Diffstat (limited to 'includes/context')
-rw-r--r--includes/context/ContextSource.php17
-rw-r--r--includes/context/DerivativeContext.php18
-rw-r--r--includes/context/IContextSource.php38
-rw-r--r--includes/context/RequestContext.php88
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
+ }
+ );
}
/**