parse method
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. iOS
// AVPlayer may request `Range: bytes=0-` for normal startup; the previous
// `start > 0 || end > 0` check returned 200 for `bytes=0-`, which makes
// the proxy look non-range-capable (delaying startup) and 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,
partial,
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');
}
}