<?php
/**
- *
- *
* Created on Sep 4, 2006
*
* Copyright © 2006 Yuri Astrakhan "<Firstname><Lastname>@gmail.com"
*/
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.
private $mCacheMode = 'private';
private $mCacheControl = [];
private $mParamsUsed = [];
+ private $mParamsSensitive = [];
/** @var bool|null Cached return value from self::lacksSameOriginSecurity() */
private $lacksSameOriginSecurity = null;
wfDebug( "API: stripping user credentials when the same-origin policy is not applied\n" );
$wgUser = new User();
$this->getContext()->setUser( $wgUser );
+ $request->response()->header( 'MediaWiki-Login-Suppressed: true' );
}
}
$runTime = microtime( true ) - $t;
$this->logRequest( $runTime );
if ( $this->mModule->isWriteMode() && $this->getRequest()->wasPosted() ) {
- $this->getStats()->timing(
+ MediaWikiServices::getInstance()->getStatsdDataFactory()->timing(
'api.' . $this->mModule->getModuleName() . '.executeTiming', 1000 * $runTime
);
}
if ( !$preflight ) {
$response->header(
- 'Access-Control-Expose-Headers: MediaWiki-API-Error, Retry-After, X-Database-Lag'
+ 'Access-Control-Expose-Headers: MediaWiki-API-Error, Retry-After, X-Database-Lag, '
+ . 'MediaWiki-Login-Suppressed'
);
}
}
} else {
// Something is seriously wrong
$config = $this->getConfig();
- $code = 'internal_api_error_' . get_class( $e );
+ $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 {
return $module;
}
+ /**
+ * @return array
+ */
+ private function getMaxLag() {
+ $dbLag = MediaWikiServices::getInstance()->getDBLoadBalancer()->getMaxLag();
+ $lagInfo = [
+ 'host' => $dbLag[0],
+ 'lag' => $dbLag[1],
+ 'type' => 'db'
+ ];
+
+ $jobQueueLagFactor = $this->getConfig()->get( 'JobQueueIncludeInMaxLagFactor' );
+ if ( $jobQueueLagFactor ) {
+ // Turn total number of jobs into seconds by using the configured value
+ $totalJobs = array_sum( JobQueueGroup::singleton()->getQueueSizes() );
+ $jobQueueLag = $totalJobs / (float)$jobQueueLagFactor;
+ if ( $jobQueueLag > $lagInfo['lag'] ) {
+ $lagInfo = [
+ 'host' => wfHostname(), // XXX: Is there a better value that could be used?
+ 'lag' => $jobQueueLag,
+ 'type' => 'jobqueue',
+ 'jobs' => $totalJobs,
+ ];
+ }
+ }
+
+ return $lagInfo;
+ }
+
/**
* Check the max lag if necessary
* @param ApiBase $module Api module being used
protected function checkMaxLag( $module, $params ) {
if ( $module->shouldCheckMaxlag() && isset( $params['maxlag'] ) ) {
$maxLag = $params['maxlag'];
- list( $host, $lag ) = wfGetLB()->getMaxLag();
- if ( $lag > $maxLag ) {
+ $lagInfo = $this->getMaxLag();
+ if ( $lagInfo['lag'] > $maxLag ) {
$response = $this->getRequest()->response();
$response->header( 'Retry-After: ' . max( intval( $maxLag ), 5 ) );
- $response->header( 'X-Database-Lag: ' . intval( $lag ) );
+ $response->header( 'X-Database-Lag: ' . intval( $lagInfo['lag'] ) );
if ( $this->getConfig()->get( 'ShowHostnames' ) ) {
- $this->dieWithError( [ 'apierror-maxlag', $lag, $host ] );
+ $this->dieWithError(
+ [ 'apierror-maxlag', $lagInfo['lag'], $lagInfo['host'] ],
+ 'maxlag',
+ $lagInfo
+ );
}
- $this->dieWithError( [ 'apierror-maxlag-generic', $lag ], 'maxlag' );
+ $this->dieWithError( [ 'apierror-maxlag-generic', $lagInfo['lag'] ], 'maxlag', $lagInfo );
}
}
" {$logCtx['ip']} " .
"T={$logCtx['timeSpentBackend']}ms";
+ $sensitive = array_flip( $this->getSensitiveParams() );
foreach ( $this->getParamsUsed() as $name ) {
$value = $request->getVal( $name );
if ( $value === null ) {
continue;
}
- if ( strlen( $value ) > 256 ) {
+ if ( isset( $sensitive[$name] ) ) {
+ $value = '[redacted]';
+ $encValue = '[redacted]';
+ } elseif ( strlen( $value ) > 256 ) {
$value = substr( $value, 0, 256 );
$encValue = $this->encodeRequestLogValue( $value ) . '[...]';
} else {
$this->mParamsUsed += array_fill_keys( (array)$params, true );
}
+ /**
+ * Get the request parameters that should be considered sensitive
+ * @since 1.29
+ * @return array
+ */
+ protected function getSensitiveParams() {
+ return array_keys( $this->mParamsSensitive );
+ }
+
+ /**
+ * Mark parameters as sensitive
+ * @since 1.29
+ * @param string|string[] $params
+ */
+ public function markParamsSensitive( $params ) {
+ $this->mParamsSensitive += array_fill_keys( (array)$params, true );
+ }
+
/**
* Get a request value, and register the fact that it was used, for logging.
* @param string $name