From 646e3d875da702d6702009a668d5379b09024727 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Fri, 7 Jun 2024 21:31:00 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=90=9B=20Applies=20strict=20type=20co?= =?UTF-8?q?nversion=20for=20finalizing=20the=20multipart=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dio/lib/src/form_data.dart | 4 ++-- dio/lib/src/multipart_file.dart | 19 ++++++++++--------- dio/lib/src/utils.dart | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/dio/lib/src/form_data.dart b/dio/lib/src/form_data.dart index b022734d3..10bc5f626 100644 --- a/dio/lib/src/form_data.dart +++ b/dio/lib/src/form_data.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:math' as math; -import 'dart:typed_data'; +import 'dart:typed_data' show Uint8List; import 'multipart_file.dart'; import 'options.dart'; @@ -188,7 +188,7 @@ class FormData { for (final file in files) { writeUtf8('--$boundary$_rn'); writeUtf8(_headerForFile(file)); - await writeStreamToSink(file.value.finalize(), controller); + await writeStreamToSink(file.value.finalize(), controller); writeLine(); } }).then((_) { diff --git a/dio/lib/src/multipart_file.dart b/dio/lib/src/multipart_file.dart index 013401acd..f40e050cf 100644 --- a/dio/lib/src/multipart_file.dart +++ b/dio/lib/src/multipart_file.dart @@ -1,7 +1,7 @@ -import 'dart:async'; -import 'dart:convert'; +import 'dart:convert' show utf8; +import 'dart:typed_data' show Uint8List; -import 'package:http_parser/http_parser.dart'; +import 'package:http_parser/http_parser.dart' show MediaType; import 'multipart_file/io_multipart_file.dart' if (dart.library.html) 'multipart_file/browser_multipart_file.dart'; @@ -32,7 +32,7 @@ class MultipartFile { this.filename, DioMediaType? contentType, Map>? headers, - }) : _data = (() => stream), + }) : _dataBuilder = (() => stream), headers = caseInsensitiveKeyMap(headers), contentType = contentType ?? MediaType('application', 'octet-stream'); @@ -48,7 +48,7 @@ class MultipartFile { this.filename, DioMediaType? contentType, Map>? headers, - }) : _data = data, + }) : _dataBuilder = data, headers = caseInsensitiveKeyMap(headers), contentType = contentType ?? MediaType('application', 'octet-stream'); @@ -112,7 +112,7 @@ class MultipartFile { final DioMediaType? contentType; /// The stream builder that will emit the file's contents for every call. - final Stream> Function() _data; + final Stream> Function() _dataBuilder; /// Whether [finalize] has been called. bool get isFinalized => _isFinalized; @@ -153,7 +153,7 @@ class MultipartFile { bool _isFinalized = false; - Stream> finalize() { + Stream finalize() { if (isFinalized) { throw StateError( 'The MultipartFile has already been finalized. ' @@ -162,7 +162,8 @@ class MultipartFile { ); } _isFinalized = true; - return _data.call(); + return _dataBuilder() + .map((e) => e is Uint8List ? e : Uint8List.fromList(e)); } /// Clone MultipartFile, returning a new instance of the same object. @@ -170,7 +171,7 @@ class MultipartFile { /// such as an unauthorized exception can be solved by refreshing the token. MultipartFile clone() { return MultipartFile.fromStream( - _data, + _dataBuilder, length, filename: filename, contentType: contentType, diff --git a/dio/lib/src/utils.dart b/dio/lib/src/utils.dart index 5cd919898..a336e4072 100644 --- a/dio/lib/src/utils.dart +++ b/dio/lib/src/utils.dart @@ -21,7 +21,7 @@ const kReleaseMode = bool.fromEnvironment('dart.vm.product'); /// Pipes all data and errors from [stream] into [sink]. Completes [Future] once /// [stream] is done. Unlike [store], [sink] remains open after [stream] is /// done. -Future writeStreamToSink(Stream stream, EventSink sink) { +Future writeStreamToSink(Stream stream, EventSink sink) { final completer = Completer(); stream.listen( sink.add, From b6847bb30331641b074c0d7eea8089e8e8de70ed Mon Sep 17 00:00:00 2001 From: Alex Li Date: Fri, 7 Jun 2024 21:47:53 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E2=9C=85=20Add=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dio/test/formdata_test.dart | 29 +++++++++++++++++++++++++++++ dio/test/mock/_formdata | 6 ++++++ 2 files changed, 35 insertions(+) diff --git a/dio/test/formdata_test.dart b/dio/test/formdata_test.dart index b416adcdd..109a53246 100644 --- a/dio/test/formdata_test.dart +++ b/dio/test/formdata_test.dart @@ -37,6 +37,14 @@ void main() async { }, contentType: DioMediaType.parse('text/plain'), ), + MultipartFile.fromBytes( + utf8.encode('hello world again.').toList(), + filename: '3.txt', + headers: { + 'test': ['d'], + }, + contentType: DioMediaType.parse('text/plain'), + ), ], }); final fmStr = await fm.readAsBytes(); @@ -91,6 +99,19 @@ void main() async { ), ), ); + fm1.files.add( + MapEntry( + 'files', + MultipartFile.fromBytes( + utf8.encode('hello world again.'), + filename: '3.txt', + headers: { + 'test': ['d'], + }, + contentType: DioMediaType.parse('text/plain'), + ), + ), + ); expect(fmStr.length, fm1.length); }, testOn: 'vm', @@ -125,6 +146,14 @@ void main() async { }, contentType: DioMediaType.parse('text/plain'), ), + MultipartFile.fromBytes( + utf8.encode('hello world again.'), + filename: '3.txt', + headers: { + 'test': ['d'], + }, + contentType: DioMediaType.parse('text/plain'), + ), ], }); final fmStr = await fm.readAsBytes(); diff --git a/dio/test/mock/_formdata b/dio/test/mock/_formdata index dc6d79e06..814c2c946 100644 --- a/dio/test/mock/_formdata +++ b/dio/test/mock/_formdata @@ -34,4 +34,10 @@ test: c 我很好人类 哈哈哈哈哈😆 +----dio-boundary-3788753558 +content-disposition: form-data; name="files"; filename="3.txt" +content-type: text/plain +test: d + +hello world again. ----dio-boundary-3788753558-- From 7109921f8970c6753c23eac1e9847522dc679f69 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Fri, 7 Jun 2024 21:49:18 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=93=9D=20CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dio/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/dio/CHANGELOG.md b/dio/CHANGELOG.md index eebd85f38..310727a0a 100644 --- a/dio/CHANGELOG.md +++ b/dio/CHANGELOG.md @@ -8,6 +8,7 @@ See the [Migration Guide][] for the complete breaking changes list.** - Raise the min Dart SDK version to 2.18.0. - Add constructor for `DioExceptionType.badCertificate`. - Create type alias `DioMediaType` for `http_parser`'s `MediaType`. +- Fix the type conversion regression when using `MultipartFile.fromBytes`. ## 5.4.3+1 From 25b5540ae0f56691f1220245f37c0695461e99f5 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Fri, 7 Jun 2024 21:53:28 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Improve=20`Completer`s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dio/lib/src/utils.dart | 2 +- dio_test/lib/src/test/download_tests.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dio/lib/src/utils.dart b/dio/lib/src/utils.dart index a336e4072..74d6db283 100644 --- a/dio/lib/src/utils.dart +++ b/dio/lib/src/utils.dart @@ -22,7 +22,7 @@ const kReleaseMode = bool.fromEnvironment('dart.vm.product'); /// [stream] is done. Unlike [store], [sink] remains open after [stream] is /// done. Future writeStreamToSink(Stream stream, EventSink sink) { - final completer = Completer(); + final completer = Completer(); stream.listen( sink.add, onError: sink.addError, diff --git a/dio_test/lib/src/test/download_tests.dart b/dio_test/lib/src/test/download_tests.dart index 85e3f7a7b..53cb617dc 100644 --- a/dio_test/lib/src/test/download_tests.dart +++ b/dio_test/lib/src/test/download_tests.dart @@ -64,7 +64,7 @@ void downloadTests( cancelToken.cancel(); }); - final completer = Completer(); + final completer = Completer(); res.data!.stream.listen( (event) {}, onError: (e, s) {