diff --git a/packages/better_networking/lib/services/http_service.dart b/packages/better_networking/lib/services/http_service.dart index a883087e..0fc31fcd 100644 --- a/packages/better_networking/lib/services/http_service.dart +++ b/packages/better_networking/lib/services/http_service.dart @@ -180,7 +180,7 @@ Future> streamHttpRequest( bool noSSL = false, }) async { final controller = StreamController(); - StreamSubscription? subscription; + StreamSubscription?>? subscription; final stopwatch = Stopwatch()..start(); cleanup() async { @@ -296,7 +296,6 @@ Future> streamHttpRequest( } //----------------- Response Handling --------------------- - final Stream outputStream = streamTextResponse(streamedResponse); HttpResponse getResponseFromBytes(List bytes) { return HttpResponse.bytes( @@ -318,22 +317,22 @@ Future> streamHttpRequest( int receivedBytes = 0; bool hasEmitted = false; - subscription = outputStream.listen( - (chunk) { - if (chunk == null || controller.isClosed) return; + subscription = streamedResponse.stream.listen( + (bytes) { + if (controller.isClosed) return; final isStreaming = kStreamingResponseTypes.contains(contentType); if (isStreaming) { //For Streaming responses, output every response - final response = getResponseFromBytes(chunk.codeUnits); + final response = getResponseFromBytes(bytes); controller.add((true, response, stopwatch.elapsed, null)); return; } //For non Streaming events, add output to buffer - receivedBytes += chunk.codeUnits.length; - buffer.write(chunk); + receivedBytes += bytes.length; + buffer.write(decodeBytes(bytes, contentType)); if (!hasEmitted && contentLength > 0 && diff --git a/packages/better_networking/lib/utils/http_response_utils.dart b/packages/better_networking/lib/utils/http_response_utils.dart index ac4a143a..f697fc38 100644 --- a/packages/better_networking/lib/utils/http_response_utils.dart +++ b/packages/better_networking/lib/utils/http_response_utils.dart @@ -1,9 +1,10 @@ -import 'dart:convert'; import 'dart:typed_data'; import 'package:http/http.dart' as http; import 'package:http_parser/http_parser.dart'; import 'package:xml/xml.dart'; import '../consts.dart'; +import 'dart:convert'; +import 'dart:typed_data'; String? formatBody(String? body, MediaType? mediaType) { if (mediaType != null && body != null) { @@ -51,19 +52,58 @@ Future convertStreamedResponse( return response; } -Stream streamTextResponse( - http.StreamedResponse streamedResponse, -) async* { - try { - if (streamedResponse.statusCode != 200) { - final errorText = await streamedResponse.stream.bytesToString(); - throw Exception('${streamedResponse.statusCode}\n$errorText'); +// Stream streamTextResponse( +// http.StreamedResponse streamedResponse, +// ) async* { +// try { +// if (streamedResponse.statusCode != 200) { +// final errorText = await streamedResponse.stream.bytesToString(); +// throw Exception('${streamedResponse.statusCode}\n$errorText'); +// } +// final utf8Stream = streamedResponse.stream.transform(utf8.decoder); +// await for (final chunk in utf8Stream) { +// yield chunk; +// } +// } catch (e) { +// rethrow; +// } +// } + +String getCharset(String contentType) { + final match = RegExp( + r'charset=([^\s;]+)', + caseSensitive: false, + ).firstMatch(contentType); + return match?.group(1)?.toLowerCase() ?? 'utf-8'; // default to utf-8 +} + +String decodeBytes(List bytes, String contentType) { + String _decodeUtf16(List bytes, Endian endianness) { + final byteData = ByteData.sublistView(Uint8List.fromList(bytes)); + final codeUnits = []; + for (int i = 0; i + 1 < byteData.lengthInBytes; i += 2) { + codeUnits.add(byteData.getUint16(i, endianness)); } - final utf8Stream = streamedResponse.stream.transform(utf8.decoder); - await for (final chunk in utf8Stream) { - yield chunk; - } - } catch (e) { - rethrow; + return String.fromCharCodes(codeUnits); + } + + final cSet = getCharset(contentType); + switch (cSet) { + case 'utf-8': + case 'utf8': + return utf8.decode(bytes, allowMalformed: true); + case 'utf-16': + case 'utf-16le': + return _decodeUtf16(bytes, Endian.little); + case 'utf-16be': + return _decodeUtf16(bytes, Endian.big); + case 'iso-8859-1': + case 'latin1': + return latin1.decode(bytes); + case 'us-ascii': + case 'ascii': + return ascii.decode(bytes); + default: + return utf8.decode(bytes, allowMalformed: true); //UTF8 } }