Skip to content

[5.6] Throttle requests exception - #23358

Merged
taylorotwell merged 4 commits into
laravel:5.6from
bencomeau:throttle-requests-exception
Mar 2, 2018
Merged

[5.6] Throttle requests exception#23358
taylorotwell merged 4 commits into
laravel:5.6from
bencomeau:throttle-requests-exception

Conversation

@bencomeau

Copy link
Copy Markdown
Contributor

Feature

I am proposing that the ThrottleRequests middleware throw a more specific exception as opposed to the current \Symfony\Component\HttpKernel\Exception\HttpException.

Reasoning

The $dontReport property of the exception handler class contains the \Symfony\Component\HttpKernel\Exception\HttpException::class which means by default rate limiting will not be logged. If one wanted to log these events, they would need to update the report method of the exception handler class to something like:

if ($exception instanceof HttpException && $exception->getStatusCode() === 429) {
    // Handle the logging as desired
}

return parent::report($exception);

Furthermore, I don't believe they would be able to use Reportable Exceptions in this instance since the exception is thrown in the framework's middleware.

Solution

Create a new exception which the ThrottleRequests middleware can utilize; one that simply extends the \Symfony\Component\HttpKernel\Exception\HttpException class. Add an additional test to the ThrottleRequestsTest to confirm the middleware is indeed throwing the desired exception.

Final Thoughts

If approved, we may consider adding \Illuminate\Http\Exceptions\ThrottleRequestsException::class to the $dontReport property of the exception handler class. Otherwise, this update would remove the long-standing functionality of not logging rate limiting by default. I would submit a pull request to the laravel repository depending on the outcome of this pull request.

@GrahamCampbell GrahamCampbell changed the title Throttle requests exception [5.6] Throttle requests exception Mar 1, 2018
try {
$this->withoutExceptionHandling()->get('/');
} catch (Throwable $e) {
$this->assertTrue($e instanceof ThrottleRequestsException);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You can use assertInstanceOf instead

@laurencei

Copy link
Copy Markdown
Contributor

I personally like the idea - but this is a breaking change. Someone might be relying on the HttpException being thrown. Plus all existing projects would suddenly start logging throttled exceptions (since it is not part of dontReport in existing projects).

@taylorotwell

taylorotwell commented Mar 2, 2018

Copy link
Copy Markdown
Member

I'm not sure there is any breaking change here if it extends HttpException. Previous try / catch will still work and it won't be logged either since that is an instanceof check and it will still see the HttpException type.

Am I wrong?

@bencomeau

Copy link
Copy Markdown
Contributor Author

Ah yes, good point @taylorotwell -- you are correct.

@morloderex

Copy link
Copy Markdown
Contributor

@taylorotwell it will still catch it because of inheritance.

@taylorotwell
taylorotwell merged commit 236a0e8 into laravel:5.6 Mar 2, 2018
@laurencei

laurencei commented Mar 2, 2018 via email

Copy link
Copy Markdown
Contributor

@GrahamCampbell

Copy link
Copy Markdown
Collaborator

TooManyRequestsHttpException already exists though...

@GrahamCampbell

Copy link
Copy Markdown
Collaborator

@bencomeau

Copy link
Copy Markdown
Contributor Author

@laurencei Thanks, hopefully I can add some details to help clear up confusion! With this functionality, users can:

  1. More easily determine if the throttle middleware was applied, from within the report method of the exception handler:

    Before:

    if ($exception instanceof HttpException && $exception->getStatusCode() === 429) {
        // Handle the logging as desired
    }
    

    After:

    if ($exception instanceof ThrottleRequestsException) {
        // Handle the logging as desired
    }
    
  2. Use Reportable & Renderable Exceptions whereas prior I do not believe this was possible.

Beyond that, I suppose the bottom-line goal was to abstract the exception a bit so it could more fluidly be handled.

@GrahamCampbell Thank you. I did notice this class existed in Symfony however given their handling of the parameters, I thought it was easier/cleaner to implement a different class. This is mostly based on the first parameter of the TooManyRequestsHttpException class, retryAfter, and the fact that we would need to pass null every time since the ThrottleRequests middleware already sets the retry after header value. Honestly, if everyone feels it should extend TooManyRequestsHttpException instead of HttpException I can do that -- I don't feel strongly enough either way.

@laurencei

Copy link
Copy Markdown
Contributor

thanks @bencomeau

@GrahamCampbell

Copy link
Copy Markdown
Collaborator

Honestly, if everyone feels it should extend TooManyRequestsHttpException instead of HttpException I can do that -- I don't feel strongly enough either way.

I feel strongly it should. It is wrong for laravel to add it's own exception when one already exists, and should have been used.

@GrahamCampbell

Copy link
Copy Markdown
Collaborator

I think it was a mistake for symfony to make their http exception class not abstract tbh.

@bencomeau

Copy link
Copy Markdown
Contributor Author

@GrahamCampbell Okay, thanks for the feedback. I do understand why you strongly feel it should -- makes enough sense to me to not reinvent the wheel :)

@taylorotwell Do you agree? Should I update this PR to extend Symfony's TooManyRequestsHttpException or should I submit a new PR?

@morloderex

Copy link
Copy Markdown
Contributor

@bencomeau it has already been merged in you need to create a new one.

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.

6 participants