Merge "jquery.textSelection: Don't throw errors on empty collections"
[lhc/web/wiklou.git] / includes / api / ApiMain.php
index 1a11b52..078e57a 100644 (file)
@@ -56,6 +56,7 @@ class ApiMain extends ApiBase {
                'parse' => 'ApiParse',
                'opensearch' => 'ApiOpenSearch',
                'feedcontributions' => 'ApiFeedContributions',
+               'feedrecentchanges' => 'ApiFeedRecentChanges',
                'feedwatchlist' => 'ApiFeedWatchlist',
                'help' => 'ApiHelp',
                'paraminfo' => 'ApiParamInfo',
@@ -67,7 +68,6 @@ class ApiMain extends ApiBase {
                'purge' => 'ApiPurge',
                'setnotificationtimestamp' => 'ApiSetNotificationTimestamp',
                'rollback' => 'ApiRollback',
-               'runjobs' => 'ApiRunJobs',
                'delete' => 'ApiDelete',
                'undelete' => 'ApiUndelete',
                'protect' => 'ApiProtect',
@@ -147,9 +147,9 @@ class ApiMain extends ApiBase {
        /**
         * Constructs an instance of ApiMain that utilizes the module and format specified by $request.
         *
-        * @param $context IContextSource|WebRequest - if this is an instance of
+        * @param IContextSource|WebRequest $context If this is an instance of
         *    FauxRequest, errors are thrown and no printing occurs
-        * @param bool $enableWrite should be set to true if the api may modify data
+        * @param bool $enableWrite Should be set to true if the api may modify data
         */
        public function __construct( $context = null, $enableWrite = false ) {
                if ( $context === null ) {
@@ -238,7 +238,7 @@ class ApiMain extends ApiBase {
        /**
         * Set how long the response should be cached.
         *
-        * @param $maxage
+        * @param int $maxage
         */
        public function setCacheMaxAge( $maxage ) {
                $this->setCacheControl( array(
@@ -301,7 +301,7 @@ class ApiMain extends ApiBase {
         * Cache control values set here will only be used if the cache mode is not
         * private, see setCacheMode().
         *
-        * @param $directives array
+        * @param array $directives
         */
        public function setCacheControl( $directives ) {
                $this->mCacheControl = $directives + $this->mCacheControl;
@@ -310,7 +310,7 @@ class ApiMain extends ApiBase {
        /**
         * Create an instance of an output formatter by its name
         *
-        * @param $format string
+        * @param string $format
         *
         * @return ApiFormatBase
         */
@@ -362,37 +362,7 @@ class ApiMain extends ApiBase {
                try {
                        $this->executeAction();
                } catch ( Exception $e ) {
-                       // Allow extra cleanup and logging
-                       wfRunHooks( 'ApiMain::onException', array( $this, $e ) );
-
-                       // Log it
-                       if ( !( $e instanceof UsageException ) ) {
-                               MWExceptionHandler::logException( $e );
-                       }
-
-                       // Handle any kind of exception by outputting properly formatted error message.
-                       // If this fails, an unhandled exception should be thrown so that global error
-                       // handler will process and log it.
-
-                       $errCode = $this->substituteResultWithError( $e );
-
-                       // Error results should not be cached
-                       $this->setCacheMode( 'private' );
-
-                       $response = $this->getRequest()->response();
-                       $headerStr = 'MediaWiki-API-Error: ' . $errCode;
-                       if ( $e->getCode() === 0 ) {
-                               $response->header( $headerStr );
-                       } else {
-                               $response->header( $headerStr, true, $e->getCode() );
-                       }
-
-                       // Reset and print just the error message
-                       ob_clean();
-
-                       // If the error occurred during printing, do a printer->profileOut()
-                       $this->mPrinter->safeProfileOut();
-                       $this->printResult( true );
+                       $this->handleException( $e );
                }
 
                // Log the request whether or not there was an error
@@ -409,6 +379,79 @@ class ApiMain extends ApiBase {
                ob_end_flush();
        }
 
+       /**
+        * Handle an exception as an API response
+        *
+        * @since 1.23
+        * @param Exception $e
+        */
+       protected function handleException( Exception $e ) {
+               // Bug 63145: Rollback any open database transactions
+               if ( !( $e instanceof UsageException ) ) {
+                       // UsageExceptions are intentional, so don't rollback if that's the case
+                       MWExceptionHandler::rollbackMasterChangesAndLog( $e );
+               }
+
+               // Allow extra cleanup and logging
+               wfRunHooks( 'ApiMain::onException', array( $this, $e ) );
+
+               // Log it
+               if ( !( $e instanceof UsageException ) ) {
+                       MWExceptionHandler::logException( $e );
+               }
+
+               // Handle any kind of exception by outputting properly formatted error message.
+               // If this fails, an unhandled exception should be thrown so that global error
+               // handler will process and log it.
+
+               $errCode = $this->substituteResultWithError( $e );
+
+               // Error results should not be cached
+               $this->setCacheMode( 'private' );
+
+               $response = $this->getRequest()->response();
+               $headerStr = 'MediaWiki-API-Error: ' . $errCode;
+               if ( $e->getCode() === 0 ) {
+                       $response->header( $headerStr );
+               } else {
+                       $response->header( $headerStr, true, $e->getCode() );
+               }
+
+               // Reset and print just the error message
+               ob_clean();
+
+               // If the error occurred during printing, do a printer->profileOut()
+               $this->mPrinter->safeProfileOut();
+               $this->printResult( true );
+       }
+
+       /**
+        * Handle an exception from the ApiBeforeMain hook.
+        *
+        * This tries to print the exception as an API response, to be more
+        * friendly to clients. If it fails, it will rethrow the exception.
+        *
+        * @since 1.23
+        * @param Exception $e
+        */
+       public static function handleApiBeforeMainException( Exception $e ) {
+               ob_start();
+
+               try {
+                       $main = new self( RequestContext::getMain(), false );
+                       $main->handleException( $e );
+               } catch ( Exception $e2 ) {
+                       // Nope, even that didn't work. Punt.
+                       throw $e;
+               }
+
+               // Log the request and reset cache headers
+               $main->logRequest( 0 );
+               $main->sendCacheHeaders();
+
+               ob_end_flush();
+       }
+
        /**
         * Check the &origin= query parameter against the Origin: HTTP header and respond appropriately.
         *
@@ -597,13 +640,14 @@ class ApiMain extends ApiBase {
        /**
         * Replace the result data with the information about an exception.
         * Returns the error code
-        * @param $e Exception
+        * @param Exception $e
         * @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 ) ) {
                        // The printer has not been created yet. Try to manually get formatter value.
@@ -613,11 +657,18 @@ class ApiMain extends ApiBase {
                        }
 
                        $this->mPrinter = $this->createPrinterByName( $value );
-                       if ( $this->mPrinter->getNeedsRawData() ) {
-                               $result->setRawMode();
-                       }
                }
 
+               // Printer may not be able to handle errors. This is particularly
+               // likely if the module returns something for getCustomPrinter().
+               if ( !$this->mPrinter->canPrintErrors() ) {
+                       $this->mPrinter->safeProfileOut();
+                       $this->mPrinter = $this->createPrinterByName( self::API_DEFAULT_FORMAT );
+               }
+
+               // Update raw mode flag for the selected printer.
+               $result->setRawMode( $this->mPrinter->getNeedsRawData() );
+
                if ( $e instanceof UsageException ) {
                        // User entered incorrect parameters - print usage screen
                        $errMessage = $e->getMessageArray();
@@ -734,9 +785,9 @@ class ApiMain extends ApiBase {
 
        /**
         * Check the max lag if necessary
-        * @param $module ApiBase object: Api module being used
-        * @param array $params an array containing the request parameters.
-        * @return boolean True on success, false should exit immediately
+        * @param ApiBase $module Api module being used
+        * @param array $params Array an array containing the request parameters.
+        * @return bool True on success, false should exit immediately
         */
        protected function checkMaxLag( $module, $params ) {
                if ( $module->shouldCheckMaxlag() && isset( $params['maxlag'] ) ) {
@@ -763,7 +814,7 @@ class ApiMain extends ApiBase {
 
        /**
         * Check for sufficient permissions to execute
-        * @param $module ApiBase An Api module
+        * @param ApiBase $module An Api module
         */
        protected function checkExecutePermissions( $module ) {
                $user = $this->getUser();
@@ -793,7 +844,7 @@ class ApiMain extends ApiBase {
 
        /**
         * Check asserts of the user's rights
-        * @param $params array
+        * @param array $params
         */
        protected function checkAsserts( $params ) {
                if ( isset( $params['assert'] ) ) {
@@ -815,7 +866,7 @@ class ApiMain extends ApiBase {
 
        /**
         * Check POST for external response and setup result printer
-        * @param $module ApiBase An Api module
+        * @param ApiBase $module An Api module
         * @param array $params an array with the request parameters
         */
        protected function setupExternalResponse( $module, $params ) {
@@ -905,6 +956,8 @@ class ApiMain extends ApiBase {
 
        /**
         * Encode a value in a format suitable for a space-separated log line.
+        * @param string $s
+        * return string
         */
        protected function encodeRequestLogValue( $s ) {
                static $table;
@@ -921,6 +974,7 @@ class ApiMain extends ApiBase {
 
        /**
         * Get the request parameters used in the course of the preceding execute() request
+        * @return array
         */
        protected function getParamsUsed() {
                return array_keys( $this->mParamsUsed );
@@ -928,6 +982,9 @@ class ApiMain extends ApiBase {
 
        /**
         * Get a request value, and register the fact that it was used, for logging.
+        * @param string $name
+        * @param mixed $default
+        * @return mixed
         */
        public function getVal( $name, $default = null ) {
                $this->mParamsUsed[$name] = true;
@@ -938,6 +995,8 @@ class ApiMain extends ApiBase {
        /**
         * Get a boolean request value, and register the fact that the parameter
         * was used, for logging.
+        * @param string $name
+        * @return bool
         */
        public function getCheck( $name ) {
                $this->mParamsUsed[$name] = true;
@@ -986,7 +1045,7 @@ class ApiMain extends ApiBase {
        /**
         * Print results using the current printer
         *
-        * @param $isError bool
+        * @param bool $isError
         */
        protected function printResult( $isError ) {
                global $wgDebugAPI;
@@ -1176,7 +1235,7 @@ class ApiMain extends ApiBase {
        /**
         * Sets whether the pretty-printer should format *bold* and $italics$
         *
-        * @param $help bool
+        * @param bool $help
         */
        public function setHelp( $help = true ) {
                $this->mPrinter->setHelp( $help );
@@ -1254,7 +1313,7 @@ class ApiMain extends ApiBase {
        }
 
        /**
-        * @param $module ApiBase
+        * @param ApiBase $module
         * @param string $paramName What type of request is this? e.g. action,
         *    query, list, prop, meta, format
         * @return string
@@ -1308,7 +1367,7 @@ class ApiMain extends ApiBase {
         *
         * @deprecated since 1.21, Use getModuleManager()->addModule() instead.
         * @param string $name The identifier for this module.
-        * @param $class ApiBase The class where this module is implemented.
+        * @param ApiBase $class The class where this module is implemented.
         */
        protected function addModule( $name, $class ) {
                $this->getModuleManager()->addModule( $name, 'action', $class );
@@ -1320,7 +1379,7 @@ class ApiMain extends ApiBase {
         *
         * @deprecated since 1.21, Use getModuleManager()->addModule() instead.
         * @param string $name The identifier for this format.
-        * @param $class ApiFormatBase The class implementing this format.
+        * @param ApiFormatBase $class The class implementing this format.
         */
        protected function addFormat( $name, $class ) {
                $this->getModuleManager()->addModule( $name, 'format', $class );
@@ -1363,10 +1422,10 @@ class UsageException extends MWException {
        private $mExtraData;
 
        /**
-        * @param $message string
-        * @param $codestr string
-        * @param $code int
-        * @param $extradata array|null
+        * @param string $message
+        * @param string $codestr
+        * @param int $code
+        * @param array|null $extradata
         */
        public function __construct( $message, $codestr, $code = 0, $extradata = null ) {
                parent::__construct( $message, $code );