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