RateLimiter: Fix peek mode
Why: - Setting the increment to 0 should check the limit without bumping it. - This was apparently broken by If3e66491306f22650. What: - Use LimitBatch::peek if the increment amount is 0 Bug: T381033 Change-Id: Ife76a1976a2063f051f00302e5adaebd701e6367 (cherry picked from commit e09606b3dc44711571cc6cf2d0d11bd7784d0cdd)
This commit is contained in:
parent
05cce96a77
commit
d0bbe78b23
3 changed files with 40 additions and 2 deletions
|
|
@ -210,7 +210,8 @@ class RateLimiter {
|
|||
|
||||
$conds = $this->getConditions( $action );
|
||||
$limiter = $this->wrstatsFactory->createRateLimiter( $conds, [ 'limiter', $action ] );
|
||||
$limitBatch = $limiter->createBatch( $incrBy );
|
||||
$peekMode = $incrBy === 0;
|
||||
$limitBatch = $limiter->createBatch( $incrBy ?: 1 );
|
||||
$this->logger->debug( __METHOD__ . ": limiting $action rate for {$user->getName()}" );
|
||||
|
||||
$id = $user->getId();
|
||||
|
|
@ -311,7 +312,7 @@ class RateLimiter {
|
|||
'ip' => $ip,
|
||||
];
|
||||
|
||||
$batchResult = $limitBatch->tryIncr();
|
||||
$batchResult = $peekMode ? $limitBatch->peek() : $limitBatch->tryIncr();
|
||||
foreach ( $batchResult->getFailedResults() as $type => $result ) {
|
||||
$this->logger->info(
|
||||
'User::pingLimiter: User tripped rate limit',
|
||||
|
|
|
|||
|
|
@ -87,6 +87,13 @@ class WRStatsReader {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !$seqSpec ) {
|
||||
// This check exists to make Phan happy.
|
||||
// It should never fail since we apply normalization in MetricSpec::__construct()
|
||||
throw new WRStatsError( 'There should have been at least one sequence' );
|
||||
}
|
||||
|
||||
$timeStep = $seqSpec->timeStep;
|
||||
$firstBucket = (int)( $range->start / $timeStep );
|
||||
$lastBucket = (int)ceil( $range->end / $timeStep );
|
||||
|
|
|
|||
|
|
@ -483,6 +483,36 @@ class RateLimiterTest extends MediaWikiIntegrationTestCase {
|
|||
$this->assertStatsHasCount( 'test.RateLimiter.limit.delete.result.tripped', 1, $statsData );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that setting the increment to 0 causes the RateLimiter to operate in
|
||||
* peek mode, checking a rate limit without setting it.
|
||||
*
|
||||
* Regression test for T381033.
|
||||
*/
|
||||
public function testPeek() {
|
||||
$limits = [
|
||||
'edit' => [
|
||||
'user' => [ 1, 60 ],
|
||||
],
|
||||
];
|
||||
|
||||
$user = new RateLimitSubject( new UserIdentityValue( 7, 'Garth' ), '127.0.0.1', [] );
|
||||
|
||||
$limiter = $this->newRateLimiter( $limits, [] );
|
||||
|
||||
// initial peek should pass
|
||||
$this->assertFalse( $limiter->limit( $user, 'edit', 0 ) );
|
||||
|
||||
// check that repeated peeking doesn't trigger the limit
|
||||
$this->assertFalse( $limiter->limit( $user, 'edit', 0 ) );
|
||||
|
||||
// first increment should pass but trigger the limit
|
||||
$this->assertFalse( $limiter->limit( $user, 'edit', 1 ) );
|
||||
|
||||
// peek should fail now
|
||||
$this->assertTrue( $limiter->limit( $user, 'edit', 0 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the most permissive limit is used when a limit is defined for
|
||||
* multiple groups a user belongs to.
|
||||
|
|
|
|||
Loading…
Reference in a new issue