*/
private $mPrinter;
- private $mModuleMgr, $mResult;
+ private $mModuleMgr, $mResult, $mErrorFormatter, $mContinuationManager;
private $mAction;
private $mEnableWrite;
private $mInternalMode, $mSquidMaxage, $mModule;
Hooks::run( 'ApiMain::moduleManager', array( $this->mModuleMgr ) );
- $this->mResult = new ApiResult( $this );
+ $this->mResult = new ApiResult( $this->getConfig()->get( 'APIMaxResultSize' ) );
+ $this->mErrorFormatter = new ApiErrorFormatter_BackCompat( $this->mResult );
+ $this->mResult->setErrorFormatter( $this->mErrorFormatter );
+ $this->mResult->setMainForContinuation( $this );
+ $this->mContinuationManager = null;
$this->mEnableWrite = $enableWrite;
$this->mSquidMaxage = -1; // flag for executeActionWithErrorHandling()
return $this->mResult;
}
+ /**
+ * Get the ApiErrorFormatter object associated with current request
+ * @return ApiErrorFormatter
+ */
+ public function getErrorFormatter() {
+ return $this->mErrorFormatter;
+ }
+
+ /**
+ * Get the continuation manager
+ * @return ApiContinuationManager|null
+ */
+ public function getContinuationManager() {
+ return $this->mContinuationManager;
+ }
+
+ /**
+ * Set the continuation manager
+ * @param ApiContinuationManager|null
+ */
+ public function setContinuationManager( $manager ) {
+ if ( $manager !== null ) {
+ if ( !$manager instanceof ApiContinuationManager ) {
+ throw new InvalidArgumentException( __METHOD__ . ': Was passed ' .
+ is_object( $manager ) ? get_class( $manager ) : gettype( $manager )
+ );
+ }
+ if ( $this->mContinuationManager !== null ) {
+ throw new UnexpectedValueException(
+ __METHOD__ . ': tried to set manager from ' . $manager->getSource() .
+ ' when a manager is already set from ' . $this->mContinuationManager->getSource()
+ );
+ }
+ }
+ $this->mContinuationManager = $manager;
+ }
+
/**
* Get the API module object. Only works after executeAction()
*
// Reset and print just the error message
ob_clean();
- $this->printResult( true );
+ // Printer may not be initialized if the extractRequestParams() fails for the main module
+ $this->createErrorPrinter();
+
+ try {
+ $this->printResult( true );
+ } catch ( UsageException $ex ) {
+ // The error printer itself is failing. Try suppressing its request
+ // parameters and redo.
+ $this->setWarning(
+ 'Error printer failed (will retry without params): ' . $ex->getMessage()
+ );
+ $this->mPrinter = null;
+ $this->createErrorPrinter();
+ $this->mPrinter->forceDefaultParams();
+ $this->printResult( true );
+ }
}
/**
if ( !in_array( $originParam, $origins ) ) {
// origin parameter set but incorrect
// Send a 403 response
- $message = HttpStatus::getMessage( 403 );
- $response->header( "HTTP/1.1 403 $message", true, 403 );
+ $response->statusHeader( 403 );
$response->header( 'Cache-Control: no-cache' );
echo "'origin' parameter does not match Origin header\n";
}
/**
- * Replace the result data with the information about an exception.
- * Returns the error code
- * @param Exception $e
- * @return string
+ * Create the printer for error output
*/
- protected function substituteResultWithError( $e ) {
- $result = $this->getResult();
-
- // Printer may not be initialized if the extractRequestParams() fails for the main module
+ private function createErrorPrinter() {
if ( !isset( $this->mPrinter ) ) {
- // The printer has not been created yet. Try to manually get formatter value.
$value = $this->getRequest()->getVal( 'format', self::API_DEFAULT_FORMAT );
if ( !$this->mModuleMgr->isDefined( $value, 'format' ) ) {
$value = self::API_DEFAULT_FORMAT;
}
-
$this->mPrinter = $this->createPrinterByName( $value );
}
if ( !$this->mPrinter->canPrintErrors() ) {
$this->mPrinter = $this->createPrinterByName( self::API_DEFAULT_FORMAT );
}
+ }
- // Update raw mode flag for the selected printer.
- $result->setRawMode( $this->mPrinter->getNeedsRawData() );
-
+ /**
+ * Replace the result data with the information about an exception.
+ * Returns the error code
+ * @param Exception $e
+ * @return string
+ */
+ protected function substituteResultWithError( $e ) {
+ $result = $this->getResult();
$config = $this->getConfig();
if ( $e instanceof UsageException ) {
// User entered incorrect parameters - generate error response
$errMessage = $e->getMessageArray();
$link = wfExpandUrl( wfScript( 'api' ) );
- ApiResult::setContent( $errMessage, "See $link for API usage" );
+ ApiResult::setContentValue( $errMessage, 'docref', "See $link for API usage" );
} else {
// Something is seriously wrong
if ( ( $e instanceof DBQueryError ) && !$config->get( 'ShowSQLErrors' ) ) {
'info' => '[' . MWExceptionHandler::getLogId( $e ) . '] ' . $info,
);
if ( $config->get( 'ShowExceptionDetails' ) ) {
- ApiResult::setContent(
+ ApiResult::setContentValue(
$errMessage,
+ 'trace',
MWExceptionHandler::getRedactedTraceAsString( $e )
);
}
}
// Remember all the warnings to re-add them later
- $oldResult = $result->getData();
- $warnings = isset( $oldResult['warnings'] ) ? $oldResult['warnings'] : null;
+ $warnings = $result->getResultData( array( 'warnings' ) );
$result->reset();
// Re-add the id
$this->setWarning( 'SECURITY WARNING: $wgDebugAPI is enabled' );
}
- $this->getResult()->cleanUpUTF8();
$printer = $this->mPrinter;
-
$printer->initPrinter( false );
$printer->execute();
$printer->closePrinter();
);
}
- public function modifyHelp( array &$help, array $options ) {
+ public function modifyHelp( array &$help, array $options, array &$tocData ) {
// Wish PHP had an "array_insert_before". Instead, we have to manually
// reindex the array to get 'permissions' in the right place.
$oldHelp = $help;
}
$help[$k] = $v;
}
+ $help['datatypes'] = '';
$help['credits'] = '';
// Fill 'permissions'
$help['permissions'] .= Html::closeElement( 'dl' );
$help['permissions'] .= Html::closeElement( 'div' );
- // Fill 'credits', if applicable
+ // Fill 'datatypes' and 'credits', if applicable
if ( empty( $options['nolead'] ) ) {
- $help['credits'] .= Html::element( 'h' . min( 6, $options['headerlevel'] + 1 ),
- array( 'id' => '+credits', 'class' => 'apihelp-header' ),
- $this->msg( 'api-credits-header' )->parse()
+ $level = $options['headerlevel'];
+ $tocnumber = &$options['tocnumber'];
+
+ $header = $this->msg( 'api-help-datatypes-header' )->parse();
+ $help['datatypes'] .= Html::rawelement( 'h' . min( 6, $level ),
+ array( 'id' => 'main/datatypes', 'class' => 'apihelp-header' ),
+ Html::element( 'span', array( 'id' => Sanitizer::escapeId( 'main/datatypes' ) ) ) .
+ $header
+ );
+ $help['datatypes'] .= $this->msg( 'api-help-datatypes' )->parseAsBlock();
+ if ( !isset( $tocData['main/datatypes'] ) ) {
+ $tocnumber[$level]++;
+ $tocData['main/datatypes'] = array(
+ 'toclevel' => count( $tocnumber ),
+ 'level' => $level,
+ 'anchor' => 'main/datatypes',
+ 'line' => $header,
+ 'number' => join( '.', $tocnumber ),
+ 'index' => false,
+ );
+ }
+
+ $header = $this->msg( 'api-credits-header' )->parse();
+ $help['credits'] .= Html::rawelement( 'h' . min( 6, $level ),
+ array( 'id' => 'main/credits', 'class' => 'apihelp-header' ),
+ Html::element( 'span', array( 'id' => Sanitizer::escapeId( 'main/credits' ) ) ) .
+ $header
);
$help['credits'] .= $this->msg( 'api-credits' )->useDatabase( false )->parseAsBlock();
+ if ( !isset( $tocData['main/credits'] ) ) {
+ $tocnumber[$level]++;
+ $tocData['main/credits'] = array(
+ 'toclevel' => count( $tocnumber ),
+ 'level' => $level,
+ 'anchor' => 'main/credits',
+ 'line' => $header,
+ 'number' => join( '.', $tocnumber ),
+ 'index' => false,
+ );
+ }
}
}