Skip to content

Conversation

@amanto
Copy link

@amanto amanto commented Apr 7, 2019

Need to replace existing Laravel middleware solution https://github.com/illuminate/routing/blob/master/Middleware/ThrottleRequests.php with current package, that support restrict access by actions/controllers, general rule applying, easier configuration with configuration files.

Extracted logic from RateLimitAnnotationListener class into separate classes, so it can be reused. Laravel application using Symfony Request class, so from this point it is enough to build logic based on Request class.

Q A
Branch? master
Bug fix? yes
New feature? no
BC breaks? no
Deprecations? yes
Tests pass? yes
Documented yes

amanto added 3 commits April 7, 2019 13:29
* Extract annotation logic into separate class AnnotationLimitProcessor, cover with tests moved logic from getAliasForRequest method
* Deprecate findBestMethodMatch method. Keep it Backward Compatible
* Deprecate PathLimitProcessor->getMatchedPath. Keep it Backward Compatible
* Create LimitProcessorInterface, add to PathLimitProcessor, AnnotationLimitProcessor
* Fix getAliasForRequest, controller as object with __invoke method implemented
* Created RateLimitInfoManager with all RateLimitInfo logic
* Set request rate_limit_info attr in the end, after all RateLimitInfo logic
* Tests/EventListener/MockStorage::createMockRate add optional reset time param
* Move remaining attempts calculation into RateLimitInfo::getRemainingAttempts, cover with tests
* Highlight some existing features
* Adding example of integration in Laravel
@mcfedr
Copy link
Collaborator

mcfedr commented Apr 15, 2019

Looks good! I like the idea, just trying to review and see how best this can be done..

*/
private $controller;

public function __construct(array $annotations, callable $controller)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If think this should be a service class, and these could be arguments to the functions getRateLimit and getRateLimitAlias.

In fact - the logic that gets the annotations from the request should be moved into getRateLimit and then this arg is not needed

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, didn't get the point about service class, can you please describe idea in more details?

In fact - the logic that gets the annotations from the request should be moved into getRateLimit and then this arg is not needed

In case of Laravel application it doesn't have by default annotations, exists some packaged, but if its possible to handle rate limit logic with configuration files I think it will be easier to start using the package by other laravel developers.
From current perspective as I see, Annotation vs PathLimit processor good fit into existing package logic. In other case I assume, there is will be much more changes.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This point has not yet been addressed. As service, this class should not take as parameters things that depend on the request (controller and annotations).

array $annotations, callable $controller should be moved to the two methods below.

As example getRateLimitAlias does not need the $annotations array, and getRateLimit does not need the callable $controller.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@goetas I don't think about AnnotationLimitProcessor as service class in general.
Main idea of LimitProcessorInterface were to provide interface for implementing additional rate limit rules. If we will move arguments from AnnotationLimitProcessor constructor into methods below, we will broke interface and will do it implementation related, not based on abstraction. Current LimitProcessorInterface fit the need of extending the rate limit rules logic. I will demonstrate some examples with current package version.

As you can see, at current MR, we already replacing PathLimitProcessor based on annotations in system, proving another implementation for LimitProcessorInterface for action with annotation rule:

$limitProcessor = $this->pathLimitProcessor;
if ($annotations) {
     $limitProcessor = new AnnotationLimitProcessor($annotations, $event->getController());
}

Additional case, that I already faced with in my application: were needed to restrict rate limit only for POST actions on /documents/long-processed-resource with specific type.
For that case we can create event and in event replace rate limit rule only for that single action:

$documentProcessing = new class() implements LimitProcessorInterface
{
    /**
     * @param Request $request
     * @return RateLimit|null
     */
    public function getRateLimit(Request $request)
    {
        return new RateLimit([
            'limit' => 5,
            'period' => 60,
            'methods' => 'POST'
        ]);
    }

    /**
     * @param Request $request
     * @return string
     */
    public function getRateLimitAlias(Request $request)
    {
        return 'documents/long-processed-resource/123';
    }
};

In fact - the logic that gets the annotations from the request should be moved into getRateLimit and then this arg is not needed

In current version, with events usage rate limit rule replaced dynamically.
To provide service level and take annotations inside getRateLimit, as I see at current moment, we need to know about all annotations declared and it will be another approach, differ from applied right now.

amanto added 4 commits April 16, 2019 17:33
RateLimitService add getRateLimitInfo method from RateLimitInfoManager
RateLimitService add getRateLimitInfo method from RateLimitInfoManager
@amanto
Copy link
Author

amanto commented Jun 14, 2019

@mcfedr can you please check discussions?

@amanto
Copy link
Author

amanto commented Jul 10, 2019

@mcfedr @goetas can someone please help with pull request review?

@amanto
Copy link
Author

amanto commented Sep 2, 2019

@mcfedr @goetas do you have time to review changes?

@goetas
Copy link
Collaborator

goetas commented Sep 3, 2019

Hi, sorry, was pretty busy in the last period, will do my best to review it in the next weeks

Copy link
Collaborator

@goetas goetas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice refactoring. Here my review.

  • AnnotationLimitProcessor issues have not yet been addressed, see my comment #86 (comment)
  • Minor change on the deprecated method being still called by this library

// Find the best match
$annotations = $event->getRequest()->attributes->get('_x-rate-limit', array());

$rateLimit = $this->findBestMethodMatch($event->getRequest(), $annotations);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if findBestMethodMatch has been deprecated, this library should not use it too

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch!
Indeed, I already moved the logic into class methods, so do not use findBestMethodMatch and keep it just for BC

*/
private $controller;

public function __construct(array $annotations, callable $controller)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This point has not yet been addressed. As service, this class should not take as parameters things that depend on the request (controller and annotations).

array $annotations, callable $controller should be moved to the two methods below.

As example getRateLimitAlias does not need the $annotations array, and getRateLimit does not need the callable $controller.

{
/**
* @param Request $request
* @return mixed|RateLimit|null
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why mixed here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, will fix

- do not use deprecated findBestMethodMatch
- remove line to trigger travis build
@amanto
Copy link
Author

amanto commented Sep 6, 2019

Looks like, travis is broken:

$ phpenv global 5.4 2>/dev/null
5.4 is not pre-installed; installing
Downloading archive: https://storage.googleapis.com/travis-ci-language-archives/php/binaries/ubuntu/16.04/x86_64/php-5.4.tar.bz2
0.15s$ curl -s -o archive.tar.bz2 $archive_url && tar xjf archive.tar.bz2 --directory /
bzip2: (stdin) is not a bzip2 file.
tar: Child returned status 2
tar: Error is not recoverable: exiting now
0.00s0.02s$ phpenv global 5.4
rbenv: version `5.4' not installed

@goetas
Copy link
Collaborator

goetas commented Sep 6, 2019

I have created amanto#2 as an improved version of the current PR.

@jaytaph @amanto Feedback is welcome.

@goetas
Copy link
Collaborator

goetas commented Aug 14, 2023

I know that a lot of time passed since you have created this pull request, if you are still interested in having it merged, could you please rebase it? (some if the problems you had are solved since now we support less symfony versions and php versions)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants