in modules/serialize/src/decode_body_header.ts [129:195]
export function decodeFinalFrameBodyHeader(
buffer: Uint8Array,
headerInfo: HeaderInfo,
readPos: number
): FrameBodyHeader | false {
/* Precondition: The contentType must be FRAMED_DATA to be a Final Frame. */
needs(
ContentType.FRAMED_DATA === headerInfo.messageHeader.contentType,
'Unknown contentType'
)
const { ivLength, tagLength } = headerInfo.algorithmSuite
/* Uint8Array is a view on top of the underlying ArrayBuffer.
* This means that raw underlying memory stored in the ArrayBuffer
* may be larger than the Uint8Array. This is especially true of
* the Node.js Buffer object. The offset and length *must* be
* passed to the DataView otherwise I will get unexpected results.
*/
const dataView = new DataView(
buffer.buffer,
buffer.byteOffset,
buffer.byteLength
)
/* Precondition: decodeFinalFrameBodyHeader readPos must be within the byte length of the buffer given. */
needs(
dataView.byteLength >= readPos && readPos >= 0,
'readPos out of bounds.'
)
/* Check for early return (Postcondition): There must be enough data to decodeFinalFrameBodyHeader.
* The format expressed here is
* SEQUENCE_NUMBER_END: Uint32(FFFF)
* SequenceIdentifier: Uint32
* IVLength: Uint8
* Reserved: Uint32
* ContentLength: Uint32
*/
if (4 + 4 + ivLength + 4 + readPos > dataView.byteLength) return false
/* The precondition SEQUENCE_NUMBER_END: Uint32(FFFF) is handled above. */
const sequenceEnd = dataView.getUint32(readPos, false) // big endian
/* Postcondition: sequenceEnd must be SEQUENCE_NUMBER_END. */
needs(
sequenceEnd === SequenceIdentifier.SEQUENCE_NUMBER_END,
'Malformed final frame: Invalid sequence number end value'
)
const sequenceNumber = dataView.getUint32((readPos += 4), false) // big endian
/* Postcondition: decodeFinalFrameBodyHeader sequenceNumber must be greater than 0. */
needs(sequenceNumber > 0, 'Malformed sequenceNumber.')
const iv = buffer.slice((readPos += 4), (readPos += ivLength))
const contentLength = dataView.getUint32(readPos)
/* Postcondition: The final frame MUST NOT exceed the frameLength. */
needs(
headerInfo.messageHeader.frameLength >= contentLength,
'Final frame length exceeds frame length.'
)
return {
sequenceNumber,
iv,
contentLength,
readPos: readPos + 4,
tagLength,
isFinalFrame: true,
contentType: ContentType.FRAMED_DATA,
}
}