diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-14 18:10:48 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-14 18:11:22 +0300 |
| commit | c269eeea138c002b46844b4d25c8af0c34e72447 (patch) | |
| tree | 30e482d3205cd408dfdbe533ac1377b1a8c103e9 /src/server | |
| parent | fff55440305437b2e221156d9e6a5f59e7853213 (diff) | |
fix: allow larger kitty graphics frames
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/headless.rs | 30 | ||||
| -rw-r--r-- | src/server/protocol.rs | 5 |
2 files changed, 29 insertions, 6 deletions
diff --git a/src/server/headless.rs b/src/server/headless.rs index 3ff3e587..11c486cb 100644 --- a/src/server/headless.rs +++ b/src/server/headless.rs @@ -37,7 +37,9 @@ use crate::detect::AgentState; use crate::events::AppEvent; use crate::layout::PaneId; use crate::server::client_transport::{self, ClientWriter, ServerEvent}; -use crate::server::protocol::{self, FrameData, RenderEncoding, ServerMessage, MAX_FRAME_SIZE}; +use crate::server::protocol::{ + self, FrameData, RenderEncoding, ServerMessage, MAX_FRAME_SIZE, MAX_GRAPHICS_FRAME_SIZE, +}; use crate::server::render_stream::ClientRenderState; // --------------------------------------------------------------------------- @@ -1008,13 +1010,21 @@ impl HeadlessServer { /// Encodes a server message into a length-prefixed frame. fn frame_server_message(msg: &ServerMessage) -> Result<Vec<u8>, protocol::FramingError> { + Self::frame_server_message_with_max(msg, MAX_FRAME_SIZE) + } + + /// Encodes a server message using an explicit payload cap. + fn frame_server_message_with_max( + msg: &ServerMessage, + max_frame_size: usize, + ) -> Result<Vec<u8>, protocol::FramingError> { let mut framed = Vec::new(); protocol::write_message(&mut framed, msg)?; let payload_len = framed.len().saturating_sub(4); - if payload_len > MAX_FRAME_SIZE { + if payload_len > max_frame_size { return Err(protocol::FramingError::Oversized { claimed: payload_len, - max: MAX_FRAME_SIZE, + max: max_frame_size, }); } Ok(framed) @@ -1542,11 +1552,11 @@ impl HeadlessServer { }; let mut commit_graphics_cache = true; - if frame.graphics.len() > MAX_FRAME_SIZE { + if frame.graphics.len() > MAX_GRAPHICS_FRAME_SIZE { warn!( client_id, graphics_bytes = frame.graphics.len(), - max = MAX_FRAME_SIZE, + max = MAX_GRAPHICS_FRAME_SIZE, "dropping oversized graphics payload for client frame" ); frame.graphics.clear(); @@ -1559,7 +1569,15 @@ impl HeadlessServer { }; let mut frame_to_commit = frame.clone(); - let serialized = match Self::frame_server_message(prepared.message()) { + let max_frame_size = if frame.graphics.is_empty() { + MAX_FRAME_SIZE + } else { + MAX_GRAPHICS_FRAME_SIZE + }; + let serialized = match Self::frame_server_message_with_max( + prepared.message(), + max_frame_size, + ) { Ok(framed) => framed, Err(protocol::FramingError::Oversized { claimed, max }) if !frame.graphics.is_empty() => diff --git a/src/server/protocol.rs b/src/server/protocol.rs index e0a3c4a0..1a220767 100644 --- a/src/server/protocol.rs +++ b/src/server/protocol.rs @@ -19,6 +19,11 @@ pub const PROTOCOL_VERSION: u32 = 5; /// rejected to prevent denial-of-service via oversized length prefixes. pub const MAX_FRAME_SIZE: usize = 2 * 1024 * 1024; +/// Maximum allowed server-to-client frame payload when Kitty graphics are enabled. +/// Normal traffic keeps `MAX_FRAME_SIZE`; this larger cap is only for explicit +/// image payloads that are naturally much larger after base64 encoding. +pub const MAX_GRAPHICS_FRAME_SIZE: usize = 32 * 1024 * 1024; + /// Length of the u32 little-endian length prefix in bytes. const LENGTH_PREFIX_BYTES: usize = 4; |
