Implement a tree-caching abuse filter parser

This filter is fully functional.  The old filter is still enabled by
default for a transitional period in case the new one suddenly has
issues.

Change-Id: I4aea5f00c62420108030e60e79d5bf34e913e95d
This commit is contained in:
Victor Vasiliev 2016-08-24 00:52:58 -04:00 committed by Aaron Schulz
parent 959077f03f
commit aa399da279
8 changed files with 1052 additions and 14 deletions

1014
AbuseFilter.parser.new.php Normal file

File diff suppressed because it is too large Load diff

View file

@ -613,6 +613,16 @@ class AbuseFilterParser {
'funcSetVar',
);
public static $mKeywords = array(
'in' => 'keywordIn',
'like' => 'keywordLike',
'matches' => 'keywordLike',
'contains' => 'keywordContains',
'rlike' => 'keywordRegex',
'irlike' => 'keywordRegexInsensitive',
'regex' => 'keywordRegex'
);
public static $funcCache = array();
/**
@ -1124,17 +1134,10 @@ class AbuseFilterParser {
protected function doLevelSpecialWords( &$result ) {
$this->doLevelUnarys( $result );
$keyword = strtolower( $this->mCur->value );
$specwords = array(
'in' => 'keywordIn',
'like' => 'keywordLike',
'matches' => 'keywordLike',
'contains' => 'keywordContains',
'rlike' => 'keywordRegex',
'irlike' => 'keywordRegexInsensitive',
'regex' => 'keywordRegex'
);
if ( $this->mCur->type == AFPToken::TKEYWORD && in_array( $keyword, array_keys( $specwords ) ) ) {
$func = $specwords[$keyword];
if ( $this->mCur->type == AFPToken::TKEYWORD
&& in_array( $keyword, array_keys( self::$mKeywords ) )
) {
$func = self::$mKeywords[$keyword];
$this->move();
$r2 = new AFPData();
$this->doLevelUnarys( $r2 );

View file

@ -72,6 +72,7 @@
"AutoloadClasses": {
"AbuseFilter": "AbuseFilter.class.php",
"AbuseFilterParser": "AbuseFilter.parser.php",
"AbuseFilterCachingParser": "AbuseFilter.parser.new.php",
"AbuseFilterTokenizer": "AbuseFilterTokenizer.php",
"AbuseFilterHooks": "AbuseFilter.hooks.php",
"AbuseFilterPreAuthenticationProvider": "AbuseFilterPreAuthenticationProvider.php",
@ -101,6 +102,8 @@
"AFPException": "AbuseFilter.parser.php",
"AFPParserState": "AbuseFilter.parser.php",
"AFPToken": "AbuseFilter.parser.php",
"AFPTreeNode": "AbuseFilter.parser.new.php",
"AFPTreeParser": "AbuseFilter.parser.new.php",
"AFPUserVisibleException": "AbuseFilter.parser.php",
"ApiQueryAbuseLog": "api/ApiQueryAbuseLog.php",
"ApiQueryAbuseFilters": "api/ApiQueryAbuseFilters.php",

View file

@ -0,0 +1 @@
NOT_MATCH

View file

@ -0,0 +1 @@
;;;;

View file

@ -0,0 +1 @@
NOT_MATCH

View file

View file

@ -37,6 +37,20 @@ class AbuseFilterParserTest extends MediaWikiTestCase {
return $parser;
}
/**
* @return [AbuseFilterParser]
*/
static function getParsers() {
static $parsers = null;
if ( !$parsers ) {
$parsers = [
new AbuseFilterParser(),
new AbuseFilterCachingParser()
];
}
return $parsers;
}
/**
* @dataProvider readTests
*/
@ -46,9 +60,10 @@ class AbuseFilterParserTest extends MediaWikiTestCase {
$this->markTestSkipped( 'Parser test ' . $testName . ' requires the AntiSpoof extension' );
}
$parser = self::getParser();
$actual = $parser->parse( $rule );
$this->assertEquals( $expected, $actual, 'Running parser test ' . $testName );
foreach ( self::getParsers() as $parser ) {
$actual = $parser->parse( $rule );
$this->assertEquals( $expected, $actual, 'Running parser test ' . $testName );
}
}
/**