Jonatas

fix multipart files

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'routes/app_pages.dart';
import 'shared/logger/logger_utils.dart';
void main() {
void main() async {
final client = GetConnect();
final form = FormData({
'file': MultipartFile(
File('README.md').readAsBytesSync(),
filename: 'readme.md',
),
});
final response = await client.post('http://localhost:8080/upload', form);
print(response.body);
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
... ...
... ... @@ -94,15 +94,17 @@ class GetHttpClient {
List<int> bodyBytes;
BodyBytes bodyStream;
final headers = <String, String>{};
headers['content-type'] = contentType ?? defaultContentType;
headers['user-agent'] = userAgent;
if (body is FormData) {
bodyBytes = await body.toBytes();
headers['content-length'] = bodyBytes.length.toString();
headers['content-type'] =
'multipart/form-data; boundary=${body.boundary}';
} else if (body is Map || body is List) {
var jsonString = json.encode(body);
headers['content-type'] = contentType ?? defaultContentType;
//TODO check this implementation
if (contentType != null) {
if (contentType.toLowerCase() == 'application/x-www-form-urlencoded') {
... ... @@ -114,6 +116,7 @@ class GetHttpClient {
bodyBytes = utf8.encode(jsonString);
headers['content-length'] = bodyBytes.length.toString();
} else if (body == null) {
headers['content-type'] = contentType ?? defaultContentType;
headers['content-length'] = '0';
} else {
if (!errorSafety) {
... ... @@ -126,7 +129,7 @@ class GetHttpClient {
}
final uri = _createUri(url, query);
print(headers);
return Request(
method: method,
url: uri,
... ...
import 'dart:async';
import 'dart:convert';
import 'dart:math';
import '../../../../get_rx/src/rx_stream/rx_stream.dart';
import '../request/request.dart';
import '../utils/utils.dart';
import 'multipart_file.dart';
class FormData {
FormData(Map<String, dynamic> map) : boundary = _getBoundary() {
urlEncode(map, '', false, (key, value) {
if (value == null) return;
(value is MultipartFile)
? files.add(MapEntry(key, value))
: fields.add(MapEntry(key, value.toString()));
return;
map.forEach((key, value) {
if (value == null) return null;
if (value is MultipartFile) {
files.add(MapEntry(key, value));
} else if (value is List<MultipartFile>) {
files.addAll(value.map((e) => MapEntry(key, e)));
} else {
fields.add(MapEntry(key, value.toString()));
}
});
}
... ... @@ -87,25 +89,27 @@ class FormData {
}
Future<List<int>> toBytes() {
final getStream = GetStream<List<int>>();
return BodyBytes(_encode()).toBytes();
}
for (final item in fields) {
stringToBytes('--$boundary\r\n', getStream);
stringToBytes(_fieldHeader(item.key, item.value), getStream);
stringToBytes(item.value, getStream);
writeLine(getStream);
}
Stream<List<int>> _encode() async* {
const line = [13, 10];
final separator = utf8.encode('--$boundary\r\n');
final close = utf8.encode('--$boundary--\r\n');
Future.forEach<MapEntry<String, MultipartFile>>(files, (file) {
stringToBytes('--$boundary\r\n', getStream);
stringToBytes(_fileHeader(file), getStream);
for (var field in fields) {
yield separator;
yield utf8.encode(_fieldHeader(field.key, field.value));
yield utf8.encode(field.value);
yield line;
}
return streamToFuture(file.value.stream, getStream)
.then((_) => writeLine(getStream));
}).then((_) {
stringToBytes('--$boundary--\r\n', getStream);
getStream.close();
});
return BodyBytes(getStream.stream).toBytes();
for (final file in files) {
yield separator;
yield utf8.encode(_fileHeader(file));
yield* file.value.stream;
yield line;
}
yield close;
}
}
... ...
import 'dart:async';
import 'dart:convert';
import '../../../../get_rx/src/rx_stream/rx_stream.dart';
import '../request/request.dart';
bool isTokenChar(int byte) {
... ... @@ -66,67 +65,13 @@ final newlineRegExp = RegExp(r'\r\n|\r|\n');
/// characters.
bool isPlainAscii(String string) => _asciiOnly.hasMatch(string);
StringBuffer urlEncode(
dynamic sub,
String path,
bool encode,
String Function(String key, Object value) handler,
) {
var urlData = StringBuffer('');
var leftBracket = '[';
var rightBracket = ']';
if (encode) {
leftBracket = '%5B';
rightBracket = '%5D';
}
var encodeComponent = encode ? Uri.encodeQueryComponent : (e) => e;
if (sub is Map) {
sub.forEach((key, value) {
if (path == '') {
urlEncode(
value,
'${encodeComponent(key as String)}',
encode,
handler,
);
} else {
urlEncode(
value,
'$path$leftBracket${encodeComponent(key as String)}$rightBracket',
encode,
handler,
);
}
});
} else {
throw 'FormData need be a Map';
}
return urlData;
}
const String GET_BOUNDARY = 'getx-http-boundary-';
Future streamToFuture(Stream stream, GetStream sink) {
var completer = Completer();
stream.listen(sink.add,
onError: sink.addError, onDone: () => completer.complete());
return completer.future;
}
void stringToBytes(String string, GetStream stream) {
stream.add(utf8.encode(string));
}
/// Encode [value] like browsers
String browserEncode(String value) {
return value.replaceAll(newlineRegExp, '%0D%0A').replaceAll('"', '%22');
}
void writeLine(GetStream stream) => stream.add([13, 10]);
const List<int> boundaryCharacters = <int>[
43,
95,
... ...