Fix malformed disconnect frame after inbound parse errors#197
Merged
Conversation
shamblett
added a commit
that referenced
this pull request
May 15, 2026
Owner
|
Thanks for the PR. Package updated and re published at version 4.17.1 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix corrupted DISCONNECT frame on inbound parse failure
Summary
This PR fixes a buffer corruption issue in
MqttServerConnection._onData()that can cause the client to send a malformed DISCONNECT packet after an inbound message parsing error.The core fix is to clear
messageStreambefore serializing the DISCONNECT frame in the_onData()catch block. This prevents residual bytes from a failed inbound parse from being included in the outbound DISCONNECT packet.Problem
When
_onData()catches an irrecoverable parsing exception, it currently attempts to send a normal DISCONNECT message:MqttByteBuffer.reset()only resets the buffer position to0; it does not clear the underlying byte buffer.If
messageStreamstill contains bytes from a malformed or partially parsed inbound packet,disconnect.writeTo(messageStream)overwrites from position0, butsend(messageStream)still sendsmessage.length, which includes any residual bytes left after the newly written DISCONNECT frame.This can result in corrupted outbound data being sent to the broker.
Root Cause
MqttServerConnection.send()sends the full buffer length:So after
reset()+disconnect.writeTo(...), old bytes still present in the buffer can remain part of the outgoing frame.Changes
mqtt_server_connection.dartReplaces
reset()withseek(0)+clear()before writing the DISCONNECT message:This ensures the outbound DISCONNECT packet contains only the serialized DISCONNECT frame.
mqtt_header.dartAdds a defensive guard in
MqttHeader.headerBytes()so headers cannot be serialized with:messageType == nullmessageType == MqttMessageType.reserved1This prevents accidentally generating a fixed header with MQTT message type
0, which is reserved and invalid for transmission.This check only affects serialization. Existing header parsing behavior is unchanged.
mqtt_byte_buffer.dartTightens
MqttByteBuffer.isMessageAvailable()by:availableBytesrather than totallengthThis avoids a range error when the buffer position points at a single remaining
0x00byte.Tests Added
This PR adds regression coverage for the affected paths:
MqttHeader.headerBytes()rejects null message typesMqttHeader.headerBytes()rejectsreserved1MqttByteBuffer.isMessageAvailable()safely handles a single remaining zero byteThe new connection regression test failed before the fix because the sent frame contained residual data before the DISCONNECT bytes. After the fix, it sends only:
Test Plan
Ran locally:
All passed.
Compatibility
This change does not modify any public API signatures.
The main behavior change is limited to error handling and defensive validation during outbound header serialization.