diff --git a/test.js b/test.js index 19e9942..dfe741a 100644 --- a/test.js +++ b/test.js @@ -719,6 +719,22 @@ testParseOnly('Version 5 PUBACK test 1', { ) testParseAndGenerate('Version 5 PUBACK test 2', { + cmd: 'puback', + messageId: 42, + retain: false, + qos: 0, + dup: false, + length: 2, + topic: null, + payload: null, + reasonCode: 0 +}, Buffer.from([ + 64, 2, // Fixed Header (PUBACK, Remaining Length) + 0, 42 // Variable Header (2 Bytes: Packet Identifier 42, Implied reason code: 0 Success, Implied no properties) +]), { protocolVersion: 5 } +) + +testParseOnly('Version 5 PUBACK test 2.1', { cmd: 'puback', messageId: 42, retain: false, @@ -1868,18 +1884,32 @@ testParseError('Invalid header flag bits, must be 0x0 for puback packet', Buffer 0, 2 // Message ID ])) +testParseGenerate('puback without reason and no MQTT 5 properties', { + cmd: 'puback', + retain: false, + qos: 0, + dup: false, + length: 2, + messageId: 2, + reasonCode: 0 +}, Buffer.from([ + 64, 2, // Header + 0, 2 // Message ID +]), { protocolVersion: 5 }) + testParseGenerate('puback with reason and no MQTT 5 properties', { cmd: 'puback', retain: false, qos: 0, dup: false, - length: 3, + length: 4, messageId: 2, reasonCode: 16 }, Buffer.from([ - 64, 3, // Header + 64, 4, // Header 0, 2, // Message ID - 16 // reason code + 16, // reason code + 0 // no user properties ]), { protocolVersion: 5 }) testParseGenerate('puback MQTT 5 properties', { diff --git a/writeToStream.js b/writeToStream.js index 00c0b7e..74ca766 100644 --- a/writeToStream.js +++ b/writeToStream.js @@ -409,20 +409,26 @@ function confirmation (packet, stream, opts) { // Header stream.write(protocol.ACKS[type][qos][dup][0]) - // Length + // Length === 3 is only true of version === 5 and no properties; therefore if reasonCode === 0 we are allowed to skip both bytes - but if we write the reason code we also have to write property length [MQTT-3.4.2-1]. + if (length === 3) length += reasonCode !== 0 ? 1 : -1 writeVarByteInt(stream, length) // Message ID writeNumber(stream, id) - // reason code in header - if (version === 5) { + // reason code in header - but only if it couldn't be omitted - indicated by length !== 2. + if (version === 5 && length !== 2) { stream.write(Buffer.from([reasonCode])) } - // properies mqtt 5 + // properties mqtt 5 if (propertiesData !== null) { propertiesData.write() + } else { + if (length === 4) { + // we have no properties but have written a reason code - so we need to indicate empty properties by filling in a zero. + stream.write(Buffer.from([0])) + } } return true }