[PR #23709] [MERGED] fix(middleware): replace BaseHTTPMiddleware HTTP middlewares with pure ASGI implementations #114638

Closed
opened 2026-05-18 15:26:55 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/open-webui/open-webui/pull/23709
Author: @Classic298
Created: 4/14/2026
Status: Merged
Merged: 4/14/2026
Merged by: @tjbck

Base: devHead: claude/fix/pure-asgi-middleware


📝 Commits (2)

  • 225e62a fix(middleware): replace BaseHTTPMiddleware HTTP middlewares with pure ASGI implementations
  • 3a20b2d fix(middleware): CommitSessionMiddleware — rollback on downstream error, never commit failed requests

📊 Changes

2 files changed (+290 additions, -96 deletions)

View changed files

📝 backend/open_webui/main.py (+17 -96)
backend/open_webui/utils/asgi_middleware.py (+273 -0)

📄 Description

Starlette's BaseHTTPMiddleware (and the @app.middleware('http') decorator that uses it) wraps the downstream app in an anyio task group whose cancel scope tears down the inner task on every exit — client disconnect, response complete, or any outer middleware bailing. That CancelledError gets injected into whatever the inner task was awaiting, so DB queries, embedding calls, and other long awaits get killed mid-flight. Under aiosqlite the cleanup path then logs a multi-page terminate_force_close() not implemented traceback at ERROR for every cancelled DB call.

Open WebUI had four such middlewares stacked
(commit_session_after_request, check_url, inspect_websocket, RedirectMiddleware) so a single cancellation would compound through all four.

Move the four middlewares to a new open_webui.utils.asgi_middleware module as plain ASGI classes (__call__(scope, receive, send)):

  • CommitSessionMiddleware — was commit_session_after_request;
    now also rolls back if commit fails
    before releasing the connection.
  • AuthTokenMiddleware — was check_url; sets request.state
    token + enable_api_keys + stamps
    X-Process-Time via a wrapped send.
  • WebsocketUpgradeGuardMiddleware
    — was inspect_websocket; rejects
    /ws/socket.io HTTP requests that
    claim transport=websocket without a
    proper Upgrade/Connection header.
  • RedirectMiddleware — was the BaseHTTPMiddleware subclass;
    same /watch + share-target rewrites.

Pure ASGI does not introduce a cancel scope around the downstream app, so client disconnects propagate via receive() (the way ASGI was designed) instead of being injected as CancelledError. Middleware ordering is preserved.

Contributor License Agreement

Note

Deleting the CLA section will lead to immediate closure of your PR and it will not be merged in.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/open-webui/open-webui/pull/23709 **Author:** [@Classic298](https://github.com/Classic298) **Created:** 4/14/2026 **Status:** ✅ Merged **Merged:** 4/14/2026 **Merged by:** [@tjbck](https://github.com/tjbck) **Base:** `dev` ← **Head:** `claude/fix/pure-asgi-middleware` --- ### 📝 Commits (2) - [`225e62a`](https://github.com/open-webui/open-webui/commit/225e62a1c7d661ae2935fb3910adcf6fa2028a42) fix(middleware): replace BaseHTTPMiddleware HTTP middlewares with pure ASGI implementations - [`3a20b2d`](https://github.com/open-webui/open-webui/commit/3a20b2da85bb62f4751218af9be70166b32265a9) fix(middleware): CommitSessionMiddleware — rollback on downstream error, never commit failed requests ### 📊 Changes **2 files changed** (+290 additions, -96 deletions) <details> <summary>View changed files</summary> 📝 `backend/open_webui/main.py` (+17 -96) ➕ `backend/open_webui/utils/asgi_middleware.py` (+273 -0) </details> ### 📄 Description Starlette's BaseHTTPMiddleware (and the @app.middleware('http') decorator that uses it) wraps the downstream app in an anyio task group whose cancel scope tears down the inner task on every exit — client disconnect, response complete, or any outer middleware bailing. That CancelledError gets injected into whatever the inner task was awaiting, so DB queries, embedding calls, and other long awaits get killed mid-flight. Under aiosqlite the cleanup path then logs a multi-page `terminate_force_close() not implemented` traceback at ERROR for every cancelled DB call. Open WebUI had four such middlewares stacked (`commit_session_after_request`, `check_url`, `inspect_websocket`, `RedirectMiddleware`) so a single cancellation would compound through all four. Move the four middlewares to a new `open_webui.utils.asgi_middleware` module as plain ASGI classes (`__call__(scope, receive, send)`): * `CommitSessionMiddleware` — was `commit_session_after_request`; now also rolls back if commit fails before releasing the connection. * `AuthTokenMiddleware` — was `check_url`; sets request.state token + enable_api_keys + stamps X-Process-Time via a wrapped send. * `WebsocketUpgradeGuardMiddleware` — was `inspect_websocket`; rejects /ws/socket.io HTTP requests that claim transport=websocket without a proper Upgrade/Connection header. * `RedirectMiddleware` — was the BaseHTTPMiddleware subclass; same /watch + share-target rewrites. Pure ASGI does not introduce a cancel scope around the downstream app, so client disconnects propagate via `receive()` (the way ASGI was designed) instead of being injected as CancelledError. Middleware ordering is preserved. ### Contributor License Agreement <!-- 🚨 DO NOT DELETE THE TEXT BELOW 🚨 Keep the "Contributor License Agreement" confirmation text intact. Deleting it will trigger the CLA-Bot to INVALIDATE your PR. Your PR will NOT be reviewed or merged until you check the box below confirming that you have read and agree to the terms of the CLA. --> - [X] By submitting this pull request, I confirm that I have read and fully agree to the [Contributor License Agreement (CLA)](https://github.com/open-webui/open-webui/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT), and I am providing my contributions under its terms. > [!NOTE] > Deleting the CLA section will lead to immediate closure of your PR and it will not be merged in. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-05-18 15:26:55 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#114638