API: Catch Errors as well as Exceptions
[lhc/web/wiklou.git] / includes / api / ApiMain.php
index 610ecf5..3b305f9 100644 (file)
@@ -24,8 +24,6 @@
 use MediaWiki\Logger\LoggerFactory;
 use MediaWiki\MediaWikiServices;
 use Wikimedia\Timestamp\TimestampException;
-use Wikimedia\Rdbms\DBQueryError;
-use Wikimedia\Rdbms\DBError;
 
 /**
  * This is the main API class, used for both external and internal processing.
@@ -246,8 +244,7 @@ class ApiMain extends ApiBase {
                        // for uselang=user (see T85635).
                } else {
                        if ( $uselang === 'content' ) {
-                               global $wgContLang;
-                               $uselang = $wgContLang->getCode();
+                               $uselang = MediaWikiServices::getInstance()->getContentLanguage()->getCode();
                        }
                        $code = RequestContext::sanitizeLangCode( $uselang );
                        $this->getContext()->setLanguage( $code );
@@ -267,8 +264,7 @@ class ApiMain extends ApiBase {
                        if ( $errorLangCode === 'uselang' ) {
                                $errorLang = $this->getLanguage();
                        } elseif ( $errorLangCode === 'content' ) {
-                               global $wgContLang;
-                               $errorLang = $wgContLang;
+                               $errorLang = MediaWikiServices::getInstance()->getContentLanguage();
                        } else {
                                $errorLangCode = RequestContext::sanitizeLangCode( $errorLangCode );
                                $errorLang = Language::factory( $errorLangCode );
@@ -486,7 +482,7 @@ class ApiMain extends ApiBase {
         * @return ApiFormatBase
         */
        public function createPrinterByName( $format ) {
-               $printer = $this->mModuleMgr->getModule( $format, 'format' );
+               $printer = $this->mModuleMgr->getModule( $format, 'format', /* $ignoreCache */ true );
                if ( $printer === null ) {
                        $this->dieWithError(
                                [ 'apierror-unknownformat', wfEscapeWikiText( $format ) ], 'unknown_format'
@@ -535,12 +531,14 @@ class ApiMain extends ApiBase {
                        $this->executeAction();
                        $runTime = microtime( true ) - $t;
                        $this->logRequest( $runTime );
-                       if ( $this->mModule->isWriteMode() && $this->getRequest()->wasPosted() ) {
-                               MediaWikiServices::getInstance()->getStatsdDataFactory()->timing(
-                                       'api.' . $this->mModule->getModuleName() . '.executeTiming', 1000 * $runTime
-                               );
-                       }
-               } catch ( Exception $e ) {
+                       MediaWikiServices::getInstance()->getStatsdDataFactory()->timing(
+                               'api.' . $this->mModule->getModuleName() . '.executeTiming', 1000 * $runTime
+                       );
+               } catch ( Exception $e ) { // @todo Remove this block when HHVM is no longer supported
+                       $this->handleException( $e );
+                       $this->logRequest( microtime( true ) - $t, $e );
+                       $isError = true;
+               } catch ( Throwable $e ) {
                        $this->handleException( $e );
                        $this->logRequest( microtime( true ) - $t, $e );
                        $isError = true;
@@ -564,9 +562,9 @@ class ApiMain extends ApiBase {
         * Handle an exception as an API response
         *
         * @since 1.23
-        * @param Exception $e
+        * @param Exception|Throwable $e
         */
-       protected function handleException( Exception $e ) {
+       protected function handleException( $e ) {
                // T65145: Rollback any open database transactions
                if ( !( $e instanceof ApiUsageException || $e instanceof UsageException ) ) {
                        // UsageExceptions are intentional, so don't rollback if that's the case
@@ -606,7 +604,10 @@ class ApiMain extends ApiBase {
                        foreach ( $ex->getStatusValue()->getErrors() as $error ) {
                                try {
                                        $this->mPrinter->addWarning( $error );
-                               } catch ( Exception $ex2 ) {
+                               } catch ( Exception $ex2 ) { // @todo Remove this block when HHVM is no longer supported
+                                       // WTF?
+                                       $this->addWarning( $error );
+                               } catch ( Throwable $ex2 ) {
                                        // WTF?
                                        $this->addWarning( $error );
                                }
@@ -637,17 +638,20 @@ class ApiMain extends ApiBase {
         * friendly to clients. If it fails, it will rethrow the exception.
         *
         * @since 1.23
-        * @param Exception $e
-        * @throws Exception
+        * @param Exception|Throwable $e
+        * @throws Exception|Throwable
         */
-       public static function handleApiBeforeMainException( Exception $e ) {
+       public static function handleApiBeforeMainException( $e ) {
                ob_start();
 
                try {
                        $main = new self( RequestContext::getMain(), false );
                        $main->handleException( $e );
                        $main->logRequest( 0, $e );
-               } catch ( Exception $e2 ) {
+               } catch ( Exception $e2 ) { // @todo Remove this block when HHVM is no longer supported
+                       // Nope, even that didn't work. Punt.
+                       throw $e;
+               } catch ( Throwable $e2 ) {
                        // Nope, even that didn't work. Punt.
                        throw $e;
                }
@@ -813,7 +817,7 @@ class ApiMain extends ApiBase {
         * Attempt to validate the value of Access-Control-Request-Headers against a list
         * of headers that we allow the follow up request to send.
         *
-        * @param string $requestedHeaders Comma seperated list of HTTP headers
+        * @param string $requestedHeaders Comma separated list of HTTP headers
         * @return bool True if all requested headers are in the list of allowed headers
         */
        protected static function matchRequestedHeaders( $requestedHeaders ) {
@@ -1015,7 +1019,7 @@ class ApiMain extends ApiBase {
         * text around the exception's (presumably English) message as a single
         * error (no warnings).
         *
-        * @param Exception $e
+        * @param Exception|Throwable $e
         * @param string $type 'error' or 'warning'
         * @return ApiMessage[]
         * @since 1.27
@@ -1040,9 +1044,7 @@ class ApiMain extends ApiBase {
                        $config = $this->getConfig();
                        $class = preg_replace( '#^Wikimedia\\\Rdbms\\\#', '', get_class( $e ) );
                        $code = 'internal_api_error_' . $class;
-                       if ( ( $e instanceof DBQueryError ) && !$config->get( 'ShowSQLErrors' ) ) {
-                               $params = [ 'apierror-databaseerror', WebRequest::getRequestId() ];
-                       } else {
+                       if ( $config->get( 'ShowExceptionDetails' ) ) {
                                if ( $e instanceof ILocalizedException ) {
                                        $msg = $e->getMessageObject();
                                } elseif ( $e instanceof MessageSpecifier ) {
@@ -1051,7 +1053,10 @@ class ApiMain extends ApiBase {
                                        $msg = wfEscapeWikiText( $e->getMessage() );
                                }
                                $params = [ 'apierror-exceptioncaught', WebRequest::getRequestId(), $msg ];
+                       } else {
+                               $params = [ 'apierror-exceptioncaughttype', WebRequest::getRequestId(), get_class( $e ) ];
                        }
+
                        $messages[] = ApiMessage::create( $params, $code );
                }
                return $messages;
@@ -1059,7 +1064,7 @@ class ApiMain extends ApiBase {
 
        /**
         * Replace the result data with the information about an exception.
-        * @param Exception $e
+        * @param Exception|Throwable $e
         * @return string[] Error codes
         */
        protected function substituteResultWithError( $e ) {
@@ -1115,9 +1120,7 @@ class ApiMain extends ApiBase {
                                )
                        );
                } else {
-                       if ( $config->get( 'ShowExceptionDetails' ) &&
-                               ( !$e instanceof DBError || $config->get( 'ShowDBErrorBacktrace' ) )
-                       ) {
+                       if ( $config->get( 'ShowExceptionDetails' ) ) {
                                $result->addContentValue(
                                        $path,
                                        'trace',
@@ -1616,7 +1619,7 @@ class ApiMain extends ApiBase {
        /**
         * Log the preceding request
         * @param float $time Time in seconds
-        * @param Exception|null $e Exception caught while processing the request
+        * @param Exception|Throwable|null $e Exception caught while processing the request
         */
        protected function logRequest( $time, $e = null ) {
                $request = $this->getRequest();