Showing
4 changed files
with
48 additions
and
83 deletions
| 1 | +import 'dart:io'; | ||
| 2 | + | ||
| 1 | import 'package:flutter/material.dart'; | 3 | import 'package:flutter/material.dart'; |
| 2 | import 'package:get/get.dart'; | 4 | import 'package:get/get.dart'; |
| 3 | import 'routes/app_pages.dart'; | 5 | import 'routes/app_pages.dart'; |
| 4 | import 'shared/logger/logger_utils.dart'; | 6 | import 'shared/logger/logger_utils.dart'; |
| 5 | 7 | ||
| 6 | -void main() { | 8 | +void main() async { |
| 9 | + final client = GetConnect(); | ||
| 10 | + final form = FormData({ | ||
| 11 | + 'file': MultipartFile( | ||
| 12 | + File('README.md').readAsBytesSync(), | ||
| 13 | + filename: 'readme.md', | ||
| 14 | + ), | ||
| 15 | + }); | ||
| 16 | + final response = await client.post('http://localhost:8080/upload', form); | ||
| 17 | + | ||
| 18 | + print(response.body); | ||
| 19 | + WidgetsFlutterBinding.ensureInitialized(); | ||
| 7 | runApp(MyApp()); | 20 | runApp(MyApp()); |
| 8 | } | 21 | } |
| 9 | 22 |
| @@ -94,15 +94,17 @@ class GetHttpClient { | @@ -94,15 +94,17 @@ class GetHttpClient { | ||
| 94 | List<int> bodyBytes; | 94 | List<int> bodyBytes; |
| 95 | BodyBytes bodyStream; | 95 | BodyBytes bodyStream; |
| 96 | final headers = <String, String>{}; | 96 | final headers = <String, String>{}; |
| 97 | - headers['content-type'] = contentType ?? defaultContentType; | 97 | + |
| 98 | headers['user-agent'] = userAgent; | 98 | headers['user-agent'] = userAgent; |
| 99 | 99 | ||
| 100 | if (body is FormData) { | 100 | if (body is FormData) { |
| 101 | bodyBytes = await body.toBytes(); | 101 | bodyBytes = await body.toBytes(); |
| 102 | headers['content-length'] = bodyBytes.length.toString(); | 102 | headers['content-length'] = bodyBytes.length.toString(); |
| 103 | + headers['content-type'] = | ||
| 104 | + 'multipart/form-data; boundary=${body.boundary}'; | ||
| 103 | } else if (body is Map || body is List) { | 105 | } else if (body is Map || body is List) { |
| 104 | var jsonString = json.encode(body); | 106 | var jsonString = json.encode(body); |
| 105 | - | 107 | + headers['content-type'] = contentType ?? defaultContentType; |
| 106 | //TODO check this implementation | 108 | //TODO check this implementation |
| 107 | if (contentType != null) { | 109 | if (contentType != null) { |
| 108 | if (contentType.toLowerCase() == 'application/x-www-form-urlencoded') { | 110 | if (contentType.toLowerCase() == 'application/x-www-form-urlencoded') { |
| @@ -114,6 +116,7 @@ class GetHttpClient { | @@ -114,6 +116,7 @@ class GetHttpClient { | ||
| 114 | bodyBytes = utf8.encode(jsonString); | 116 | bodyBytes = utf8.encode(jsonString); |
| 115 | headers['content-length'] = bodyBytes.length.toString(); | 117 | headers['content-length'] = bodyBytes.length.toString(); |
| 116 | } else if (body == null) { | 118 | } else if (body == null) { |
| 119 | + headers['content-type'] = contentType ?? defaultContentType; | ||
| 117 | headers['content-length'] = '0'; | 120 | headers['content-length'] = '0'; |
| 118 | } else { | 121 | } else { |
| 119 | if (!errorSafety) { | 122 | if (!errorSafety) { |
| @@ -126,7 +129,7 @@ class GetHttpClient { | @@ -126,7 +129,7 @@ class GetHttpClient { | ||
| 126 | } | 129 | } |
| 127 | 130 | ||
| 128 | final uri = _createUri(url, query); | 131 | final uri = _createUri(url, query); |
| 129 | - | 132 | + print(headers); |
| 130 | return Request( | 133 | return Request( |
| 131 | method: method, | 134 | method: method, |
| 132 | url: uri, | 135 | url: uri, |
| 1 | import 'dart:async'; | 1 | import 'dart:async'; |
| 2 | import 'dart:convert'; | 2 | import 'dart:convert'; |
| 3 | import 'dart:math'; | 3 | import 'dart:math'; |
| 4 | -import '../../../../get_rx/src/rx_stream/rx_stream.dart'; | ||
| 5 | import '../request/request.dart'; | 4 | import '../request/request.dart'; |
| 6 | import '../utils/utils.dart'; | 5 | import '../utils/utils.dart'; |
| 7 | import 'multipart_file.dart'; | 6 | import 'multipart_file.dart'; |
| 8 | 7 | ||
| 9 | class FormData { | 8 | class FormData { |
| 10 | FormData(Map<String, dynamic> map) : boundary = _getBoundary() { | 9 | FormData(Map<String, dynamic> map) : boundary = _getBoundary() { |
| 11 | - urlEncode(map, '', false, (key, value) { | ||
| 12 | - if (value == null) return; | ||
| 13 | - (value is MultipartFile) | ||
| 14 | - ? files.add(MapEntry(key, value)) | ||
| 15 | - : fields.add(MapEntry(key, value.toString())); | ||
| 16 | - return; | 10 | + map.forEach((key, value) { |
| 11 | + if (value == null) return null; | ||
| 12 | + if (value is MultipartFile) { | ||
| 13 | + files.add(MapEntry(key, value)); | ||
| 14 | + } else if (value is List<MultipartFile>) { | ||
| 15 | + files.addAll(value.map((e) => MapEntry(key, e))); | ||
| 16 | + } else { | ||
| 17 | + fields.add(MapEntry(key, value.toString())); | ||
| 18 | + } | ||
| 17 | }); | 19 | }); |
| 18 | } | 20 | } |
| 19 | 21 | ||
| @@ -87,25 +89,27 @@ class FormData { | @@ -87,25 +89,27 @@ class FormData { | ||
| 87 | } | 89 | } |
| 88 | 90 | ||
| 89 | Future<List<int>> toBytes() { | 91 | Future<List<int>> toBytes() { |
| 90 | - final getStream = GetStream<List<int>>(); | ||
| 91 | - | ||
| 92 | - for (final item in fields) { | ||
| 93 | - stringToBytes('--$boundary\r\n', getStream); | ||
| 94 | - stringToBytes(_fieldHeader(item.key, item.value), getStream); | ||
| 95 | - stringToBytes(item.value, getStream); | ||
| 96 | - writeLine(getStream); | 92 | + return BodyBytes(_encode()).toBytes(); |
| 97 | } | 93 | } |
| 98 | 94 | ||
| 99 | - Future.forEach<MapEntry<String, MultipartFile>>(files, (file) { | ||
| 100 | - stringToBytes('--$boundary\r\n', getStream); | ||
| 101 | - stringToBytes(_fileHeader(file), getStream); | 95 | + Stream<List<int>> _encode() async* { |
| 96 | + const line = [13, 10]; | ||
| 97 | + final separator = utf8.encode('--$boundary\r\n'); | ||
| 98 | + final close = utf8.encode('--$boundary--\r\n'); | ||
| 102 | 99 | ||
| 103 | - return streamToFuture(file.value.stream, getStream) | ||
| 104 | - .then((_) => writeLine(getStream)); | ||
| 105 | - }).then((_) { | ||
| 106 | - stringToBytes('--$boundary--\r\n', getStream); | ||
| 107 | - getStream.close(); | ||
| 108 | - }); | ||
| 109 | - return BodyBytes(getStream.stream).toBytes(); | 100 | + for (var field in fields) { |
| 101 | + yield separator; | ||
| 102 | + yield utf8.encode(_fieldHeader(field.key, field.value)); | ||
| 103 | + yield utf8.encode(field.value); | ||
| 104 | + yield line; | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + for (final file in files) { | ||
| 108 | + yield separator; | ||
| 109 | + yield utf8.encode(_fileHeader(file)); | ||
| 110 | + yield* file.value.stream; | ||
| 111 | + yield line; | ||
| 112 | + } | ||
| 113 | + yield close; | ||
| 110 | } | 114 | } |
| 111 | } | 115 | } |
| 1 | import 'dart:async'; | 1 | import 'dart:async'; |
| 2 | import 'dart:convert'; | 2 | import 'dart:convert'; |
| 3 | -import '../../../../get_rx/src/rx_stream/rx_stream.dart'; | ||
| 4 | import '../request/request.dart'; | 3 | import '../request/request.dart'; |
| 5 | 4 | ||
| 6 | bool isTokenChar(int byte) { | 5 | bool isTokenChar(int byte) { |
| @@ -66,67 +65,13 @@ final newlineRegExp = RegExp(r'\r\n|\r|\n'); | @@ -66,67 +65,13 @@ final newlineRegExp = RegExp(r'\r\n|\r|\n'); | ||
| 66 | /// characters. | 65 | /// characters. |
| 67 | bool isPlainAscii(String string) => _asciiOnly.hasMatch(string); | 66 | bool isPlainAscii(String string) => _asciiOnly.hasMatch(string); |
| 68 | 67 | ||
| 69 | -StringBuffer urlEncode( | ||
| 70 | - dynamic sub, | ||
| 71 | - String path, | ||
| 72 | - bool encode, | ||
| 73 | - String Function(String key, Object value) handler, | ||
| 74 | -) { | ||
| 75 | - var urlData = StringBuffer(''); | ||
| 76 | - var leftBracket = '['; | ||
| 77 | - var rightBracket = ']'; | ||
| 78 | - | ||
| 79 | - if (encode) { | ||
| 80 | - leftBracket = '%5B'; | ||
| 81 | - rightBracket = '%5D'; | ||
| 82 | - } | ||
| 83 | - | ||
| 84 | - var encodeComponent = encode ? Uri.encodeQueryComponent : (e) => e; | ||
| 85 | - if (sub is Map) { | ||
| 86 | - sub.forEach((key, value) { | ||
| 87 | - if (path == '') { | ||
| 88 | - urlEncode( | ||
| 89 | - value, | ||
| 90 | - '${encodeComponent(key as String)}', | ||
| 91 | - encode, | ||
| 92 | - handler, | ||
| 93 | - ); | ||
| 94 | - } else { | ||
| 95 | - urlEncode( | ||
| 96 | - value, | ||
| 97 | - '$path$leftBracket${encodeComponent(key as String)}$rightBracket', | ||
| 98 | - encode, | ||
| 99 | - handler, | ||
| 100 | - ); | ||
| 101 | - } | ||
| 102 | - }); | ||
| 103 | - } else { | ||
| 104 | - throw 'FormData need be a Map'; | ||
| 105 | - } | ||
| 106 | - | ||
| 107 | - return urlData; | ||
| 108 | -} | ||
| 109 | - | ||
| 110 | const String GET_BOUNDARY = 'getx-http-boundary-'; | 68 | const String GET_BOUNDARY = 'getx-http-boundary-'; |
| 111 | 69 | ||
| 112 | -Future streamToFuture(Stream stream, GetStream sink) { | ||
| 113 | - var completer = Completer(); | ||
| 114 | - stream.listen(sink.add, | ||
| 115 | - onError: sink.addError, onDone: () => completer.complete()); | ||
| 116 | - return completer.future; | ||
| 117 | -} | ||
| 118 | - | ||
| 119 | -void stringToBytes(String string, GetStream stream) { | ||
| 120 | - stream.add(utf8.encode(string)); | ||
| 121 | -} | ||
| 122 | - | ||
| 123 | /// Encode [value] like browsers | 70 | /// Encode [value] like browsers |
| 124 | String browserEncode(String value) { | 71 | String browserEncode(String value) { |
| 125 | return value.replaceAll(newlineRegExp, '%0D%0A').replaceAll('"', '%22'); | 72 | return value.replaceAll(newlineRegExp, '%0D%0A').replaceAll('"', '%22'); |
| 126 | } | 73 | } |
| 127 | 74 | ||
| 128 | -void writeLine(GetStream stream) => stream.add([13, 10]); | ||
| 129 | - | ||
| 130 | const List<int> boundaryCharacters = <int>[ | 75 | const List<int> boundaryCharacters = <int>[ |
| 131 | 43, | 76 | 43, |
| 132 | 95, | 77 | 95, |
-
Please register or login to post a comment