The mandatory Unicode NFC normalization on API parameters was causing spurious dirty diffs in VisualEditor/DiscussionTools when editors used HTML entities to encode non-NFC codepoints, like  . Although wikitext is (ought to be!) in NFC form, the output HTML may not be, due to explicit entities in the wikitext. This type is used in VisualEditor change I0d34c9a01f1132c2616ed3392ea40d8b73e15325 to prevent Parsoid HTML from being corrupted when it is round-tripped. Bug: T266140 Change-Id: I2e78e660ba1867744e34eda7d00ea527ec016b71
141 lines
3.6 KiB
PHP
141 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace MediaWiki\Api\Validator;
|
|
|
|
use ApiMain;
|
|
use MediaWiki\Message\Converter as MessageConverter;
|
|
use Wikimedia\Message\DataMessageValue;
|
|
use Wikimedia\ParamValidator\Callbacks;
|
|
use Wikimedia\ParamValidator\Util\UploadedFile;
|
|
|
|
/**
|
|
* ParamValidator callbacks for the Action API
|
|
* @since 1.35
|
|
* @ingroup API
|
|
*/
|
|
class ApiParamValidatorCallbacks implements Callbacks {
|
|
|
|
/** @var ApiMain */
|
|
private $apiMain;
|
|
|
|
/** @var MessageConverter */
|
|
private $messageConverter;
|
|
|
|
/**
|
|
* @internal
|
|
* @param ApiMain $main
|
|
*/
|
|
public function __construct( ApiMain $main ) {
|
|
$this->apiMain = $main;
|
|
$this->messageConverter = new MessageConverter();
|
|
}
|
|
|
|
public function hasParam( $name, array $options ) {
|
|
return $this->apiMain->getCheck( $name );
|
|
}
|
|
|
|
public function getValue( $name, $default, array $options ) {
|
|
$value = $this->apiMain->getVal( $name, $default );
|
|
$request = $this->apiMain->getRequest();
|
|
$rawValue = $request->getRawVal( $name );
|
|
|
|
if ( $options['raw'] ?? false ) {
|
|
// Bypass NFC normalization
|
|
return $rawValue;
|
|
}
|
|
if ( is_string( $rawValue ) ) {
|
|
// Preserve U+001F for multi-values
|
|
if ( substr( $rawValue, 0, 1 ) === "\x1f" ) {
|
|
// This loses the potential checkTitleEncoding() transformation done by
|
|
// WebRequest for $_GET. Let's call that a feature.
|
|
$value = implode( "\x1f", $request->normalizeUnicode( explode( "\x1f", $rawValue ) ) );
|
|
}
|
|
|
|
// Check for NFC normalization, and warn
|
|
if ( $rawValue !== $value ) {
|
|
$options['module']->handleParamNormalization( $name, $value, $rawValue );
|
|
}
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
|
|
public function hasUpload( $name, array $options ) {
|
|
return $this->getUploadedFile( $name, $options ) !== null;
|
|
}
|
|
|
|
public function getUploadedFile( $name, array $options ) {
|
|
$upload = $this->apiMain->getUpload( $name );
|
|
if ( !$upload->exists() ) {
|
|
return null;
|
|
}
|
|
return new UploadedFile( [
|
|
'error' => $upload->getError(),
|
|
'tmp_name' => $upload->getTempName(),
|
|
'size' => $upload->getSize(),
|
|
'name' => $upload->getName(),
|
|
'type' => $upload->getType(),
|
|
] );
|
|
}
|
|
|
|
public function recordCondition(
|
|
DataMessageValue $message, $name, $value, array $settings, array $options
|
|
) {
|
|
/** @var \ApiBase $module */
|
|
$module = $options['module'];
|
|
|
|
$code = $message->getCode();
|
|
switch ( $code ) {
|
|
case 'param-deprecated': // @codeCoverageIgnore
|
|
case 'deprecated-value': // @codeCoverageIgnore
|
|
if ( $code === 'param-deprecated' ) {
|
|
$feature = $name;
|
|
} else {
|
|
$feature = $name . '=' . $value;
|
|
$data = $message->getData() ?? [];
|
|
if ( isset( $data['💩'] ) ) {
|
|
// This is from an old-style Message. Strip out ParamValidator's added params.
|
|
unset( $data['💩'] );
|
|
$message = DataMessageValue::new(
|
|
$message->getKey(),
|
|
array_slice( $message->getParams(), 2 ),
|
|
$code,
|
|
$data
|
|
);
|
|
}
|
|
}
|
|
|
|
$m = $module;
|
|
while ( !$m->isMain() ) {
|
|
$p = $m->getParent();
|
|
$mName = $m->getModuleName();
|
|
$mParam = $p->encodeParamName( $p->getModuleManager()->getModuleGroup( $mName ) );
|
|
$feature = "{$mParam}={$mName}&{$feature}";
|
|
$m = $p;
|
|
}
|
|
$module->addDeprecation(
|
|
$this->messageConverter->convertMessageValue( $message ),
|
|
$feature,
|
|
$message->getData()
|
|
);
|
|
break;
|
|
|
|
case 'param-sensitive': // @codeCoverageIgnore
|
|
$module->getMain()->markParamsSensitive( $name );
|
|
break;
|
|
|
|
default:
|
|
$module->addWarning(
|
|
$this->messageConverter->convertMessageValue( $message ),
|
|
$message->getCode(),
|
|
$message->getData()
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public function useHighLimits( array $options ) {
|
|
return $this->apiMain->canApiHighLimits();
|
|
}
|
|
|
|
}
|