Skip to content
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

Prevent BaseHTTPMiddleware from hiding errors of StreamingResponse #1459

Merged
merged 5 commits into from
Jan 31, 2022
Merged

Prevent BaseHTTPMiddleware from hiding errors of StreamingResponse #1459

merged 5 commits into from
Jan 31, 2022

Conversation

o-fedorov
Copy link
Contributor

@o-fedorov o-fedorov commented Jan 31, 2022

The issue is observed when:

  • an application uses a BaseHTTPMiddleware subclass;
  • it provides StreamingResponse;
  • there is an exception raised inside the generator wrapped with StreamingResponse.

Prior to v0.17.0 the exception was raised and the traceback was printed to the server logs. Now it is silently ignored.

Edit by @Kludex : Closes #1433

Copy link
Member

@Kludex Kludex left a comment

Choose a reason for hiding this comment

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

Alternative to #1452

Would you mind adding this test?

def test_exception_on_mounted_apps(test_client_factory):
    sub_app = Starlette(routes=[Route("/", exc)])
    app.mount("/sub", sub_app)

    client = test_client_factory(app)
    with pytest.raises(Exception) as ctx:
        client.get("/sub/")
    assert str(ctx.value) == "Exc"

starlette/middleware/base.py Outdated Show resolved Hide resolved
* remove `nonlocal app_exc`;
* add extra test.
@o-fedorov
Copy link
Contributor Author

Alternative to #1452

Would you mind adding this test?

def test_exception_on_mounted_apps(test_client_factory):
    sub_app = Starlette(routes=[Route("/", exc)])
    app.mount("/sub", sub_app)

    client = test_client_factory(app)
    with pytest.raises(Exception) as ctx:
        client.get("/sub/")
    assert str(ctx.value) == "Exc"

The test is added

@Kludex
Copy link
Member

Kludex commented Jan 31, 2022

I don't think this work if the Response object from the middleware is ignored, as below:

from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import Response

class CustomHeaderMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        await call_next(request)
        return Response("Do you see an exception now?")

middleware = [
    Middleware(CustomHeaderMiddleware)
]

app = Starlette(routes=routes, middleware=middleware)

Can you confirm? Using the same StreamingResponse endpoint, you created on your test with this middleware.

#1452 should be able to solve this.

@o-fedorov
Copy link
Contributor Author

Sorry, both this approach and #1452 seems to not solving the issue if the Response object from the middleware is ignored

Copy link
Member

@Kludex Kludex left a comment

Choose a reason for hiding this comment

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

Sorry, both this approach and #1452 seems to not solving the issue if the Response object from the middleware is ignored

My bad... That exception is not even raised! 😆

In any case, I like this PR more than the one I created because it brings the exception conditional closer to where it can be retrieved.

@Kludex
Copy link
Member

Kludex commented Jan 31, 2022

More context about this PR can be found on #1452 and #1433.

The issue here is that we check if the endpoint (or app) raised an exception only if http.response.start is not sent, but StreamingResponse (and mounted apps) pass that conditional, and we can have an exception after that point.

@Kludex
Copy link
Member

Kludex commented Jan 31, 2022

Thanks for the PR @o-fedorov ! :)

@Kludex Kludex merged commit aff548a into encode:master Jan 31, 2022
@o-fedorov o-fedorov deleted the feature/o-fedorov/base-middleware-do-not-hide-stream-errors branch January 31, 2022 12:03
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.

Raising Exceptions in sub-applications routes
2 participants