Line after await http response in Flutter app does not execute - flutter

I want to fetch a result from Flask API after sending http.MultipartFile request to server.
like this:
Future<String> upload(List<int> filename, String url) async {
//filename : binary conversion of string
//String url : api address
print("Inside Upload future!");
var request = http.MultipartRequest('POST', Uri.parse(url));
request.files.add(
http.MultipartFile.fromBytes('file', filename, filename: 'files.txt'));
print("Sending Request!");
http.Response response = await http.Response.fromStream(await request.send());
print("request sent! now returning");
var rtr = response.body;
return rtr;
}
But the problem is it does not return, and output after execution is The print after await is not executed why??:
Inside Upload future!
Sending Request!
I am sending a String to Flask API like:
It works correctly, it is receiving a string and then replying with the same string with some modifications.
#app.route('/test_api', methods=['GET', 'POST'])
def test_api():
uploaded_file = request.files['file']
file_content = uploaded_file.read().splitlines()
uploaded_file.seek(0)
file_pretty = uploaded_file.read()
a = runkey(file_pretty)
//takes string agrument and returns manipulated string
uploaded_file.seek(0)
filename = secure_filename(uploaded_file.filename)
resp = make_response(a)
resp.headers['Content-Type'] = 'text/plain;charset=UTF-8'
n = filename
resp.headers['Content-Disposition'] = 'attachment;filename='+'n'
return resp ```

I Solved this, By Adding
resp.headers['Access-Control-Allow-Origin'] = '*'
//before returning response to client
to the FlaskAPI response.
actually, I thought there's an error in Dart somewhere. But it was hiding in Chrome debugging, Since I am using Flutter Web.
The error is of Cross-Origin not allowed due to access control.

Related

Flutter S3 download using presigned URL issue

I am attempting to use presigned urls to download files on s3 to my flutter app. I have a lambda function that generates and passes the url. The presigned url works fine by itself but once it gets into flutter the data is somehow changed and AWS comes back with 404 error. It seems that somehow the token is corrupted.
If have tried parsing the data returned as XML, JSON and with no parsing what so ever. I have also changed the output from the lambda to be JSON or just send the url directly, neither solved the issue. None of these approaches have worked. Do I have to extract XML or something?
Here's the code that gets the url from a lambda call:
http.Response res1 = await http.get(url2);
dynamic data1 = cnv.jsonDecode(res1.body); //XmlDocument.parse(res1.body);
if (data1['theStatus'] == "error") {
String theStatus2 = "error";
return theStatus2;
} else {
(data1['theUrl']);
writeData(77, data1['theUrl']); //save in Hive
return data1;
}
Here's the code that uses the presigned url:
tFuture<File?> downloadFile(String url, String name) async {
final appStorage = await getApplicationDocumentsDirectory();
final file = File('${appStorage.path}/$name');
final response = await Dio().get(
url,
options: Options(
responseType: ResponseType.bytes,
followRedirects: false,
receiveTimeout: 0,
),
);
final raf = file.openSync(mode: FileMode.write);
raf.writeFromSync(response.data);
print('file saved');
await raf.close();
return file;
}
http.Response res1 = await http.get(url2);
final data1 = cnv.jsonDecode(res1.body); //XmlDocument.parse(res1.body);
if (data1['theStatus'] == "error") {
String theStatus2 = "error";
return theStatus2;
} else {
String theUrl = data1['theUrl'];
writeData(77, data1['theUrl']); //save in Hive
return theUrl;
}
If I hard code theUrl above with a presigned url from the browser accessing the lambda everything works fine...
I believe the issue is something to do with XML but when I use XML parse it throws an error no root... Any help appreciated.
Found the issue... my lambda function did not have the correct credentials. I found the solution using this:
How I can generated pre-signed url for different file versions of AWS S3 objects in NodeJS?

Flutter api calls oauth_signature HMAC-SHA1 generation

I am trying to make an API call to my server everything works properly on postman but I can't seem to get it going on Flutter
String oauthConsumer ='oauth_consumer_key=[MyKey]';
String oauthNonce =
'oauth_nonce=${Random().nextInt(4294967296).toString()}';
String oauthCallback =
'oauth_callback=[MyCallback address]';
String oauthVersion = 'oauth_version=1.0';
String oauthTime =
'oauth_timestamp=${(DateTime.now().millisecondsSinceEpoch ~/ 1000).toString()}';
String oauthMethod = 'oauth_signature_method=HMAC-SHA1';
var oauthList = [
oauthCallback,
oauthConsumer,
oauthNonce,
oauthMethod,
oauthTime,
oauthVersion
];
oauthList.sort();
String oauthSig = //[I need a method to create this properly]
var request = http.Request('POST', Uri.parse([My URL]));
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
print(await response.stream.bytesToString());
}
Like I mention postman does return the token and the token secret but trying on Flutter returns the Authentication Required error
Picture of the Postman request body
On the Authorization tab just filled in the Consumer Key and the Consumer Secret the headers where left untouched and default like this:

Convert raw http POST to data, write to file in Flutter

I'm running a web server instance in my Flutter app in order to run an image conversion tool, written in JavaScript. The JS code sends a POST command along with a body which contains the raw image data.
Using httpServer and VirtualDirectory, I'm serving all of the required files if JS calls GET, and now when it calls the POST command, I need to convert the POST request to raw data and save it to a file, as it contains the image data I need.
The current web server logic is written in Python. It uses rfile.read in order to write the data from the request into a file.
contentLength = int(self.headers['Content-Length'])
open("output_files/output.%03d.jpg"%frame,"wb").write(self.rfile.read(contentLength))
This is what I'm trying to recreate in Flutter. Here's my code so far.
_startServer({required String basePath}) async {
var server = await HttpServer.bind(InternetAddress.loopbackIPv4, 8080);
virDir = VirtualDirectory('$tempDir/converter/')
..allowDirectoryListing = true;
debugPrint(
"Server running on IP : ${server.address} On Port : ${server.port}");
await for (var request in server) {
switch (request.method) {
case 'GET':
String path = request.uri.toString();
if (!path.contains(basePath)) {
path = basePath + request.uri.toString();
}
debugPrint('request uri: $path');
final File file = File(path);
if (await file.exists()) {
request.response.statusCode = HttpStatus.ok;
virDir?.serveFile(file, request);
} else {
debugPrint('Could not find: $file');
request.response.statusCode = HttpStatus.notFound;
}
break;
case 'POST':
debugPrint('Content Length: ${request.headers.contentLength}');
debugPrint('Content Type: ${request.headers.contentType}');
final File image =
File('$basePath/videos/frame.${intFixed(frame, 3)}.jpg');
if (!image.existsSync()) {
request.response.statusCode = HttpStatus.ok;
request.response.write('Finished');
request.response.headers.contentType = ContentType.text;
request.response.headers.contentLength = 'Finished'.length;
await request.response.close();
return;
}
final File newImage =
File('$basePath/output_files/output.${intFixed(frame, 3)}.jpg');
ByteData data = ByteData(request.headers.contentLength);
final buffer = data.buffer;
await newImage.writeAsBytes(
buffer.asUint8List(0, request.headers.contentLength));
frame++;
debugPrint('$frame');
request.response.statusCode = HttpStatus.ok;
request.response.headers.contentType = ContentType.text;
request.response.headers.contentLength = "Success".length;
request.response.write("Success");
await request.response.close();
}
}
}
Specifically, this part:
ByteData data = ByteData(request.headers.contentLength);
final buffer = data.buffer;
await newImage.writeAsBytes(
buffer.asUint8List(0, request.headers.contentLength));
When I set a breakpoint and check data, there's no data per-se. Just a list of zeros.
How do I convert the POST request to raw in order to save it to a file? The content length and the content type is correct (image/jpeg), but getting it to data is really stumping me.
After a lot of trial and error, the solution is to use await request.single which outputs a Uint8List, then write that to file as it's a stream of the HTTPRequest object itself.
https://api.flutter.dev/flutter/dart-async/Stream/single.html
final data = await request.single;
final file = File('$basePath/output_files/output.${intFixed(frame, 3)}.jpg');
file.writeAsBytesSync(data);

How to get query params in a server request in flutter?

In order to authenticate with Imgur on a mobile app, I decided to spawn an http server on port 8585 in order to complete the oauth flow. The request is read and a response is written, but I cannot access the queryparameters from the url.
I already tried using uri.queryparameters["access_token"], but null is returned.
the server is spawned as follows:
Future<Stream<String>> _server() async {
final StreamController<String> onCode = new StreamController();
HttpServer server =
await HttpServer.bind(InternetAddress.loopbackIPv4, 8585);
server.listen((HttpRequest request) async {
print(request.uri.hashCode);
final String accessToken = request.uri.queryParameters["access_token"];
request.response
..statusCode = 200
..headers.set("Content-Type", ContentType.html.mimeType)
..write("<html><h1>You can now close this window</h1></html>");
await request.response.close();
await server.close(force: true);
onCode.add(accessToken);
await onCode.close();
});
return onCode.stream;
}
the url the server gets is of the sort: http://localhost:8585/callback#access_token=your_token_here&expires_in=315360000&token_type=bearer&refresh_token=_your_refresh_token_here
Can anyone help me? I've been stuck on this for two whole days!
It returns null because query parameters start with ? at the beginning but in this link, there is a # before the query parameters and replacing it with a ? does solve the problem.
solution 1:
var uri =Uri.parse('http://localhost:8585/callback#access_token=your_token_here&expires_in=315360000&token_type=bearer&refresh_token=_your_refresh_token_here');
var newUri = Uri(query: uri.toString().substring(uri.toString().indexOf('#')+1));
print(newUri.queryParameters['access_token']) // your_token_here;
solution 2:
var uri =Uri.parse('http://localhost:8585/callback#access_token=your_token_here&expires_in=315360000&token_type=bearer&refresh_token=_your_refresh_token_here');
var newUri = Uri.parse(uri.toString().replaceFirst('#', '?'));
print(newUri.queryParameters['access_token']) // your_token_here;

How send data to php file With Post

I am new in flutter and I want to send data(id in my program) to a php file and get it with $_POST ,and then send the result back but the Solution's that i have found didn't work .
I think my body is wrong , I tried to change body to a
Map<String,dynamic>
but its didn't work.
Future<List<dynamic>> getData() async {
String body = "{'id' : 1}" ;
String url = "http://10.0.2.2:8080/facts/get.php";
http.Response responseData = await http.post(
url
,body: body);
print(responseData.body);
return json.decode(responseData.body);
}