Prevent oversized client storage hydration payloads

Merged
HA
10d ago
+300-27

Summary

Follow-up to #7486 and #7605. #7605 stops the reconnect loop: a CONNECT that the server or a proxy drops is retried with backoff and shows a generic connection error. This PR gives a clear error when browser storage makes the hydrate larger than the server's message limit, and does not send it.

  • The frontend measures each Socket.IO CONNECT packet as the encoder produces it, so the packet is encoded once. The size includes the /_event namespace and the Engine.IO message type, as the server receives it.
  • The limit is the maxPayload from the Engine.IO handshake. The frontend build does not need the limit.
  • The size counts code points for WebSocket text frames and UTF-8 bytes for polling bodies, as python-engineio does.
  • An oversized hydrate is reported once with its size and the limit, for example: Hydration payload (1000004 characters) exceeds the server limit (1000000 characters). Reduce browser storage data and reload. The socket disconnects, and later events do not rebuild the hydrate.
  • The default ConnectionToaster shows this error at once, under its own toast id, until the user closes it. ConnectionBanner shows it too. ClientErrorType.HYDRATION_PAYLOAD_TOO_LARGE is the shared error code.

A proxy limit is not known to the client. That case keeps the backoff from #7605.

Tests

  • tests/units/compiler/state_js.test.mjs: the check measures the namespaced frame (exactly at the limit is sent, one over is refused), for both transports. It also covers: the limit comes from the handshake, code points vs. bytes, one encode per CONNECT, other packets are unchanged, no rebuild on later events or on reconnect.
  • tests/units/components/core/test_banner.py: the toaster shows the error before the two-error threshold.
  • tests/integration/tests_playwright/test_hydration_storage.py: test_hydration_over_server_limit_is_reported_once (1.1 MB of LocalStorage opens one socket, shows the error, and hydrates after the storage is cleared). It fails on main. The #7605 backoff test now covers only the proxy case.