Skip to content

Commit 644cb5c

Browse files
feat: add max_message_size parameter to MessageDecoder
MessageDecoder now accepts a max_message_size parameter (default 64 MiB) that is forwarded to the internal ReadBuffer. Previously the only way to customize the limit was to access the private _buffer attribute. Closes #138 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e085af7 commit 644cb5c

2 files changed

Lines changed: 30 additions & 2 deletions

File tree

src/dqlitewire/codec.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,12 @@ class MessageDecoder:
164164
layer that owns the socket.
165165
"""
166166

167-
def __init__(self, is_request: bool = False, version: int = PROTOCOL_VERSION) -> None:
167+
def __init__(
168+
self,
169+
is_request: bool = False,
170+
version: int = PROTOCOL_VERSION,
171+
max_message_size: int = ReadBuffer.DEFAULT_MAX_MESSAGE_SIZE,
172+
) -> None:
168173
"""Initialize decoder.
169174
170175
Args:
@@ -174,13 +179,16 @@ def __init__(self, is_request: bool = False, version: int = PROTOCOL_VERSION) ->
174179
Defaults to PROTOCOL_VERSION (1). Use PROTOCOL_VERSION_LEGACY
175180
for pre-1.0 dqlite servers (affects LeaderResponse format).
176181
Ignored for request decoders (version comes from handshake).
182+
max_message_size: Maximum allowed message size in bytes.
183+
Defaults to 64 MiB. Messages exceeding this limit are
184+
rejected with DecodeError.
177185
"""
178186
if not is_request and version not in _SUPPORTED_VERSIONS:
179187
raise ProtocolError(
180188
f"Unsupported protocol version: {version:#x}. "
181189
f"Supported: {', '.join(f'{v:#x}' for v in sorted(_SUPPORTED_VERSIONS))}"
182190
)
183-
self._buffer = ReadBuffer()
191+
self._buffer = ReadBuffer(max_message_size=max_message_size)
184192
self._is_request = is_request
185193
self._type_map = REQUEST_TYPES if is_request else RESPONSE_TYPES
186194
# For client-side decoders, version is set from the constructor parameter.

tests/test_codec.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,26 @@ def test_decoder_request_ignores_version(self) -> None:
9595
decoder = MessageDecoder(is_request=True, version=0xDEADBEEF)
9696
assert decoder.version is None # not set until handshake
9797

98+
def test_decoder_custom_max_message_size(self) -> None:
99+
"""138: max_message_size should be configurable via constructor."""
100+
import struct
101+
102+
from dqlitewire.exceptions import DecodeError
103+
104+
decoder = MessageDecoder(max_message_size=64)
105+
# Feed a message larger than 64 bytes
106+
oversized = struct.pack("<IBBH", 100, 0, 0, 0) # 808-byte body
107+
decoder.feed(oversized)
108+
with pytest.raises(DecodeError, match="exceeds maximum"):
109+
decoder.decode()
110+
111+
def test_decoder_default_max_message_size(self) -> None:
112+
"""138: default max_message_size should match ReadBuffer default."""
113+
from dqlitewire.buffer import ReadBuffer
114+
115+
decoder = MessageDecoder()
116+
assert decoder._buffer._max_message_size == ReadBuffer.DEFAULT_MAX_MESSAGE_SIZE
117+
98118
def test_decode_handshake(self) -> None:
99119
decoder = MessageDecoder(is_request=True)
100120
decoder.feed(PROTOCOL_VERSION.to_bytes(8, "little"))

0 commit comments

Comments
 (0)