handleHttp3StreamChunk method

void handleHttp3StreamChunk(
  1. int streamId,
  2. int streamOffset,
  3. Uint8List streamData, {
  4. required bool fin,
})

Implementation

void handleHttp3StreamChunk(
  int streamId,
  int streamOffset,
  Uint8List streamData, {
  required bool fin,
}) {
  final chunks = h3.streamChunks.putIfAbsent(
    streamId,
    () => <int, Uint8List>{},
  );
  chunks[streamOffset] = streamData;

  String kind = h3.streamKinds[streamId] ?? 'unknown';

  // ----------------------------------------------------------
  // 1) Determine stream kind
  // ----------------------------------------------------------
  if (kind == 'unknown') {
    if (_isClientInitiatedBidi(streamId)) {
      kind = 'request';
      h3.streamKinds[streamId] = kind;
      h3.streamTypePrefixLen[streamId] = 0;
    } else if (_isClientInitiatedUni(streamId)) {
      final zeroChunk = chunks[0];
      if (zeroChunk == null) {
        return; // need stream type prefix first
      }

      final typeInfo = readVarInt(zeroChunk, 0);
      if (typeInfo == null) {
        return;
      }

      final streamType = typeInfo.value as int;
      final prefixLen = typeInfo.byteLength as int;
      h3.streamTypePrefixLen[streamId] = prefixLen;

      if (streamType == H3_STREAM_TYPE_CONTROL) {
        kind = 'client_control';
        h3.peerControlStreamSeen = true;
        print('✅ Saw client HTTP/3 control stream on stream $streamId');

        // 🔴 ADD THIS LINE
        // sendHttp3SettingsPing();
      } else if (streamType == H3_STREAM_TYPE_QPACK_ENCODER) {
        kind = 'qpack_encoder';
        print('✅ Saw client QPACK encoder stream on stream $streamId');
      } else if (streamType == H3_STREAM_TYPE_QPACK_DECODER) {
        kind = 'qpack_decoder';
        print('✅ Saw client QPACK decoder stream on stream $streamId');
      } else if (streamType == WT_STREAM_TYPE_UNI) {
        kind = 'wt_uni';
        print('✅ Saw client WebTransport uni stream on stream $streamId');
      } else {
        kind = 'other_client_uni';
        print(
          'â„šī¸ Ignoring unknown client uni stream type '
          '0x${streamType.toRadixString(16)} on stream $streamId',
        );
      }

      h3.streamKinds[streamId] = kind;
    } else {
      kind = 'other';
      h3.streamKinds[streamId] = kind;
      h3.streamTypePrefixLen[streamId] = 0;
    }
  }

  final prefixLen = h3.streamTypePrefixLen[streamId] ?? 0;

  // ----------------------------------------------------------
  // 2) Handle request streams directly as HTTP/3 frame streams
  // ----------------------------------------------------------
  if (kind == 'request' || kind == 'client_control') {
    final rawStart = streamOffset;
    final rawEnd = streamOffset + streamData.length;

    if (rawEnd <= prefixLen) {
      return;
    }

    int sliceStartInChunk = 0;
    int h3Offset = rawStart - prefixLen;

    if (rawStart < prefixLen) {
      sliceStartInChunk = prefixLen - rawStart;
      h3Offset = 0;
    }

    final h3Bytes = streamData.sublist(sliceStartInChunk);

    final frameChunks = h3.h3FrameChunks.putIfAbsent(
      streamId,
      () => <int, Uint8List>{},
    );
    frameChunks[h3Offset] = h3Bytes;

    final readOffset = h3.h3FrameReadOffsets[streamId] ?? 0;
    final extracted = extract_h3_frames_from_chunks(frameChunks, readOffset);
    h3.h3FrameReadOffsets[streamId] = extracted['new_from_offset'] as int;

    for (final frame in extracted['frames']) {
      final int type = frame['frame_type'] as int;
      final Uint8List payload = frame['payload'] as Uint8List;

      if (kind == 'request') {
        if (type == H3_FRAME_HEADERS) {
          _handleHttp3HeadersFrame(streamId, payload);
        } else if (type == H3_FRAME_DATA) {
          print('đŸ“Ļ HTTP/3 DATA on stream=$streamId len=${payload.length}');
        } else {
          print(
            'â„šī¸ Ignoring unsupported request-stream frame '
            '0x${type.toRadixString(16)} on stream=$streamId',
          );
        }
      } else if (kind == 'client_control') {
        if (type == H3_FRAME_SETTINGS) {
          final settings = parse_h3_settings_frame(payload);
          print('✅ Parsed client HTTP/3 SETTINGS: $settings');
        } else {
          print(
            'â„šī¸ Ignoring client control-frame type '
            '0x${type.toRadixString(16)}',
          );
        }
      }
    }

    if (fin) {
      print('✅ QUIC stream $streamId FIN received');
    }

    return;
  }

  // ----------------------------------------------------------
  // 3) QPACK streams (currently just recognize and ignore)
  // ----------------------------------------------------------
  if (kind == 'qpack_encoder' || kind == 'qpack_decoder') {
    if (fin) {
      print('✅ QPACK stream $streamId FIN received');
    }
    return;
  }

  // ----------------------------------------------------------
  // 4) WebTransport unidirectional streams
  // ----------------------------------------------------------
  if (kind == 'wt_uni') {
    _handleWebTransportUniStreamChunk(
      streamId,
      streamOffset,
      streamData,
      fin: fin,
    );
    return;
  }

  if (fin) {
    print('✅ QUIC stream $streamId FIN received');
  }
}