decodeAll static method

(List<RpcDecodedFrame>, int) decodeAll(
  1. Uint8List data, {
  2. int? maxPayloadLen,
  3. int? maxMetadataLen,
  4. void onMalformedMetadata(
    1. int streamId
    )?,
})

Read multiple frames from a buffer.

Returns the decoded frames and the number of bytes consumed.

When maxPayloadLen is non-null, a frame declaring a larger payload is rejected from the header alone — the oversized payload is never sliced or buffered — by throwing RpcFrameException. Frames decoded before the offending one are not returned on throw; the caller is expected to treat the error as a protocol violation and tear down.

maxMetadataLen is enforced the same way, from the header alone.

Malformed metadata in an otherwise well-sized frame is different, and onMalformedMetadata is how a caller says so. The framing is INTACT there — the declared length is known and the payload is fully present — so the frame can be stepped over and decoding continues in sync. With the callback the offending stream id is reported and the frame skipped; without it the old throw is kept, which is what a server wants.

Implementation

static (List<RpcDecodedFrame>, int) decodeAll(
  Uint8List data, {
  int? maxPayloadLen,
  int? maxMetadataLen,
  void Function(int streamId)? onMalformedMetadata,
}) {
  final frames = <RpcDecodedFrame>[];
  var offset = 0;

  if (data.length < headerSize) return (frames, offset);

  // One view over the whole buffer, and no intermediate frame slice.
  final view = ByteData.sublistView(data);

  while (offset + headerSize <= data.length) {
    // A size violation throws here, before the payload is known to be
    // present, and is never stepped over.
    final header = _readHeader(
      view,
      offset,
      maxPayloadLen: maxPayloadLen,
      maxMetadataLen: maxMetadataLen,
    );
    final end = offset + headerSize + header.payloadLen;
    if (data.length < end) break;

    if (onMalformedMetadata == null) {
      frames.add(_frameAt(data, offset, header));
    } else {
      try {
        frames.add(_frameAt(data, offset, header));
      } on RpcFrameException {
        // Only a complete metadata payload that will not parse gets here,
        // and its framing is intact.
        onMalformedMetadata(header.streamId);
      }
    }
    offset = end;
  }

  return (frames, offset);
}