parse method

  1. @override
Future<bool> parse(
  1. Socket socket,
  2. Uri uri,
  3. Map<String, String> headers
)
override

Parses the request and returns the data to the socket.

Handles HTTP range requests for large file downloads, splitting the file into segments (default 2MB, configurable via Config.segmentSize).

Returns true if parsing and response succeed, otherwise false.

Implementation

@override
Future<bool> parse(
  Socket socket,
  Uri uri,
  Map<String, String> headers,
) async {
  try {
    // Implementation for parsing and responding to HTTP range requests.
    // Handles both Android and iOS platforms.
    RegExp exp = RegExp(r'bytes=(\d+)-(\d*)');
    RegExpMatch? rangeMatch = exp.firstMatch(headers['range'] ?? '');
    int requestRangeStart = int.tryParse(rangeMatch?.group(1) ?? '0') ?? 0;
    int requestRangeEnd = int.tryParse(rangeMatch?.group(2) ?? '0') ?? -1;
    // Any request carrying a Range header must be answered with 206. The
    // previous `start > 0 || end > 0` check returned 200 for `bytes=0-`, which
    // makes ffmpeg/libmpv treat the stream as non-seekable (is_streamed=1):
    // seeking jumps to EOF and, when moov sits at the tail, the final frames
    // decode as garbage.
    bool partial = rangeMatch != null;
    List<String> responseHeaders = <String>[
      partial ? 'HTTP/1.1 206 Partial Content' : 'HTTP/1.1 200 OK',
      'Accept-Ranges: bytes',
      'Content-Type: video/mp4',
    ];

    if (Platform.isAndroid) {
      await parseAndroid(
        socket,
        uri,
        responseHeaders,
        requestRangeStart,
        requestRangeEnd,
        headers,
      );
    } else {
      await parseIOS(
        socket,
        uri,
        responseHeaders,
        requestRangeStart,
        requestRangeEnd,
        headers,
      );
    }
    await socket.flush();
    return true;
  } catch (e) {
    // Handles any errors during parsing.
    logW('[UrlParserMp4] ⚠ ⚠ ⚠ parse error: $e');
    return false;
  } finally {
    // Ensures the socket is closed after processing.
    await socket.close();
    logD('Connection closed\n');
  }
}