Skip to content

RateLimiter attempt method returns true if callback returns values considered false #44820

@a-bashtannik

Description

@a-bashtannik
  • Laravel Version: 9.36.3 and other
  • PHP Version: 8.1.11 and other
  • Database Driver & Version: doesn't matter

Description:

The attempt method contains ?: operator and casts the return value of $callback function to true for all list of values considered as false.

    public function attempt($key, $maxAttempts, Closure $callback, $decaySeconds = 60)
    {
        if ($this->tooManyAttempts($key, $maxAttempts)) {
            return false;
        }

        return tap($callback() ?: true, function () use ($key, $decaySeconds) {
            $this->hit($key, $decaySeconds);
        });
    }

Steps To Reproduce:

$return = RateLimiter::attempt('key', 10, fn() => false, 1); // $return = true, not false

$return = RateLimiter::attempt('key', 10, fn() => [], 1); // $return = true, not []
$return = RateLimiter::attempt('key', 10, fn() => 0, 1); // $return = true, not 0
$return = RateLimiter::attempt('key', 10, fn() => 0.0, 1); // $return = true, not 0.0
$return = RateLimiter::attempt('key', 10, fn() => "", 1); // $return = true, not an empty string

// etc.

Obviously, it's a bug, but the fix also affects the attempt() method return value and may bring backward incompatibility to those who depend on true return.

I believe we have to change attempt() body, remove the cast:

$callback() ?: true

and return explicitly defined user value

$callback()

Case: 3rd-party APIs may return empty arrays as a successful response.

I'm ready to provide PR but kindly ask the community to advise how to deal with this bug-fix effect.
Does it make sense to push the fix in the next version branch?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions