Merge "add type check and bail out when title could not be created"
[lhc/web/wiklou.git] / includes / api / ApiMain.php
index a88a0a5..7f412bc 100644 (file)
  * @defgroup API API
  */
 
-if ( !defined( 'MEDIAWIKI' ) ) {
-       // Eclipse helper - will be ignored in production
-       require_once( 'ApiBase.php' );
-}
-
 /**
  * This is the main API class, used for both external and internal processing.
  * When executed, it will create the requested formatter object,
@@ -66,6 +61,7 @@ class ApiMain extends ApiBase {
                'paraminfo' => 'ApiParamInfo',
                'rsd' => 'ApiRsd',
                'compare' => 'ApiComparePages',
+               'tokens' => 'ApiTokens',
 
                // Write modules
                'purge' => 'ApiPurge',
@@ -84,6 +80,7 @@ class ApiMain extends ApiBase {
                'patrol' => 'ApiPatrol',
                'import' => 'ApiImport',
                'userrights' => 'ApiUserrights',
+               'options' => 'ApiOptions',
        );
 
        /**
@@ -132,7 +129,7 @@ class ApiMain extends ApiBase {
        private $mPrinter;
 
        private $mModules, $mModuleNames, $mFormats, $mFormatNames;
-       private $mResult, $mAction, $mShowVersions, $mEnableWrite, $mRequest;
+       private $mResult, $mAction, $mShowVersions, $mEnableWrite;
        private $mInternalMode, $mSquidMaxage, $mModule;
 
        private $mCacheMode = 'private';
@@ -141,11 +138,25 @@ class ApiMain extends ApiBase {
        /**
         * Constructs an instance of ApiMain that utilizes the module and format specified by $request.
         *
-        * @param $request WebRequest - if this is an instance of FauxRequest, errors are thrown and no printing occurs
+        * @param $context IContextSource|WebRequest - if this is an instance of FauxRequest, errors are thrown and no printing occurs
         * @param $enableWrite bool should be set to true if the api may modify data
         */
