242 Commits

Author SHA1 Message Date
Classic298 c5ec01b1f9 fix: make the aiodns resolver opt-in and pin aiodns to 3.6.1 (#28242)
Since v0.11.0 shipped aiodns, aiohttp silently switched every outbound request from the OS resolver to c-ares. On some Windows hosts the bundled c-ares 1.34.6 (pycares 5) discovers only 127.0.0.1:53 as nameserver, so every external provider lookup fails (#28013). In Docker the long-lived c-ares channel intermittently stops resolving container names while Docker's embedded DNS keeps answering, which wipes the Ollama model list and fails all in-flight chats with a misleading "Model not found" (#28215).

This restores the pre-0.11 ThreadedResolver (OS resolver) by default and gates the c-ares path behind a new env var, AIOHTTP_CLIENT_ASYNC_DNS_RESOLVER, off by default. The event-loop DNS perf improvement is now opt-in for deployments whose resolver setup is known to work with c-ares, instead of a process-wide side effect of the package being installed.

aiodns is also downgraded and pinned to 3.6.1 (pycares<5), the last release before the broken c-ares 1.34.6 build, so opting in does not hit the Windows regression. The hardcoded AsyncResolver in the Mistral OCR loader now follows the same switch. Simply removing aiodns instead was not an option because opting in would then be impossible, and #28215 showed the Docker failure is c-ares itself, not aiodns 4.x.
2026-08-10 19:52:29 -06:00
Classic298 2d18727ab8 perf: build info log messages lazily so raising the log level actually saves work (#27837)
Raising GLOBAL_LOG_LEVEL to WARNING buys quieter output but not less work: 241 INFO call sites interpolate their payload into an f-string before the logging call gets to drop it. The heaviest is get_doc, which logs every chunk id and metadata dict in a collection, so on the full-context retrieval path that is the entire knowledge base, once per chat request.

That one line at WARNING, CPython 3.12:

| knowledge base | payload | before   | after   |
| -------------- | ------- | -------- | ------- |
| top-k of 3     | 1.2 kB  | 3.8 us   | 0.07 us |
| 500 chunks     | 201 kB  | 583.6 us | 0.08 us |
| 5000 chunks    | 2.0 MB  | 5.8 ms   | 0.15 us |

The lazy form log.info('query_doc:result %s %s', result.ids, result.metadatas) hands the payload to record.getMessage(), which the InterceptHandler only reaches once a record has passed the level check. Output at INFO is byte-identical. Two sites that already built their message eagerly, one str concat and one % operator, move to the same lazy form.
2026-08-02 15:39:10 -05:00
Timothy Jaeryang Baek 810378c0b8 refac 2026-07-27 19:39:36 -04:00
Timothy Jaeryang Baek b6b16d5871 refac 2026-07-27 19:24:03 -04:00
Timothy Jaeryang Baek c4332be71e refac 2026-07-27 04:36:56 -04:00
Timothy Jaeryang Baek 11e61b69eb refac
Co-Authored-By: Classic298 <27028174+Classic298@users.noreply.github.com>
2026-07-27 04:00:46 -04:00
Classic298 72fdf238a8 perf: optional orjson JSON codec behind ENABLE_ORJSON (#27583)
Swap the JSON encoder/decoder used across the backend from stdlib json to
orjson when ENABLE_ORJSON is set — HTTP request bodies, JSONResponse
bodies, upstream provider responses, SSE chunks, and socket.io/Redis
payloads.

The flag defaults to off, in which case the app uses stdlib json and
engineio's codec verbatim, so default behaviour is unchanged.

- json_codec exports JSONCodec (stdlib json or the orjson codec) and
  SOCKETIO_JSON (engineio's codec or the orjson codec); call sites import
  JSONCodec and stay implementation-agnostic
- apply_orjson_http_json() is a no-op when the flag is off, leaving
  starlette's Request.json / JSONResponse.render untouched
- the orjson codec falls back to the stdlib for inputs orjson rejects
  (non-str dict keys, ints beyond 64 bits, NaN literals)
- orjson is imported only when the flag is on
- FastAPI(default_response_class=...) is deliberately not used: an
  explicit default disables the Pydantic direct-to-bytes fast path for
  response_model routes
2026-07-27 03:45:37 -04:00
Timothy Jaeryang Baek 6aebfd88e9 refac 2026-07-27 02:24:41 -04:00
Timothy Jaeryang Baek def26ce266 refac 2026-07-27 01:21:32 -04:00
EntropyYue f21d7947f9 fix: Set default Redis socket timeout to None (#27104) 2026-07-27 00:30:00 -04:00
Timothy Jaeryang Baek c727643e05 refac 2026-07-27 00:11:59 -04:00
Timothy Jaeryang Baek 4a7d4ebada refac 2026-07-27 00:10:36 -04:00
Timothy Jaeryang Baek 453b9fb029 refac 2026-07-26 18:36:49 -04:00
Timothy Jaeryang Baek 2ef6c76f51 refac 2026-07-23 22:52:23 -04:00
Timothy Jaeryang Baek 429f2df50c refac 2026-07-23 21:29:33 -04:00
Timothy Jaeryang Baek bd6e0b61c2 refac 2026-07-09 17:28:05 -05:00
Timothy Jaeryang Baek 645cd9327c refac 2026-07-01 02:59:14 -05:00
Timothy Jaeryang Baek 517cd8d102 refac 2026-06-29 13:03:14 -05:00
Timothy Jaeryang Baek c0c6c2181a refac 2026-06-29 12:40:20 -05:00
Timothy Jaeryang Baek b4073f6378 refac 2026-06-29 12:29:10 -05:00
Timothy Jaeryang Baek a70a6589af refac 2026-06-29 03:42:36 -05:00
Timothy Jaeryang Baek 390e200f76 refac 2026-06-29 03:13:17 -05:00
Timothy Jaeryang Baek d99ac7d3f8 refac 2026-06-28 23:02:38 -05:00
Timothy Jaeryang Baek 0130b49514 refac 2026-06-28 22:32:10 -05:00
Timothy Jaeryang Baek a54878b14f refac 2026-06-19 15:34:43 +02:00
Timothy Jaeryang Baek eebbc48f80 refac
Co-Authored-By: Jacob Leksan <63938553+jmleksan@users.noreply.github.com>
2026-06-01 14:13:28 -07:00
Timothy Jaeryang Baek 6fce92aa12 chore: format 2026-06-01 13:56:55 -07:00
Timothy Jaeryang Baek 4297c02b12 refac 2026-06-01 12:44:16 -07:00
Timothy Jaeryang Baek c93f071700 refac 2026-06-01 11:58:16 -07:00
Classic298 83890f18b9 feat: cap profile image data URI size to bound model/avatar bloat (#25476)
* feat: cap profile image data URI size to bound model/avatar bloat

validate_profile_image_url() validated data-URI format (MIME allowlist,
SVG rejection, scheme checks) but never its length, so a valid
data:image/...;base64,<huge> passed for both custom-model icons and user
avatars. Large inline images bloat Postgres and the Redis MODELS hash and
degrade model-list latency.

Add PROFILE_IMAGE_MAX_DATA_URI_SIZE (default 256 KiB, 0 disables) and
reject oversized data URIs in the shared validator, so both model meta
(ModelMeta.profile_image_url) and user avatars (UpdateProfileForm) are
bounded at one chokepoint. ModelMeta already clears invalid values to
None on read, so existing oversized icons stop propagating into the
MODELS hash on the next refresh.

Fixes #25468

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: default PROFILE_IMAGE_MAX_DATA_URI_SIZE to None (no cap)

Per review: opt-in rather than a 256 KiB default. Unset leaves data URIs
uncapped; the validator already skips the check on a falsy value.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 09:57:06 -07:00
Timothy Jaeryang Baek ee47c9c833 refac 2026-05-31 18:34:37 -07:00
Classic298 f2650353da fix: remove hardcoded WEBUI_SECRET_KEY fallback, require key explicitly (#25218)
The 't0p-s3cr3t' default was dead code on every supported startup path:
start.sh, start_windows.bat and `open-webui serve` all set or
auto-generate WEBUI_SECRET_KEY before the backend imports env.py. It was
only ever reachable by invoking uvicorn directly, which is unsupported
and unsafe (the app would then sign tokens/cookies with a public,
hardcoded key). It also keeps getting reported as a vulnerability because
it looks dangerous, even though it is unreachable in practice.

Drop the fallback (default to '') so an unset key is caught by the
existing WEBUI_AUTH guard, and replace the vague error with a clear,
actionable message explaining that the key is a hard requirement and how
the supported start methods provide it. Exit cleanly via SystemExit
instead of raising a ValueError traceback.

WEBUI_AUTH=False keeps working unchanged (key defaults to '').

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 14:53:25 -07:00
Timothy Jaeryang Baek 2b99945d27 refac
Co-Authored-By: Classic298 <27028174+Classic298@users.noreply.github.com>
2026-05-20 00:22:27 +04:00
Timothy Jaeryang Baek f607337582 refac 2026-05-14 02:56:44 +09:00
Timothy Jaeryang Baek 5b125c24d4 feat: kb_exec 2026-05-13 15:41:30 +09:00
Timothy Jaeryang Baek 6d0295588e refac: modernize type annotations (PEP 604 / PEP 585) 2026-05-12 17:10:15 +09:00
Timothy Jaeryang Baek 998c86a52b style: standardize os.environ.get to os.getenv 2026-05-12 06:12:16 +09:00
Timothy Jaeryang Baek 83736e8dbd style: ruff format 2026-05-12 06:12:06 +09:00
Timothy Jaeryang Baek 4cee7c29a5 refac 2026-05-12 06:01:12 +09:00
Timothy Jaeryang Baek 15e696691c refac 2026-05-11 02:25:11 +09:00
Timothy Jaeryang Baek df42d96c95 refac 2026-05-09 21:05:49 +09:00
Timothy Jaeryang Baek 7bcc0e2e5c chore: format 2026-05-09 15:25:27 +09:00
Classic298 cfd2888545 fix:image url validation and signout post (#24420)
* refac(routers): reject external URLs in profile/model image handlers

* refac(ui): centralize image URL validation in safeImageUrl helper

* refac(auths): make signout POST-only

* refac: gate external profile image redirect behind ENABLE_PROFILE_IMAGE_URL_FORWARDING

Restore the 302 redirect for external http(s) profile image URLs in
the user and model profile-image endpoints, but gate it behind a new
ENABLE_PROFILE_IMAGE_URL_FORWARDING env flag (default: True).

Existing deployments that rely on external profile image forwarding
continue to work unchanged.  Operators who want to suppress the
redirect (to prevent client-side IP/UA/Referer leaks) can set the
flag to False.
2026-05-09 07:33:31 +09:00
Shamil ae0827cec0 style(env): satisfy ruff (datetime alias, line length, identity check) (#24118) 2026-05-09 05:30:09 +09:00
Timothy Jaeryang Baek db05fdaf83 refac 2026-04-24 16:23:28 +09:00
Timothy Jaeryang Baek 5127354b3e refac 2026-04-20 09:21:30 +09:00
Timothy Jaeryang Baek 7cc7b367dc refac 2026-04-17 11:27:58 +09:00
Timothy Jaeryang Baek 2f9e326dba refac 2026-04-15 10:26:47 -07:00
Timothy Jaeryang Baek 715cf9797a refac 2026-04-13 16:25:44 -05:00
Timothy Jaeryang Baek 25898116ea chore: format 2026-04-12 18:12:59 -05:00