You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iggy.apache.org by hg...@apache.org on 2026/07/06 17:24:53 UTC
(iggy) 04/14: fix(server-ng): reject snapshot replies exceeding binary frame cap
This is an automated email from the ASF dual-hosted git repository.
hubcio pushed a commit to branch http-listener-rebased
in repository https://gitbox.apache.org/repos/asf/iggy.git
commit 52daec4fb197321c1e1d1aba676f76d011138f87
Author: Hubert Gruszecki <h....@gmail.com>
AuthorDate: Mon Jul 6 18:03:15 2026 +0200
fix(server-ng): reject snapshot replies exceeding binary frame cap
The snapshot archive is the first unbounded non-replicated reply body. The
binary reply frames as [256-byte header][archive], and the client's
message_bus::read_message tears the connection down untyped on any frame past
MAX_MESSAGE_SIZE (64 MiB), while a frame past u32::MAX would panic
build_reply_with_body on shard 0. Guard the archive length at the binary
dispatch arm and return a typed SnapshotFileCompletionFailed the SDK decodes.
The HTTP path streams via Body and stays uncapped.
---
core/server-ng/src/dispatch.rs | 31 ++++++++++++++++++++++++++++---
1 file changed, 28 insertions(+), 3 deletions(-)
diff --git a/core/server-ng/src/dispatch.rs b/core/server-ng/src/dispatch.rs
index 81ecdcd6d..70de9b972 100644
--- a/core/server-ng/src/dispatch.rs
+++ b/core/server-ng/src/dispatch.rs
@@ -78,12 +78,13 @@ use iggy_binary_protocol::responses::clients::get_clients::GetClientsResponse;
use iggy_binary_protocol::responses::consumer_groups::SyncConsumerGroupResponse;
use iggy_binary_protocol::responses::system::get_snapshot::GetSnapshotResponse;
use iggy_binary_protocol::{
- AckLevel, ClientVersionInfo, Command2, EvictionReason, GenericHeader, KIND_CONSUMER_GROUP,
- Operation, ProtocolVersion, RequestHeader, WireDecode, WireEncode, WireIdentifier,
- is_protocol_compatible,
+ AckLevel, ClientVersionInfo, Command2, EvictionReason, GenericHeader, HEADER_SIZE,
+ KIND_CONSUMER_GROUP, Operation, ProtocolVersion, RequestHeader, WireDecode, WireEncode,
+ WireIdentifier, is_protocol_compatible,
};
use iggy_common::{IggyError, PollingStrategy, SnapshotCompression, SystemSnapshotType};
use message_bus::client_listener::RequestHandler;
+use message_bus::framing::MAX_MESSAGE_SIZE;
use message_bus::replica::listener::MessageHandler;
use message_bus::{AUTO_COMMIT_CLIENT_ID, IggyMessageBus, MessageBus};
use metadata::impls::metadata::{
@@ -1223,6 +1224,30 @@ async fn handle_get_snapshot(
};
match result {
Ok(archive) => {
+ // The reply frames as `[256-byte header][archive]`. The client's
+ // `message_bus::read_message` rejects any frame past `MAX_MESSAGE_SIZE`
+ // (64 MiB) by tearing the connection down untyped, and a frame past
+ // `u32::MAX` would panic `build_reply_with_body`. The archive is the
+ // only unbounded non-replicated body, so refuse an oversized one with a
+ // typed error the SDK decodes. The HTTP path streams via `Body` (not
+ // this framing), so it stays uncapped.
+ let frame_size = HEADER_SIZE + archive.len();
+ if frame_size > MAX_MESSAGE_SIZE {
+ warn!(
+ transport_client_id,
+ frame_size,
+ max = MAX_MESSAGE_SIZE,
+ "snapshot archive exceeds the client frame limit; refusing to send"
+ );
+ send_non_replicated_deny(
+ shard,
+ request,
+ transport_client_id,
+ IggyError::SnapshotFileCompletionFailed.as_code(),
+ )
+ .await;
+ return;
+ }
send_non_replicated_bytes(
shard,
request,