-       public function __construct( $request, $enableWrite = false ) {
-               $this->mInternalMode = ( $request instanceof FauxRequest );
+       public function __construct( $context = null, $enableWrite = false ) {
+               if ( $context === null ) {
+                       $context = RequestContext::getMain();
+               } elseif ( $context instanceof WebRequest ) {
+                       // BC for pre-1.19
+                       $request = $context;
+                       $context = RequestContext::getMain();
+               }
+               // We set a derivative context so we can change stuff later
+               $this->setContext( new DerivativeContext( $context ) );
+
+               if ( isset( $request ) ) {
+                       $this->getContext()->setRequest( $request );
+               }
+
+               $this->mInternalMode = ( $this->getRequest() instanceof FauxRequest );
 
                // Special handling for the main module: $parent === $this
                parent::__construct( $this, $this->mInternalMode ? 'main_int' : 'main' );
@@ -156,11 +167,12 @@ class ApiMain extends ApiBase {
                        // Remove all modules other than login
                        global $wgUser;
 
-                       if ( $request->getVal( 'callback' ) !== null ) {
+                       if ( $this->getRequest()->getVal( 'callback' ) !== null ) {
                                // JSON callback allows cross-site reads.
                                // For safety, strip user credentials.
                                wfDebug( "API: stripping user credentials for JSON callback\n" );
                                $wgUser = new User();
+                               $this->getContext()->setUser( $wgUser );
                        }
                }
 
@@ -175,8 +187,6 @@ class ApiMain extends ApiBase {
                $this->mShowVersions = false;
                $this->mEnableWrite = $enableWrite;
 
-               $this->mRequest = &$request;
-
                $this->mSquidMaxage = - 1; // flag for executeActionWithErrorHandling()
                $this->mCommit = false;
        }
@@ -189,14 +199,6 @@ class ApiMain extends ApiBase {
                return $this->mInternalMode;
        }
 
-       /**
-        * Return the request object that contains client's request
-        * @return WebRequest
-        */
-       public function getRequest() {
-               return $this->mRequest;
-       }
-
        /**
         * Get the ApiResult object associated with current request
         *
@@ -286,6 +288,7 @@ class ApiMain extends ApiBase {
         * $this->setCacheMode('private')
         */
        public function setCachePrivate() {
+               wfDeprecated( __METHOD__, '1.17' );
                $this->setCacheMode( 'private' );
        }
 
@@ -314,6 +317,7 @@ class ApiMain extends ApiBase {
         * @deprecated since 1.17 Use setCacheMode( 'anon-public-user-private' )
         */
        public function setVaryCookie() {
+               wfDeprecated( __METHOD__, '1.17' );
                $this->setCacheMode( 'anon-public-user-private' );
        }
 
@@ -399,7 +403,7 @@ class ApiMain extends ApiBase {
        }
 
        protected function sendCacheHeaders() {
-               global $wgUseXVO, $wgOut, $wgVaryOnXFPForAPI;
+               global $wgUseXVO, $wgVaryOnXFP;
                $response = $this->getRequest()->response();
 
                if ( $this->mCacheMode == 'private' ) {
@@ -408,14 +412,15 @@ class ApiMain extends ApiBase {
                }
 
                if ( $this->mCacheMode == 'anon-public-user-private' ) {
-                       $xfp = $wgVaryOnXFPForAPI ? ', X-Forwarded-Proto' : '';
+                       $xfp = $wgVaryOnXFP ? ', X-Forwarded-Proto' : '';
                        $response->header( 'Vary: Accept-Encoding, Cookie' . $xfp );
                        if ( $wgUseXVO ) {
-                               if ( $wgVaryOnXFPForAPI ) {
-                                       $wgOut->addVaryHeader( 'X-Forwarded-Proto' );
+                               $out = $this->getOutput();
+                               if ( $wgVaryOnXFP ) {
+                                       $out->addVaryHeader( 'X-Forwarded-Proto' );
                                }
-                               $response->header( $wgOut->getXVO() );
-                               if ( $wgOut->haveCacheVaryCookies() ) {
+                               $response->header( $out->getXVO() );
+                               if ( $out->haveCacheVaryCookies() ) {
                                        // Logged in, mark this request private
                                        $response->header( 'Cache-Control: private' );
                                        return;
@@ -430,7 +435,7 @@ class ApiMain extends ApiBase {
                }
 
                // Send public headers
-               if ( $wgVaryOnXFPForAPI ) {
+               if ( $wgVaryOnXFP ) {
                        $response->header( 'Vary: Accept-Encoding, X-Forwarded-Proto' );
                        if ( $wgUseXVO ) {
                                // Bleeeeegh. Our header setting system sucks
@@ -486,6 +491,8 @@ class ApiMain extends ApiBase {
         * @return string
         */
        protected function substituteResultWithError( $e ) {
+               global $wgShowHostnames;
+
                $result = $this->getResult();
                // Printer may not be initialized if the extractRequestParams() fails for the main module
                if ( !isset ( $this->mPrinter ) ) {
@@ -533,8 +540,12 @@ class ApiMain extends ApiBase {
                if ( !is_null( $requestid ) ) {
                        $result->addValue( null, 'requestid', $requestid );
                }
-               // servedby is especially useful when debugging errors
-               $result->addValue( null, 'servedby', wfHostName() );
+
+               if ( $wgShowHostnames ) {
+                       // servedby is especially useful when debugging errors
+                       $result->addValue( null, 'servedby', wfHostName() );
+               }
+
                $result->addValue( null, 'error', $errMessage );
 
                return $errMessage['code'];
@@ -545,15 +556,20 @@ class ApiMain extends ApiBase {
         * @return array
         */
        protected function setupExecuteAction() {
+               global $wgShowHostnames;
+
                // First add the id to the top element
                $result = $this->getResult();
                $requestid = $this->getParameter( 'requestid' );
                if ( !is_null( $requestid ) ) {
                        $result->addValue( null, 'requestid', $requestid );
                }
-               $servedby = $this->getParameter( 'servedby' );
-               if ( $servedby ) {
-                       $result->addValue( null, 'servedby', wfHostName() );
+
+               if ( $wgShowHostnames ) {
+                       $servedby = $this->getParameter( 'servedby' );
+                       if ( $servedby ) {
+                               $result->addValue( null, 'servedby', wfHostName() );
+                       }
                }
 
                $params = $this->extractRequestParams();
@@ -580,13 +596,18 @@ class ApiMain extends ApiBase {
                $moduleParams = $module->extractRequestParams();
 
                // Die if token required, but not provided (unless there is a gettoken parameter)
+               if ( isset( $moduleParams['gettoken'] ) ) {
+                       $gettoken = $moduleParams['gettoken'];
+               } else {
+                       $gettoken = false;
+               }
+
                $salt = $module->getTokenSalt();
-               if ( $salt !== false && !isset( $moduleParams['gettoken'] ) ) {
+               if ( $salt !== false && !$gettoken ) {
                        if ( !isset( $moduleParams['token'] ) ) {
                                $this->dieUsageMsg( array( 'missingparam', 'token' ) );
                        } else {
-                               global $wgUser;
-                               if ( !$wgUser->matchEditToken( $moduleParams['token'], $salt, $this->getRequest() ) ) {
+                               if ( !$this->getUser()->matchEditToken( $moduleParams['token'], $salt ) ) {
                                        $this->dieUsageMsg( 'sessionfailure' );
                                }
                        }
@@ -628,9 +649,9 @@ class ApiMain extends ApiBase {
         * @param $module ApiBase An Api module
         */
        protected function checkExecutePermissions( $module ) {
-               global $wgUser;
+               $user = $this->getUser();
                if ( $module->isReadMode() && !in_array( 'read', User::getGroupPermissions( array( '*' ) ), true ) &&
-                       !$wgUser->isAllowed( 'read' ) )
+                       !$user->isAllowed( 'read' ) )
                {
                        $this->dieUsageMsg( 'readrequired' );
                }
@@ -638,7 +659,7 @@ class ApiMain extends ApiBase {
                        if ( !$this->mEnableWrite ) {
                                $this->dieUsageMsg( 'writedisabled' );
                        }
-                       if ( !$wgUser->isAllowed( 'writeapi' ) ) {
+                       if ( !$user->isAllowed( 'writeapi' ) ) {
                                $this->dieUsageMsg( 'writerequired' );
                        }
                        if ( wfReadOnly() ) {
@@ -654,7 +675,7 @@ class ApiMain extends ApiBase {
         */
        protected function setupExternalResponse( $module, $params ) {
                // Ignore mustBePosted() for internal calls
-               if ( $module->mustBePosted() && !$this->mRequest->wasPosted() ) {
+               if ( $module->mustBePosted() && !$this->getRequest()->wasPosted() ) {
                        $this->dieUsageMsg( array( 'mustbeposted', $this->mAction ) );
                }
 
@@ -779,7 +800,7 @@ class ApiMain extends ApiBase {
                                'wait until the replication lag is less than the specified value.',
                                'In case of a replag error, a HTTP 503 error is returned, with the message like',
                                '"Waiting for $host: $lag seconds lagged\n".',
-                               'See http://www.mediawiki.org/wiki/Manual:Maxlag_parameter for more information',
+                               'See https://www.mediawiki.org/wiki/Manual:Maxlag_parameter for more information',
                        ),
                        'smaxage' => 'Set the s-maxage header to this many seconds. Errors are never cached',
                        'maxage' => 'Set the max-age header to this many seconds. Errors are never cached',
@@ -801,8 +822,8 @@ class ApiMain extends ApiBase {
                        '**                                                                                                      **',
                        '**                      This is an auto-generated MediaWiki API documentation page                      **',
                        '**                                                                                                      **',
-                       '**                                    Documentation and Examples:                                       **',
-                       '**                                 http://www.mediawiki.org/wiki/API                                    **',
+                       '**                                     Documentation and Examples:                                      **',
+                       '**                                  https://www.mediawiki.org/wiki/API                                  **',
                        '**                                                                                                      **',
                        '**********************************************************************************************************',
                        '',
@@ -817,13 +838,13 @@ class ApiMain extends ApiBase {
                        '                       In the case of an invalid action being passed, these will have a value',
                        '                       of "unknown_action"',
                        '',
-                       '                       For more information see http://www.mediawiki.org/wiki/API:Errors_and_warnings',
+                       '                       For more information see https://www.mediawiki.org/wiki/API:Errors_and_warnings',
                        '',
-                       'Documentation:         http://www.mediawiki.org/wiki/API:Main_page',
-                       'FAQ                    http://www.mediawiki.org/wiki/API:FAQ',
-                       'Mailing list:          http://lists.wikimedia.org/mailman/listinfo/mediawiki-api',
-                       'Api Announcements:     http://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce',
-                       'Bugs & Requests:       http://bugzilla.wikimedia.org/buglist.cgi?component=API&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=bugs.delta_ts',
+                       'Documentation:         https://www.mediawiki.org/wiki/API:Main_page',
+                       'FAQ                    https://www.mediawiki.org/wiki/API:FAQ',
+                       'Mailing list:          https://lists.wikimedia.org/mailman/listinfo/mediawiki-api',
+                       'Api Announcements:     https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce',
+                       'Bugs & Requests:       https://bugzilla.wikimedia.org/buglist.cgi?component=API&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=bugs.delta_ts',
                        '',
                        '',
                        '',
@@ -859,7 +880,7 @@ class ApiMain extends ApiBase {
                        '    Yuri Astrakhan <Firstname><Lastname>@gmail.com (creator, lead developer Sep 2006-Sep 2007)',
                        '',
                        'Please send your comments, suggestions and questions to mediawiki-api@lists.wikimedia.org',
-                       'or file a bug report at http://bugzilla.wikimedia.org/'
+                       'or file a bug report at https://bugzilla.wikimedia.org/'
                );
        }
 
@@ -964,8 +985,7 @@ class ApiMain extends ApiBase {
         */
        public function canApiHighLimits() {
                if ( !isset( $this->mCanApiHighLimits ) ) {
-                       global $wgUser;
-                       $this->mCanApiHighLimits = $wgUser->isAllowed( 'apihighlimits' );
+                       $this->mCanApiHighLimits = $this->getUser()->isAllowed( 'apihighlimits' );
                }
 
                return $this->mCanApiHighLimits;
@@ -987,7 +1007,7 @@ class ApiMain extends ApiBase {
         */
        public function getVersion() {
                $vers = array();
-               $vers[] = 'MediaWiki: ' . SpecialVersion::getVersion() . "\n    http://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/";
+               $vers[] = 'MediaWiki: ' . SpecialVersion::getVersion() . "\n    https://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/";
                $vers[] = __CLASS__ . ': $Id$';
                $vers[] = ApiBase::getBaseVersion();
                $vers[] = ApiFormatBase::getBaseVersion();
@@ -1043,7 +1063,7 @@ class ApiMain extends ApiBase {
  *
  * @ingroup API
  */
-class UsageException extends Exception {
+class UsageException extends MWException {
 
        private $mCodestr;
        private $mExtraData;