Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[HttpKernel] ErrorListener::onKernelException should ignore exception thrown after kernel.terminate #51912

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
VincentLanglet opened this issue Oct 9, 2023 · 4 comments · Fixed by #52128

Comments

@VincentLanglet
Copy link
Contributor

Symfony version(s) affected

all

Description

Related to #45205 issue, which was ignored...

When an exception is thrown in a kernel.terminate event,

  • kernel.exception is thrown
  • the Symfony ErrorListener::onKernelException handler the exception
  • $response = $event->getKernel()->handle($request, HttpKernelInterface::SUB_REQUEST, false); is called
  • this trigger the ErrorController and then the TwigErrorRenderer
  1. The response rendered seems useless since the response was already sent before the terminate event. (cf https://symfony.com/doc/current/components/http_kernel.html#8-the-kernel-terminate-event)
  2. It can produce extra-useless exception, in my case I have a custom view TwigBundle/Exception/error.html.twig
    which use the session and/or flashbag and I'm getting some Failed to start the session because headers have already been sent.

Introducing a kernel.terminate_exception and using it instead of kernel.exception could even appear as a BC break for kernel.exception listeners or a bugfix because according to the schema in the doc https://symfony.com/doc/current/components/http_kernel.html#handling-exceptions-the-kernel-exception-event, we can see the order Exception -> Response -> Terminate.

How to reproduce

  • Throw an exception in a kernel.terminate listener -> You'll get extra code executed for no reason
  • Add app.session.flashbag.get('success') call in a custom TwigBundle/Exception/error.html.twig template. -> You'll get failed to start the session error in your logs.

Possible Solution

Either throw a different event for exception thrown after the terminate exception

Either, at least provide a ExceptionEvent::isTerminated or TerminableInterface::isTerminated, which would allow to write

if ($thing->isTerminated()) {
     return;
}

at the beginning of some ExceptionListener like the ErrorListener

Additional Context

No response

@fancyweb
Copy link
Contributor

The current logic might actually be "OK" enough.
When fastcgi_finish_request() is not called, then the extra response and exception are actually output and are useful.
Also, I'm pretty sure some people rely on the current logic without knowing it 😅

@VincentLanglet
Copy link
Contributor Author

The current logic might actually be "OK" enough. When fastcgi_finish_request() is not called, then the extra response and exception are actually output and are useful.
Also, I'm pretty sure some people rely on the current logic without knowing it 😅

That's why I proposed adding a isTerminated method and calling in the ErrorListener to early return in order to avoid BC break as much as possible. People customer listeners won't be impacted. Only the ErrorListener would be.

But maybe things should be thought differently:
If the fastcgi_finish_request call finish the request, there is no need to try rendering a view anymore no ?
What about an early return

if (headers_sent()) {
        return;
}

somewhere in the ErrorListener or TwigErrorRenderer ?

@nicolas-grekas
Copy link
Member

On my side I think #52047 is the way to go.

adding a isTerminated method and calling in the ErrorListener to early return

Why not, but then this creates an opportunity to hide errors, so at least the early return should also check if we're in debug mode, and skip the exception only if not.

if (headers_sent()) {

nope, that's too hacky.

nicolas-grekas added a commit that referenced this issue Oct 18, 2023
…onse::send() (fancyweb)

This PR was merged into the 6.4 branch.

Discussion
----------

[HttpFoundation][Runtime] Add $flush parameter to Response::send()

| Q             | A
| ------------- | ---
| Branch?       | 6.4
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | -
| License       | MIT

Inspired by #51912 and #45205 subjects

Adds optional argument `$flush` to `Response::send()`. If `$flush === false`, output buffers are not flushed/`*_finish_request()` and alike functions are not called.

We leverage that in the Runtime component by not flushing the output buffers when debug mode is on in order to see exceptions thrown in listeners listening on the `TerminateEvent` and also to feel a more "real" processing time of things happening on terminate.

Commits
-------

a3304cc [HttpFoundation] Add $flush parameter to Response::send()
@VincentLanglet
Copy link
Contributor Author

On my side I think #52047 is the way to go.

adding a isTerminated method and calling in the ErrorListener to early return

Why not, but then this creates an opportunity to hide errors, so at least the early return should also check if we're in debug mode, and skip the exception only if not.

Something like this #52128 ?

@fabpot fabpot closed this as completed in 638f7d0 Nov 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants