Jonatas

update to 3.22.0

  1 +## [3.22.0]
  2 +- Added: more multipart options. Now you can send as multipart:
  3 +
  4 +File:
  5 +'file':MultipartFile(File('./images/avatar.png'), filename: 'avatar.png'),
  6 +
  7 +String path:
  8 +'file':MultipartFile('./images/avatar.png', filename: 'avatar.png'),
  9 +
  10 +Or bytes (Flutter web work only with bytes):
  11 +'file':MultipartFile(File('file').readAsBytesSync(), filename: 'avatar.png'),
  12 +
  13 +- Improve: auto jsonDecode occurs only if response.header.contentType is "application/json"
  14 +
  15 +- Added: Upload Progress to MultipartRequest
  16 +- Added support to List<MultipartFile> (@jasonlaw)
  17 +- Improve and fix requests types (@eduardoflorence)
  18 +- Fix HeaderValue variables with same name (@haidang93)
  19 +
1 ## [3.21.3] 20 ## [3.21.3]
2 - Improve multipart file and defaultDecoder on GetConnect 21 - Improve multipart file and defaultDecoder on GetConnect
3 22
  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';
@@ -127,6 +127,7 @@ class GetConnect extends GetConnectInterface { @@ -127,6 +127,7 @@ class GetConnect extends GetConnectInterface {
127 Map<String, String> headers, 127 Map<String, String> headers,
128 Map<String, dynamic> query, 128 Map<String, dynamic> query,
129 Decoder<T> decoder, 129 Decoder<T> decoder,
  130 + Progress uploadProgress,
130 }) { 131 }) {
131 _checkIfDisposed(); 132 _checkIfDisposed();
132 return httpClient.post<T>( 133 return httpClient.post<T>(
@@ -136,6 +137,7 @@ class GetConnect extends GetConnectInterface { @@ -136,6 +137,7 @@ class GetConnect extends GetConnectInterface {
136 contentType: contentType, 137 contentType: contentType,
137 query: query, 138 query: query,
138 decoder: decoder, 139 decoder: decoder,
  140 + uploadProgress: uploadProgress,
139 ); 141 );
140 } 142 }
141 143
@@ -147,6 +149,7 @@ class GetConnect extends GetConnectInterface { @@ -147,6 +149,7 @@ class GetConnect extends GetConnectInterface {
147 Map<String, String> headers, 149 Map<String, String> headers,
148 Map<String, dynamic> query, 150 Map<String, dynamic> query,
149 Decoder<T> decoder, 151 Decoder<T> decoder,
  152 + Progress uploadProgress,
150 }) { 153 }) {
151 _checkIfDisposed(); 154 _checkIfDisposed();
152 return httpClient.put<T>( 155 return httpClient.put<T>(
@@ -156,6 +159,7 @@ class GetConnect extends GetConnectInterface { @@ -156,6 +159,7 @@ class GetConnect extends GetConnectInterface {
156 contentType: contentType, 159 contentType: contentType,
157 query: query, 160 query: query,
158 decoder: decoder, 161 decoder: decoder,
  162 + uploadProgress: uploadProgress,
159 ); 163 );
160 } 164 }
161 165
@@ -168,6 +172,7 @@ class GetConnect extends GetConnectInterface { @@ -168,6 +172,7 @@ class GetConnect extends GetConnectInterface {
168 Map<String, String> headers, 172 Map<String, String> headers,
169 Map<String, dynamic> query, 173 Map<String, dynamic> query,
170 Decoder<T> decoder, 174 Decoder<T> decoder,
  175 + Progress uploadProgress,
171 }) { 176 }) {
172 _checkIfDisposed(); 177 _checkIfDisposed();
173 return httpClient.request<T>( 178 return httpClient.request<T>(
@@ -178,6 +183,7 @@ class GetConnect extends GetConnectInterface { @@ -178,6 +183,7 @@ class GetConnect extends GetConnectInterface {
178 contentType: contentType, 183 contentType: contentType,
179 query: query, 184 query: query,
180 decoder: decoder, 185 decoder: decoder,
  186 + uploadProgress: uploadProgress,
181 ); 187 );
182 } 188 }
183 189
1 import 'dart:async'; 1 import 'dart:async';
2 import 'dart:convert'; 2 import 'dart:convert';
3 -  
4 import 'package:flutter/foundation.dart'; 3 import 'package:flutter/foundation.dart';
5 4
6 import '../src/certificates/certificates.dart'; 5 import '../src/certificates/certificates.dart';
7 import '../src/exceptions/exceptions.dart'; 6 import '../src/exceptions/exceptions.dart';
8 -import '../src/http_impl/http_request_stub.dart'  
9 - if (dart.library.html) 'http_impl/http_request_html.dart'  
10 - if (dart.library.io) 'http_impl/http_request_io.dart';  
11 -import '../src/http_impl/request_base.dart';  
12 import '../src/multipart/form_data.dart'; 7 import '../src/multipart/form_data.dart';
13 import '../src/request/request.dart'; 8 import '../src/request/request.dart';
14 import '../src/response/response.dart'; 9 import '../src/response/response.dart';
15 import '../src/status/http_status.dart'; 10 import '../src/status/http_status.dart';
  11 +import 'http/interface/request_base.dart';
  12 +import 'http/stub/http_request_stub.dart'
  13 + if (dart.library.html) 'http/html/http_request_html.dart'
  14 + if (dart.library.io) 'http/io/http_request_io.dart';
16 import 'interceptors/get_modifiers.dart'; 15 import 'interceptors/get_modifiers.dart';
17 16
18 typedef Decoder<T> = T Function(dynamic data); 17 typedef Decoder<T> = T Function(dynamic data);
19 18
  19 +typedef Progress = Function(double percent);
  20 +
20 class GetHttpClient { 21 class GetHttpClient {
21 String userAgent; 22 String userAgent;
22 String baseUrl; 23 String baseUrl;
@@ -90,9 +91,10 @@ class GetHttpClient { @@ -90,9 +91,10 @@ class GetHttpClient {
90 String method, 91 String method,
91 Map<String, dynamic> query, 92 Map<String, dynamic> query,
92 Decoder<T> decoder, 93 Decoder<T> decoder,
  94 + Progress uploadProgress,
93 ) async { 95 ) async {
94 List<int> bodyBytes; 96 List<int> bodyBytes;
95 - BodyBytes bodyStream; 97 + BodyBytesStream bodyStream;
96 final headers = <String, String>{}; 98 final headers = <String, String>{};
97 99
98 headers['user-agent'] = userAgent; 100 headers['user-agent'] = userAgent;
@@ -125,11 +127,10 @@ class GetHttpClient { @@ -125,11 +127,10 @@ class GetHttpClient {
125 } 127 }
126 128
127 if (bodyBytes != null) { 129 if (bodyBytes != null) {
128 - bodyStream = BodyBytes.fromBytes(bodyBytes); 130 + bodyStream = _trackProgress(bodyBytes, uploadProgress);
129 } 131 }
130 132
131 final uri = _createUri(url, query); 133 final uri = _createUri(url, query);
132 -  
133 return Request<T>( 134 return Request<T>(
134 method: method, 135 method: method,
135 url: uri, 136 url: uri,
@@ -141,6 +142,27 @@ class GetHttpClient { @@ -141,6 +142,27 @@ class GetHttpClient {
141 ); 142 );
142 } 143 }
143 144
  145 + BodyBytesStream _trackProgress(
  146 + List<int> bodyBytes,
  147 + Progress uploadProgress,
  148 + ) {
  149 + var total = 0;
  150 + var length = bodyBytes.length;
  151 +
  152 + var byteStream =
  153 + Stream.fromIterable(bodyBytes.map((i) => [i])).transform<List<int>>(
  154 + StreamTransformer.fromHandlers(handleData: (data, sink) {
  155 + total += data.length;
  156 + if (uploadProgress != null) {
  157 + var percent = total / length * 100;
  158 + uploadProgress(percent);
  159 + }
  160 + sink.add(data);
  161 + }),
  162 + );
  163 + return BodyBytesStream(byteStream);
  164 + }
  165 +
144 void _setSimpleHeaders( 166 void _setSimpleHeaders(
145 Map<String, String> headers, 167 Map<String, String> headers,
146 String contentType, 168 String contentType,
@@ -187,6 +209,8 @@ class GetHttpClient { @@ -187,6 +209,8 @@ class GetHttpClient {
187 headers: response.headers, 209 headers: response.headers,
188 statusCode: response.statusCode, 210 statusCode: response.statusCode,
189 body: response.body, 211 body: response.body,
  212 + bodyBytes: response.bodyBytes,
  213 + bodyString: response.bodyString,
190 statusText: response.statusText, 214 statusText: response.statusText,
191 ); 215 );
192 } 216 }
@@ -232,6 +256,7 @@ class GetHttpClient { @@ -232,6 +256,7 @@ class GetHttpClient {
232 @required dynamic body, 256 @required dynamic body,
233 Map<String, dynamic> query, 257 Map<String, dynamic> query,
234 Decoder<T> decoder, 258 Decoder<T> decoder,
  259 + @required Progress uploadProgress,
235 }) { 260 }) {
236 return _requestWithBody<T>( 261 return _requestWithBody<T>(
237 url, 262 url,
@@ -240,6 +265,7 @@ class GetHttpClient { @@ -240,6 +265,7 @@ class GetHttpClient {
240 'post', 265 'post',
241 query, 266 query,
242 decoder ?? (defaultDecoder as Decoder<T>), 267 decoder ?? (defaultDecoder as Decoder<T>),
  268 + uploadProgress,
243 ); 269 );
244 } 270 }
245 271
@@ -250,6 +276,7 @@ class GetHttpClient { @@ -250,6 +276,7 @@ class GetHttpClient {
250 @required dynamic body, 276 @required dynamic body,
251 @required Map<String, dynamic> query, 277 @required Map<String, dynamic> query,
252 Decoder<T> decoder, 278 Decoder<T> decoder,
  279 + @required Progress uploadProgress,
253 }) { 280 }) {
254 return _requestWithBody<T>( 281 return _requestWithBody<T>(
255 url, 282 url,
@@ -258,6 +285,7 @@ class GetHttpClient { @@ -258,6 +285,7 @@ class GetHttpClient {
258 method, 285 method,
259 query, 286 query,
260 decoder ?? (defaultDecoder as Decoder<T>), 287 decoder ?? (defaultDecoder as Decoder<T>),
  288 + uploadProgress,
261 ); 289 );
262 } 290 }
263 291
@@ -267,6 +295,7 @@ class GetHttpClient { @@ -267,6 +295,7 @@ class GetHttpClient {
267 @required dynamic body, 295 @required dynamic body,
268 @required Map<String, dynamic> query, 296 @required Map<String, dynamic> query,
269 Decoder<T> decoder, 297 Decoder<T> decoder,
  298 + @required Progress uploadProgress,
270 }) { 299 }) {
271 return _requestWithBody<T>( 300 return _requestWithBody<T>(
272 url, 301 url,
@@ -275,6 +304,7 @@ class GetHttpClient { @@ -275,6 +304,7 @@ class GetHttpClient {
275 'put', 304 'put',
276 query, 305 query,
277 decoder ?? (defaultDecoder as Decoder<T>), 306 decoder ?? (defaultDecoder as Decoder<T>),
  307 + uploadProgress,
278 ); 308 );
279 } 309 }
280 310
@@ -303,6 +333,7 @@ class GetHttpClient { @@ -303,6 +333,7 @@ class GetHttpClient {
303 Map<String, String> headers, 333 Map<String, String> headers,
304 Map<String, dynamic> query, 334 Map<String, dynamic> query,
305 Decoder<T> decoder, 335 Decoder<T> decoder,
  336 + Progress uploadProgress,
306 // List<MultipartFile> files, 337 // List<MultipartFile> files,
307 }) async { 338 }) async {
308 try { 339 try {
@@ -313,7 +344,7 @@ class GetHttpClient { @@ -313,7 +344,7 @@ class GetHttpClient {
313 body: body, 344 body: body,
314 query: query, 345 query: query,
315 decoder: decoder, 346 decoder: decoder,
316 - // files: files, 347 + uploadProgress: uploadProgress,
317 ), 348 ),
318 headers: headers, 349 headers: headers,
319 ); 350 );
@@ -323,9 +354,6 @@ class GetHttpClient { @@ -323,9 +354,6 @@ class GetHttpClient {
323 throw GetHttpException(e.toString()); 354 throw GetHttpException(e.toString());
324 } 355 }
325 return Future.value(Response<T>( 356 return Future.value(Response<T>(
326 - request: null,  
327 - statusCode: null,  
328 - body: null,  
329 statusText: 'Can not connect to server. Reason: $e', 357 statusText: 'Can not connect to server. Reason: $e',
330 )); 358 ));
331 } 359 }
@@ -339,6 +367,7 @@ class GetHttpClient { @@ -339,6 +367,7 @@ class GetHttpClient {
339 Map<String, String> headers, 367 Map<String, String> headers,
340 Map<String, dynamic> query, 368 Map<String, dynamic> query,
341 Decoder<T> decoder, 369 Decoder<T> decoder,
  370 + Progress uploadProgress,
342 }) async { 371 }) async {
343 try { 372 try {
344 var response = await _performRequest<T>( 373 var response = await _performRequest<T>(
@@ -349,6 +378,7 @@ class GetHttpClient { @@ -349,6 +378,7 @@ class GetHttpClient {
349 query: query, 378 query: query,
350 body: body, 379 body: body,
351 decoder: decoder, 380 decoder: decoder,
  381 + uploadProgress: uploadProgress,
352 ), 382 ),
353 headers: headers, 383 headers: headers,
354 ); 384 );
@@ -358,9 +388,6 @@ class GetHttpClient { @@ -358,9 +388,6 @@ class GetHttpClient {
358 throw GetHttpException(e.toString()); 388 throw GetHttpException(e.toString());
359 } 389 }
360 return Future.value(Response<T>( 390 return Future.value(Response<T>(
361 - request: null,  
362 - statusCode: null,  
363 - body: null,  
364 statusText: 'Can not connect to server. Reason: $e', 391 statusText: 'Can not connect to server. Reason: $e',
365 )); 392 ));
366 } 393 }
@@ -373,6 +400,7 @@ class GetHttpClient { @@ -373,6 +400,7 @@ class GetHttpClient {
373 Map<String, String> headers, 400 Map<String, String> headers,
374 Map<String, dynamic> query, 401 Map<String, dynamic> query,
375 Decoder<T> decoder, 402 Decoder<T> decoder,
  403 + Progress uploadProgress,
376 }) async { 404 }) async {
377 try { 405 try {
378 var response = await _performRequest<T>( 406 var response = await _performRequest<T>(
@@ -382,6 +410,7 @@ class GetHttpClient { @@ -382,6 +410,7 @@ class GetHttpClient {
382 query: query, 410 query: query,
383 body: body, 411 body: body,
384 decoder: decoder, 412 decoder: decoder,
  413 + uploadProgress: uploadProgress,
385 ), 414 ),
386 headers: headers, 415 headers: headers,
387 ); 416 );
@@ -391,9 +420,6 @@ class GetHttpClient { @@ -391,9 +420,6 @@ class GetHttpClient {
391 throw GetHttpException(e.toString()); 420 throw GetHttpException(e.toString());
392 } 421 }
393 return Future.value(Response<T>( 422 return Future.value(Response<T>(
394 - request: null,  
395 - statusCode: null,  
396 - body: null,  
397 statusText: 'Can not connect to server. Reason: $e', 423 statusText: 'Can not connect to server. Reason: $e',
398 )); 424 ));
399 } 425 }
@@ -417,14 +443,72 @@ class GetHttpClient { @@ -417,14 +443,72 @@ class GetHttpClient {
417 throw GetHttpException(e.toString()); 443 throw GetHttpException(e.toString());
418 } 444 }
419 return Future.value(Response<T>( 445 return Future.value(Response<T>(
420 - request: null,  
421 - statusCode: null,  
422 - body: null,  
423 statusText: 'Can not connect to server. Reason: $e', 446 statusText: 'Can not connect to server. Reason: $e',
424 )); 447 ));
425 } 448 }
426 } 449 }
427 450
  451 + // Future<Response<T>> download<T>(
  452 + // String url,
  453 + // String path, {
  454 + // Map<String, String> headers,
  455 + // String contentType = 'application/octet-stream',
  456 + // Map<String, dynamic> query,
  457 + // }) async {
  458 + // try {
  459 + // var response = await _performRequest<T>(
  460 + // () => _get<T>(url, contentType, query, null),
  461 + // headers: headers,
  462 + // );
  463 + // response.bodyBytes.listen((value) {});
  464 + // return response;
  465 + // } on Exception catch (e) {
  466 + // if (!errorSafety) {
  467 + // throw GetHttpException(e.toString());
  468 + // }
  469 + // return Future.value(Response<T>(
  470 + // statusText: 'Can not connect to server. Reason: $e',
  471 + // ));
  472 + // }
  473 +
  474 + // int byteCount = 0;
  475 + // int totalBytes = httpResponse.contentLength;
  476 +
  477 + // Directory appDocDir = await getApplicationDocumentsDirectory();
  478 + // String appDocPath = appDocDir.path;
  479 +
  480 + // File file = File(path);
  481 +
  482 + // var raf = file.openSync(mode: FileMode.write);
  483 +
  484 + // Completer completer = Completer<String>();
  485 +
  486 + // httpResponse.listen(
  487 + // (data) {
  488 + // byteCount += data.length;
  489 +
  490 + // raf.writeFromSync(data);
  491 +
  492 + // if (onDownloadProgress != null) {
  493 + // onDownloadProgress(byteCount, totalBytes);
  494 + // }
  495 + // },
  496 + // onDone: () {
  497 + // raf.closeSync();
  498 +
  499 + // completer.complete(file.path);
  500 + // },
  501 + // onError: (e) {
  502 + // raf.closeSync();
  503 + // file.deleteSync();
  504 + // completer.completeError(e);
  505 + // },
  506 + // cancelOnError: true,
  507 + // );
  508 +
  509 + // return completer.future;
  510 + // }
  511 +
428 Future<Response<T>> delete<T>( 512 Future<Response<T>> delete<T>(
429 String url, { 513 String url, {
430 Map<String, String> headers, 514 Map<String, String> headers,
@@ -443,9 +527,6 @@ class GetHttpClient { @@ -443,9 +527,6 @@ class GetHttpClient {
443 throw GetHttpException(e.toString()); 527 throw GetHttpException(e.toString());
444 } 528 }
445 return Future.value(Response<T>( 529 return Future.value(Response<T>(
446 - request: null,  
447 - statusCode: null,  
448 - body: null,  
449 statusText: 'Can not connect to server. Reason: $e', 530 statusText: 'Can not connect to server. Reason: $e',
450 )); 531 ));
451 } 532 }
  1 +// import 'dart:html' as html;
  2 +
  3 +List<int> fileToBytes(dynamic data) {
  4 + if (data is List<int>) {
  5 + return data;
  6 + } else {
  7 + throw FormatException('File is not [File] or [String] or [List<int>]');
  8 + }
  9 +}
  10 +
  11 +// void writeOnFile(List<int> bytes) {
  12 +// var blob = html.Blob(["data"], 'text/plain', 'native');
  13 +// var anchorElement = html.AnchorElement(
  14 +// href: html.Url.createObjectUrlFromBlob(blob).toString(),
  15 +// )
  16 +// ..setAttribute("download", "data.txt")
  17 +// ..click();
  18 +// }
1 import 'dart:async'; 1 import 'dart:async';
2 import 'dart:html' as html; 2 import 'dart:html' as html;
3 import 'dart:typed_data'; 3 import 'dart:typed_data';
4 -import '../certificates/certificates.dart';  
5 -import '../exceptions/exceptions.dart';  
6 -import '../request/request.dart';  
7 -import '../response/response.dart';  
8 -import 'body_decoder.dart';  
9 -import 'request_base.dart'; 4 +
  5 +import '../../certificates/certificates.dart';
  6 +import '../../exceptions/exceptions.dart';
  7 +import '../../request/request.dart';
  8 +import '../../response/response.dart';
  9 +import '../interface/request_base.dart';
  10 +import '../utils/body_decoder.dart';
10 11
11 /// A `dart:html` implementation of `HttpRequestBase`. 12 /// A `dart:html` implementation of `HttpRequestBase`.
12 class HttpRequestImpl implements HttpRequestBase { 13 class HttpRequestImpl implements HttpRequestBase {
@@ -44,12 +45,24 @@ class HttpRequestImpl implements HttpRequestBase { @@ -44,12 +45,24 @@ class HttpRequestImpl implements HttpRequestBase {
44 var reader = html.FileReader(); 45 var reader = html.FileReader();
45 46
46 reader.onLoad.first.then((_) async { 47 reader.onLoad.first.then((_) async {
47 - var bodyBytes = BodyBytes.fromBytes(reader.result as Uint8List); 48 + var bodyBytes = BodyBytesStream.fromBytes(reader.result as Uint8List);
48 49
49 final stringBody = 50 final stringBody =
50 await bodyBytesToString(bodyBytes, xhr.responseHeaders); 51 await bodyBytesToString(bodyBytes, xhr.responseHeaders);
51 52
52 - final body = bodyDecoded<T>(request, stringBody); 53 + String contentType;
  54 +
  55 + if (xhr.responseHeaders.containsKey('content-type')) {
  56 + contentType = xhr.responseHeaders['content-type'];
  57 + } else {
  58 + contentType = 'application/json';
  59 + }
  60 + // xhr.responseHeaders.containsKey(key)
  61 + final body = bodyDecoded<T>(
  62 + request,
  63 + stringBody,
  64 + contentType,
  65 + );
53 66
54 final response = Response<T>( 67 final response = Response<T>(
55 bodyBytes: bodyBytes, 68 bodyBytes: bodyBytes,
@@ -58,6 +71,7 @@ class HttpRequestImpl implements HttpRequestBase { @@ -58,6 +71,7 @@ class HttpRequestImpl implements HttpRequestBase {
58 headers: xhr.responseHeaders, 71 headers: xhr.responseHeaders,
59 statusText: xhr.statusText, 72 statusText: xhr.statusText,
60 body: body, 73 body: body,
  74 + bodyString: stringBody,
61 ); 75 );
62 completer.complete(response); 76 completer.complete(response);
63 }); 77 });
1 -import '../request/request.dart';  
2 -import '../response/response.dart'; 1 +import '../../request/request.dart';
  2 +import '../../response/response.dart';
3 3
4 /// Abstract interface of [HttpRequestImpl]. 4 /// Abstract interface of [HttpRequestImpl].
5 abstract class HttpRequestBase { 5 abstract class HttpRequestBase {
  1 +import 'dart:io';
  2 +
  3 +List<int> fileToBytes(dynamic data) {
  4 + if (data is File) {
  5 + return data.readAsBytesSync();
  6 + } else if (data is String) {
  7 + if (File(data).existsSync()) {
  8 + return File(data).readAsBytesSync();
  9 + } else {
  10 + throw 'File [data] not exists';
  11 + }
  12 + } else if (data is List<int>) {
  13 + return data;
  14 + } else {
  15 + throw FormatException('File is not [File] or [String] or [List<int>]');
  16 + }
  17 +}
  18 +
  19 +void writeOnFile(List<int> bytes) {}
  1 +import 'dart:async';
1 import 'dart:io' as io; 2 import 'dart:io' as io;
2 3
3 -import '../certificates/certificates.dart';  
4 -import '../exceptions/exceptions.dart';  
5 -import '../request/request.dart';  
6 -import '../response/response.dart';  
7 -import 'body_decoder.dart';  
8 -import 'request_base.dart'; 4 +import '../../certificates/certificates.dart';
  5 +import '../../exceptions/exceptions.dart';
  6 +import '../../request/request.dart';
  7 +import '../../response/response.dart';
  8 +import '../interface/request_base.dart';
  9 +import '../utils/body_decoder.dart';
9 10
10 /// A `dart:io` implementation of `HttpRequestBase`. 11 /// A `dart:io` implementation of `HttpRequestBase`.
11 class HttpRequestImpl extends HttpRequestBase { 12 class HttpRequestImpl extends HttpRequestBase {
@@ -32,7 +33,7 @@ class HttpRequestImpl extends HttpRequestBase { @@ -32,7 +33,7 @@ class HttpRequestImpl extends HttpRequestBase {
32 @override 33 @override
33 Future<Response<T>> send<T>(Request<T> request) async { 34 Future<Response<T>> send<T>(Request<T> request) async {
34 var requestBody = await request.bodyBytes.toBytes(); 35 var requestBody = await request.bodyBytes.toBytes();
35 - var stream = BodyBytes.fromBytes(requestBody ?? const []); 36 + var stream = BodyBytesStream.fromBytes(requestBody ?? const []);
36 37
37 try { 38 try {
38 var ioRequest = (await _httpClient.openUrl(request.method, request.url)) 39 var ioRequest = (await _httpClient.openUrl(request.method, request.url))
@@ -42,6 +43,12 @@ class HttpRequestImpl extends HttpRequestBase { @@ -42,6 +43,12 @@ class HttpRequestImpl extends HttpRequestBase {
42 ..contentLength = requestBody.length ?? -1; 43 ..contentLength = requestBody.length ?? -1;
43 request.headers.forEach(ioRequest.headers.set); 44 request.headers.forEach(ioRequest.headers.set);
44 45
  46 + // var response = await stream.map((s) {
  47 + // received += s.length;
  48 + // print("${(received / total) * 100} %");
  49 + // return s;
  50 + // }).pipe(ioRequest) as io.HttpClientResponse;
  51 +
45 var response = await stream.pipe(ioRequest) as io.HttpClientResponse; 52 var response = await stream.pipe(ioRequest) as io.HttpClientResponse;
46 53
47 var headers = <String, String>{}; 54 var headers = <String, String>{};
@@ -49,10 +56,16 @@ class HttpRequestImpl extends HttpRequestBase { @@ -49,10 +56,16 @@ class HttpRequestImpl extends HttpRequestBase {
49 headers[key] = values.join(','); 56 headers[key] = values.join(',');
50 }); 57 });
51 58
52 - final bodyBytes = BodyBytes(response); 59 + final bodyBytes = BodyBytesStream(response);
53 final stringBody = await bodyBytesToString(bodyBytes, headers); 60 final stringBody = await bodyBytesToString(bodyBytes, headers);
54 61
55 - final body = bodyDecoded<T>(request, stringBody); 62 + // response.headers.contentType.mimeType == 'application/json'
  63 +
  64 + final body = bodyDecoded<T>(
  65 + request,
  66 + stringBody,
  67 + response.headers.contentType.mimeType,
  68 + );
56 69
57 return Response( 70 return Response(
58 headers: headers, 71 headers: headers,
@@ -61,6 +74,7 @@ class HttpRequestImpl extends HttpRequestBase { @@ -61,6 +74,7 @@ class HttpRequestImpl extends HttpRequestBase {
61 statusText: response.reasonPhrase, 74 statusText: response.reasonPhrase,
62 bodyBytes: bodyBytes, 75 bodyBytes: bodyBytes,
63 body: body, 76 body: body,
  77 + bodyString: stringBody,
64 ); 78 );
65 } on io.HttpException catch (error) { 79 } on io.HttpException catch (error) {
66 throw GetHttpException(error.message, error.uri); 80 throw GetHttpException(error.message, error.uri);
@@ -77,8 +91,8 @@ class HttpRequestImpl extends HttpRequestBase { @@ -77,8 +91,8 @@ class HttpRequestImpl extends HttpRequestBase {
77 } 91 }
78 } 92 }
79 93
80 -extension FileExt on io.FileSystemEntity {  
81 - String get fileName {  
82 - return this?.path?.split(io.Platform.pathSeparator)?.last;  
83 - }  
84 -} 94 +// extension FileExt on io.FileSystemEntity {
  95 +// String get fileName {
  96 +// return this?.path?.split(io.Platform.pathSeparator)?.last;
  97 +// }
  98 +// }
  1 +void writeOnFile(List<int> bytes) {}
  2 +
  3 +List<int> fileToBytes(dynamic data) {
  4 + throw UnimplementedError();
  5 +}
1 -import '../certificates/certificates.dart';  
2 -import '../request/request.dart';  
3 -import '../response/response.dart';  
4 -import 'request_base.dart'; 1 +import '../../certificates/certificates.dart';
  2 +import '../../request/request.dart';
  3 +import '../../response/response.dart';
  4 +import '../interface/request_base.dart';
5 5
6 class HttpRequestImpl extends HttpRequestBase { 6 class HttpRequestImpl extends HttpRequestBase {
7 HttpRequestImpl({ 7 HttpRequestImpl({
1 import 'dart:convert'; 1 import 'dart:convert';
2 2
3 -import '../../../../get_core/get_core.dart'; 3 +import '../../../../../get_core/get_core.dart';
4 4
5 -import '../request/request.dart'; 5 +import '../../request/request.dart';
6 6
7 -T bodyDecoded<T>(Request<T> request, String stringBody) { 7 +T bodyDecoded<T>(Request<T> request, String stringBody, String mimeType) {
8 T body; 8 T body;
9 var bodyToDecode; 9 var bodyToDecode;
  10 +
  11 + if (mimeType.contains('application/json')) {
10 try { 12 try {
11 bodyToDecode = jsonDecode(stringBody); 13 bodyToDecode = jsonDecode(stringBody);
12 } on FormatException catch (_) { 14 } on FormatException catch (_) {
13 - Get.log('Cannot decode body in json'); 15 + Get.log('Cannot decode server response to json');
14 bodyToDecode = stringBody; 16 bodyToDecode = stringBody;
15 } 17 }
  18 + }
16 19
17 try { 20 try {
18 if (request.decoder == null) { 21 if (request.decoder == null) {
@@ -89,7 +89,7 @@ class FormData { @@ -89,7 +89,7 @@ class FormData {
89 } 89 }
90 90
91 Future<List<int>> toBytes() { 91 Future<List<int>> toBytes() {
92 - return BodyBytes(_encode()).toBytes(); 92 + return BodyBytesStream(_encode()).toBytes();
93 } 93 }
94 94
95 Stream<List<int>> _encode() async* { 95 Stream<List<int>> _encode() async* {
1 import 'package:flutter/foundation.dart'; 1 import 'package:flutter/foundation.dart';
2 2
  3 +import '../http/stub/file_decoder_stub.dart'
  4 + if (dart.library.html) '../http/html/file_decoder_html.dart'
  5 + if (dart.library.io) '../http/io/file_decoder_io.dart';
  6 +
3 import '../request/request.dart'; 7 import '../request/request.dart';
4 8
5 class MultipartFile { 9 class MultipartFile {
6 MultipartFile( 10 MultipartFile(
7 - List<int> bytes, { 11 + dynamic data, {
8 @required this.filename, 12 @required this.filename,
9 this.contentType = 'application/octet-stream', 13 this.contentType = 'application/octet-stream',
10 - }) : length = bytes.length,  
11 - stream = BodyBytes.fromBytes(bytes); 14 + }) : _bytes = fileToBytes(data) {
  15 + _length = _bytes.length;
  16 + _stream = BodyBytesStream.fromBytes(_bytes);
  17 + }
  18 +
  19 + final List<int> _bytes;
12 20
13 final String contentType; 21 final String contentType;
14 22
15 /// This stream will emit the file content of File. 23 /// This stream will emit the file content of File.
16 - final BodyBytes stream; 24 + BodyBytesStream _stream;
  25 +
  26 + int _length;
  27 +
  28 + BodyBytesStream get stream => _stream;
17 29
18 - final int length; 30 + int get length => _length;
19 31
20 final String filename; 32 final String filename;
21 } 33 }
@@ -20,8 +20,8 @@ class Request<T> { @@ -20,8 +20,8 @@ class Request<T> {
20 /// ex: `GET`,`POST`,`PUT`,`DELETE` 20 /// ex: `GET`,`POST`,`PUT`,`DELETE`
21 final String method; 21 final String method;
22 22
23 - /// The BodyBytes of body from this [Request]  
24 - final BodyBytes bodyBytes; 23 + /// The BodyBytesStream of body from this [Request]
  24 + final BodyBytesStream bodyBytes;
25 25
26 /// When true, the client will follow redirects to resolves this [Request] 26 /// When true, the client will follow redirects to resolves this [Request]
27 final bool followRedirects; 27 final bool followRedirects;
@@ -49,7 +49,7 @@ class Request<T> { @@ -49,7 +49,7 @@ class Request<T> {
49 @required Uri url, 49 @required Uri url,
50 @required String method, 50 @required String method,
51 @required Map<String, String> headers, 51 @required Map<String, String> headers,
52 - BodyBytes bodyBytes, 52 + BodyBytesStream bodyBytes,
53 bool followRedirects = true, 53 bool followRedirects = true,
54 int maxRedirects = 4, 54 int maxRedirects = 4,
55 FormData files, 55 FormData files,
@@ -66,7 +66,7 @@ class Request<T> { @@ -66,7 +66,7 @@ class Request<T> {
66 return Request._( 66 return Request._(
67 url: url, 67 url: url,
68 method: method, 68 method: method,
69 - bodyBytes: bodyBytes ??= BodyBytes.fromBytes(const []), 69 + bodyBytes: bodyBytes ??= BodyBytesStream.fromBytes(const []),
70 headers: Map.from(headers ??= <String, String>{}), 70 headers: Map.from(headers ??= <String, String>{}),
71 followRedirects: followRedirects, 71 followRedirects: followRedirects,
72 maxRedirects: maxRedirects, 72 maxRedirects: maxRedirects,
@@ -77,11 +77,11 @@ class Request<T> { @@ -77,11 +77,11 @@ class Request<T> {
77 } 77 }
78 } 78 }
79 79
80 -class BodyBytes extends StreamView<List<int>> {  
81 - BodyBytes(Stream<List<int>> stream) : super(stream); 80 +class BodyBytesStream extends StreamView<List<int>> {
  81 + BodyBytesStream(Stream<List<int>> stream) : super(stream);
82 82
83 - factory BodyBytes.fromBytes(List<int> bytes) =>  
84 - BodyBytes(Stream.fromIterable([bytes])); 83 + factory BodyBytesStream.fromBytes(List<int> bytes) =>
  84 + BodyBytesStream(Stream.fromIterable([bytes]));
85 85
86 Future<Uint8List> toBytes() { 86 Future<Uint8List> toBytes() {
87 var completer = Completer<Uint8List>(); 87 var completer = Completer<Uint8List>();
1 import 'dart:collection'; 1 import 'dart:collection';
2 import 'dart:convert'; 2 import 'dart:convert';
3 -  
4 -import 'package:flutter/foundation.dart';  
5 -  
6 import '../request/request.dart'; 3 import '../request/request.dart';
7 import '../status/http_status.dart'; 4 import '../status/http_status.dart';
8 5
9 class Response<T> { 6 class Response<T> {
10 const Response({ 7 const Response({
11 - @required this.request,  
12 - @required this.statusCode,  
13 - // ignore: always_require_non_null_named_parameters 8 + this.request,
  9 + this.statusCode,
14 this.bodyBytes, 10 this.bodyBytes,
  11 + this.bodyString,
15 this.statusText = '', 12 this.statusText = '',
16 this.headers = const {}, 13 this.headers = const {},
17 - @required this.body, 14 + this.body,
18 }); 15 });
19 16
20 /// The Http [Request] linked with this [Response]. 17 /// The Http [Request] linked with this [Response].
@@ -46,7 +43,10 @@ class Response<T> { @@ -46,7 +43,10 @@ class Response<T> {
46 bool get unauthorized => status.isUnauthorized; 43 bool get unauthorized => status.isUnauthorized;
47 44
48 /// The response body as a Stream of Bytes. 45 /// The response body as a Stream of Bytes.
49 - final BodyBytes bodyBytes; 46 + final BodyBytesStream bodyBytes;
  47 +
  48 + /// The response body as a Stream of Bytes.
  49 + final String bodyString;
50 50
51 /// The decoded body of this [Response]. You can access the 51 /// The decoded body of this [Response]. You can access the
52 /// body parameters as Map 52 /// body parameters as Map
@@ -55,7 +55,7 @@ class Response<T> { @@ -55,7 +55,7 @@ class Response<T> {
55 } 55 }
56 56
57 Future<String> bodyBytesToString( 57 Future<String> bodyBytesToString(
58 - BodyBytes bodyBytes, Map<String, String> headers) { 58 + BodyBytesStream bodyBytes, Map<String, String> headers) {
59 return bodyBytes.bytesToString(_encodingForHeaders(headers)); 59 return bodyBytes.bytesToString(_encodingForHeaders(headers));
60 } 60 }
61 61
@@ -52,9 +52,9 @@ String validateField(String field) { @@ -52,9 +52,9 @@ String validateField(String field) {
52 return field.toLowerCase(); 52 return field.toLowerCase();
53 } 53 }
54 54
55 -BodyBytes toBodyBytes(Stream<List<int>> stream) {  
56 - if (stream is BodyBytes) return stream;  
57 - return BodyBytes(stream); 55 +BodyBytesStream toBodyBytesStream(Stream<List<int>> stream) {
  56 + if (stream is BodyBytesStream) return stream;
  57 + return BodyBytesStream(stream);
58 } 58 }
59 59
60 final _asciiOnly = RegExp(r'^[\x00-\x7F]+$'); 60 final _asciiOnly = RegExp(r'^[\x00-\x7F]+$');
1 name: get 1 name: get
2 description: Open screens/snackbars/dialogs/bottomSheets without context, manage states and inject dependencies easily with GetX. 2 description: Open screens/snackbars/dialogs/bottomSheets without context, manage states and inject dependencies easily with GetX.
3 -version: 3.21.3 3 +version: 3.22.0
4 homepage: https://github.com/jonataslaw/getx 4 homepage: https://github.com/jonataslaw/getx
5 5
6 environment: 6 environment: