prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  middleware causes exceptions to not be raised/handled silently
  ### Discussed in https://github.com/encode/starlette/discussions/1976
  
  <div type='discussions-op-text'>
  
  <sup>Originally posted by **fraser-langton** December  6, 2022</sup>
  From [issue in FastAPI](https://github.com/tiangolo/fastapi/issues/5173) - issue was said to be from starlette
  
  Was initially noticed in FastAPI 0.74.0, was fixed after 0.79.0 but has since regressed (FastAPI 0.88.0 it isn't working)
  
  When exceptions are raised on a subapp, the exceptions are not propagated all the way to see in console
  In the example code
  /info raises an exception and the full stacktrace is seen in console
  /private/info does not raise the exception and only `INFO: 127.0.0.1:56308 - "GET /info HTTP/1.1" 500 Internal Server Error` is shown in console
  
  ```python
  import uvicorn
  from fastapi import FastAPI
  from starlette.middleware.base import BaseHTTPMiddleware
  
  
  app = FastAPI()
  
  
  @app.get("/info")
  def info():
      # raises Exception as expected, the traceback is seen in console
      raise Exception
  
  
  private_api = FastAPI()
  
  
  @private_api.get("/info")
  def info():
      # exception is handled silently, no traceback is seen in console
      raise Exception
  
  
  app.mount("/private", private_api)
  
  
  class Middleware(BaseHTTPMiddleware):
  
      async def dispatch(self, request, call_next):
          return await call_next(request)
  
  
  app.add_middleware(Middleware)  # when this is removed, the exceptions are raised for all routes
  
  
  if __name__ == '__main__':
      uvicorn.run(app, port=8000)
  ```
  </div>
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `starlette/middleware/base.py`
  Content:
  ```
  1 import typing
  2 
  3 import anyio
  4 
  5 from starlette.requests import Request
  6 from starlette.responses import Response, StreamingResponse
  7 from starlette.types import ASGIApp, Message, Receive, Scope, Send
  8 
  9 RequestResponseEndpoint = typing.Callable[[Request], typing.Awaitable[Response]]
  10 DispatchFunction = typing.Callable[
  11     [Request, RequestResponseEndpoint], typing.Awaitable[Response]
  12 ]
  13 T = typing.TypeVar("T")
  14 
  15 
  16 class BaseHTTPMiddleware:
  17     def __init__(
  18         self, app: ASGIApp, dispatch: typing.Optional[DispatchFunction] = None
  19     ) -> None:
  20         self.app = app
  21         self.dispatch_func = self.dispatch if dispatch is None else dispatch
  22 
  23     async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
  24         if scope["type"] != "http":
  25             await self.app(scope, receive, send)
  26             return
  27 
  28         response_sent = anyio.Event()
  29 
  30         async def call_next(request: Request) -> Response:
  31             app_exc: typing.Optional[Exception] = None
  32             send_stream, recv_stream = anyio.create_memory_object_stream()
  33 
  34             async def receive_or_disconnect() -> Message:
  35                 if response_sent.is_set():
  36                     return {"type": "http.disconnect"}
  37 
  38                 async with anyio.create_task_group() as task_group:
  39 
  40                     async def wrap(func: typing.Callable[[], typing.Awaitable[T]]) -> T:
  41                         result = await func()
  42                         task_group.cancel_scope.cancel()
  43                         return result
  44 
  45                     task_group.start_soon(wrap, response_sent.wait)
  46                     message = await wrap(request.receive)
  47 
  48                 if response_sent.is_set():
  49                     return {"type": "http.disconnect"}
  50 
  51                 return message
  52 
  53             async def close_recv_stream_on_response_sent() -> None:
  54                 await response_sent.wait()
  55                 recv_stream.close()
  56 
  57             async def send_no_error(message: Message) -> None:
  58                 try:
  59                     await send_stream.send(message)
  60                 except anyio.BrokenResourceError:
  61                     # recv_stream has been closed, i.e. response_sent has been set.
  62                     return
  63 
  64             async def coro() -> None:
  65                 nonlocal app_exc
  66 
  67                 async with send_stream:
  68                     try:
  69                         await self.app(scope, receive_or_disconnect, send_no_error)
  70                     except Exception as exc:
  71                         app_exc = exc
  72 
  73             task_group.start_soon(close_recv_stream_on_response_sent)
  74             task_group.start_soon(coro)
  75 
  76             try:
  77                 message = await recv_stream.receive()
  78             except anyio.EndOfStream:
  79                 if app_exc is not None:
  80                     raise app_exc
  81                 raise RuntimeError("No response returned.")
  82 
  83             assert message["type"] == "http.response.start"
  84 
  85             async def body_stream() -> typing.AsyncGenerator[bytes, None]:
  86                 async with recv_stream:
  87                     async for message in recv_stream:
  88                         assert message["type"] == "http.response.body"
  89                         body = message.get("body", b"")
  90                         if body:
  91                             yield body
  92                         if not message.get("more_body", False):
  93                             break
  94 
  95                 if app_exc is not None:
  96                     raise app_exc
  97 
  98             response = StreamingResponse(
  99                 status_code=message["status"], content=body_stream()
  100             )
  101             response.raw_headers = message["headers"]
  102             return response
  103 
  104         async with anyio.create_task_group() as task_group:
  105             request = Request(scope, receive=receive)
  106             response = await self.dispatch_func(request, call_next)
  107             await response(scope, receive, send)
  108             response_sent.set()
  109 
  110     async def dispatch(
  111         self, request: Request, call_next: RequestResponseEndpoint
  112     ) -> Response:
  113         raise NotImplementedError()  # pragma: no cover
  114
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/starlette/middleware/base.py b/starlette/middleware/base.py
  --- a/starlette/middleware/base.py
  +++ b/starlette/middleware/base.py
  @@ -89,8 +89,6 @@
                           body = message.get("body", b"")
                           if body:
                               yield body
  -                        if not message.get("more_body", False):
  -                            break
   
                   if app_exc is not None:
                       raise app_exc
  
verification_info: {"golden_diff": "diff --git a/starlette/middleware/base.py b/starlette/middleware/base.py\n--- a/starlette/middleware/base.py\n+++ b/starlette/middleware/base.py\n@@ -89,8 +89,6 @@\n                         body = message.get(\"body\", b\"\")\n                         if body:\n                             yield body\n-                        if not message.get(\"more_body\", False):\n-                            break\n \n                 if app_exc is not None:\n                     raise app_exc\n", "issue": "middleware causes exceptions to not be raised/handled silently\n### Discussed in https://github.com/encode/starlette/discussions/1976\r\n\r\n<div type='discussions-op-text'>\r\n\r\n<sup>Originally posted by **fraser-langton** December  6, 2022</sup>\r\nFrom [issue in FastAPI](https://github.com/tiangolo/fastapi/issues/5173) - issue was said to be from starlette\r\n\r\nWas initially noticed in FastAPI 0.74.0, was fixed after 0.79.0 but has since regressed (FastAPI 0.88.0 it isn't working)\r\n\r\nWhen exceptions are raised on a subapp, the exceptions are not propagated all the way to see in console\r\nIn the example code\r\n/info raises an exception and the full stacktrace is seen in console\r\n/private/info does not raise the exception and only `INFO: 127.0.0.1:56308 - \"GET /info HTTP/1.1\" 500 Internal Server Error` is shown in console\r\n\r\n```python\r\nimport uvicorn\r\nfrom fastapi import FastAPI\r\nfrom starlette.middleware.base import BaseHTTPMiddleware\r\n\r\n\r\napp = FastAPI()\r\n\r\n\r\n@app.get(\"/info\")\r\ndef info():\r\n    # raises Exception as expected, the traceback is seen in console\r\n    raise Exception\r\n\r\n\r\nprivate_api = FastAPI()\r\n\r\n\r\n@private_api.get(\"/info\")\r\ndef info():\r\n    # exception is handled silently, no traceback is seen in console\r\n    raise Exception\r\n\r\n\r\napp.mount(\"/private\", private_api)\r\n\r\n\r\nclass Middleware(BaseHTTPMiddleware):\r\n\r\n    async def dispatch(self, request, call_next):\r\n        return await call_next(request)\r\n\r\n\r\napp.add_middleware(Middleware)  # when this is removed, the exceptions are raised for all routes\r\n\r\n\r\nif __name__ == '__main__':\r\n    uvicorn.run(app, port=8000)\r\n```\r\n</div>\n", "before_files": [{"content": "import typing\n\nimport anyio\n\nfrom starlette.requests import Request\nfrom starlette.responses import Response, StreamingResponse\nfrom starlette.types import ASGIApp, Message, Receive, Scope, Send\n\nRequestResponseEndpoint = typing.Callable[[Request], typing.Awaitable[Response]]\nDispatchFunction = typing.Callable[\n    [Request, RequestResponseEndpoint], typing.Awaitable[Response]\n]\nT = typing.TypeVar(\"T\")\n\n\nclass BaseHTTPMiddleware:\n    def __init__(\n        self, app: ASGIApp, dispatch: typing.Optional[DispatchFunction] = None\n    ) -> None:\n        self.app = app\n        self.dispatch_func = self.dispatch if dispatch is None else dispatch\n\n    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:\n        if scope[\"type\"] != \"http\":\n            await self.app(scope, receive, send)\n            return\n\n        response_sent = anyio.Event()\n\n        async def call_next(request: Request) -> Response:\n            app_exc: typing.Optional[Exception] = None\n            send_stream, recv_stream = anyio.create_memory_object_stream()\n\n            async def receive_or_disconnect() -> Message:\n                if response_sent.is_set():\n                    return {\"type\": \"http.disconnect\"}\n\n                async with anyio.create_task_group() as task_group:\n\n                    async def wrap(func: typing.Callable[[], typing.Awaitable[T]]) -> T:\n                        result = await func()\n                        task_group.cancel_scope.cancel()\n                        return result\n\n                    task_group.start_soon(wrap, response_sent.wait)\n                    message = await wrap(request.receive)\n\n                if response_sent.is_set():\n                    return {\"type\": \"http.disconnect\"}\n\n                return message\n\n            async def close_recv_stream_on_response_sent() -> None:\n                await response_sent.wait()\n                recv_stream.close()\n\n            async def send_no_error(message: Message) -> None:\n                try:\n                    await send_stream.send(message)\n                except anyio.BrokenResourceError:\n                    # recv_stream has been closed, i.e. response_sent has been set.\n                    return\n\n            async def coro() -> None:\n                nonlocal app_exc\n\n                async with send_stream:\n                    try:\n                        await self.app(scope, receive_or_disconnect, send_no_error)\n                    except Exception as exc:\n                        app_exc = exc\n\n            task_group.start_soon(close_recv_stream_on_response_sent)\n            task_group.start_soon(coro)\n\n            try:\n                message = await recv_stream.receive()\n            except anyio.EndOfStream:\n                if app_exc is not None:\n                    raise app_exc\n                raise RuntimeError(\"No response returned.\")\n\n            assert message[\"type\"] == \"http.response.start\"\n\n            async def body_stream() -> typing.AsyncGenerator[bytes, None]:\n                async with recv_stream:\n                    async for message in recv_stream:\n                        assert message[\"type\"] == \"http.response.body\"\n                        body = message.get(\"body\", b\"\")\n                        if body:\n                            yield body\n                        if not message.get(\"more_body\", False):\n                            break\n\n                if app_exc is not None:\n                    raise app_exc\n\n            response = StreamingResponse(\n                status_code=message[\"status\"], content=body_stream()\n            )\n            response.raw_headers = message[\"headers\"]\n            return response\n\n        async with anyio.create_task_group() as task_group:\n            request = Request(scope, receive=receive)\n            response = await self.dispatch_func(request, call_next)\n            await response(scope, receive, send)\n            response_sent.set()\n\n    async def dispatch(\n        self, request: Request, call_next: RequestResponseEndpoint\n    ) -> Response:\n        raise NotImplementedError()  # pragma: no cover\n", "path": "starlette/middleware/base.py"}], "after_files": [{"content": "import typing\n\nimport anyio\n\nfrom starlette.requests import Request\nfrom starlette.responses import Response, StreamingResponse\nfrom starlette.types import ASGIApp, Message, Receive, Scope, Send\n\nRequestResponseEndpoint = typing.Callable[[Request], typing.Awaitable[Response]]\nDispatchFunction = typing.Callable[\n    [Request, RequestResponseEndpoint], typing.Awaitable[Response]\n]\nT = typing.TypeVar(\"T\")\n\n\nclass BaseHTTPMiddleware:\n    def __init__(\n        self, app: ASGIApp, dispatch: typing.Optional[DispatchFunction] = None\n    ) -> None:\n        self.app = app\n        self.dispatch_func = self.dispatch if dispatch is None else dispatch\n\n    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:\n        if scope[\"type\"] != \"http\":\n            await self.app(scope, receive, send)\n            return\n\n        response_sent = anyio.Event()\n\n        async def call_next(request: Request) -> Response:\n            app_exc: typing.Optional[Exception] = None\n            send_stream, recv_stream = anyio.create_memory_object_stream()\n\n            async def receive_or_disconnect() -> Message:\n                if response_sent.is_set():\n                    return {\"type\": \"http.disconnect\"}\n\n                async with anyio.create_task_group() as task_group:\n\n                    async def wrap(func: typing.Callable[[], typing.Awaitable[T]]) -> T:\n                        result = await func()\n                        task_group.cancel_scope.cancel()\n                        return result\n\n                    task_group.start_soon(wrap, response_sent.wait)\n                    message = await wrap(request.receive)\n\n                if response_sent.is_set():\n                    return {\"type\": \"http.disconnect\"}\n\n                return message\n\n            async def close_recv_stream_on_response_sent() -> None:\n                await response_sent.wait()\n                recv_stream.close()\n\n            async def send_no_error(message: Message) -> None:\n                try:\n                    await send_stream.send(message)\n                except anyio.BrokenResourceError:\n                    # recv_stream has been closed, i.e. response_sent has been set.\n                    return\n\n            async def coro() -> None:\n                nonlocal app_exc\n\n                async with send_stream:\n                    try:\n                        await self.app(scope, receive_or_disconnect, send_no_error)\n                    except Exception as exc:\n                        app_exc = exc\n\n            task_group.start_soon(close_recv_stream_on_response_sent)\n            task_group.start_soon(coro)\n\n            try:\n                message = await recv_stream.receive()\n            except anyio.EndOfStream:\n                if app_exc is not None:\n                    raise app_exc\n                raise RuntimeError(\"No response returned.\")\n\n            assert message[\"type\"] == \"http.response.start\"\n\n            async def body_stream() -> typing.AsyncGenerator[bytes, None]:\n                async with recv_stream:\n                    async for message in recv_stream:\n                        assert message[\"type\"] == \"http.response.body\"\n                        body = message.get(\"body\", b\"\")\n                        if body:\n                            yield body\n\n                if app_exc is not None:\n                    raise app_exc\n\n            response = StreamingResponse(\n                status_code=message[\"status\"], content=body_stream()\n            )\n            response.raw_headers = message[\"headers\"]\n            return response\n\n        async with anyio.create_task_group() as task_group:\n            request = Request(scope, receive=receive)\n            response = await self.dispatch_func(request, call_next)\n            await response(scope, receive, send)\n            response_sent.set()\n\n    async def dispatch(\n        self, request: Request, call_next: RequestResponseEndpoint\n    ) -> Response:\n        raise NotImplementedError()  # pragma: no cover\n", "path": "starlette/middleware/base.py"}]}