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?
Related
I am trying to send a signature from flutter to a GCP Storage bucket.
Currently, I can send a file to the bucket but it's not openable.
Here is what I am using to get base64 format which I supposed is the intended format to send files.
final data = await _signaturePadKey.currentState!
.toImage(pixelRatio: 3.0);
final image = await data.toByteData(
format: ui.ImageByteFormat.png);
// To send
final base64String =
base64.encode(image!.buffer.asUint8List());
setState(() => {_signatureFile = base64String});
Then I am sending my request as :
Future postOKTrackingSignature(String signature, String projectID) async {
await refreshSTSToken(projectID);
String token = await getSTSToken();
// Headers
var headersData = {
"Authorization": "Bearer $token",
"Content-Type": "image/png"
};
// URL building
var resourcePart =
"XXX";
var paramsData = {
'uploadType': 'multipart',
'name': "${resourcePart}signature.png",
};
var baseURI = 'https://storage.googleapis.com/upload/storage/v1/b/';
String bucketName = "XXX";
var query = paramsData.entries.map((p) => '${p.key}=${p.value}').join('&');
// Body
var bodyData = signature;
final response = await http.post(
Uri.parse("$baseURI$bucketName/o?$resourcePart$query"),
headers: headersData,
body: bodyData);
switch (response.statusCode) {
case 200:
print("$baseURI$bucketName/o?$resourcePart$query");
return {"statusCode": response.statusCode};
default:
print("$baseURI$bucketName/o?$resourcePart$query");
return {"statusCode": response.statusCode, "error": response.body};
}
}
Sadly, I the file got upload but is not usable when I want to get preview, or even download it and try to open it. But while I change the extension to .txt, take the string to : https://base64.guru/converter/decode/file it show me my image a png.
I also tried this :
var dataPrepation = base64.normalize(signature);
var bodyData = "data:image/png;base64,$dataPrepation";
String example :
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
Consider Firebase Storage instead of base64; this stackoverflow topic compares the two and outlines the benefits of each.
In light of this, I strongly advise you to continue working on your project utilizing Firebase Storage.
Now, to Upload a file to Cloud Storage, you first create a reference to the full path of the file, including the file name.
// Create a storage reference from our app
final storageRef = FirebaseStorage.instance.ref();
// Create a reference to "mountains.jpg"
final mountainsRef = storageRef.child("mountains.jpg");
// Create a reference to 'images/mountains.jpg'
final mountainImagesRef = storageRef.child("images/mountains.jpg");
// While the file names are the same, the references point to different files
assert(mountainsRef.name == mountainImagesRef.name);
assert(mountainsRef.fullPath != mountainImagesRef.fullPath);
Additionally, I would suggest you review the guide for Firebase Cloud Storage in Flutter written by Dane Mackier.
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);
I have a ByteStream downloaded from a Server, namely datas regarding the user.
Its in MySql server as
"username":"Neor","totalCoins":"350"
The truncated part of .php file that gives-away this data, is as follows:
$data = $stmt->fetchColumn();
header($_SERVER["SERVER_PROTOCOL"] . " 200 OK");
header("Cache-Control: public");
header("Content-Type: application/octet-stream");
header("Content-Transfer-Encoding: Binary");
header("Content-Length:".strlen($data));
echo $data;
I use ths Flutter code to download the data:
Future<void> downloadData() async {
var url = Uri.parse("https://example.com/mycloud.php");
var request = http.MultipartRequest('POST', url)
..fields["user"] = "Dia";
var response = await request.send();
var stream = response.stream; }
On checking if the downloaded ByteStream contains anything, I've used print(stream.length), which prints out as 137.
How can I get the information I want from the ByteStream?
(If my question lacks in any way, please let me know.)
There shouldn't be any need to use a multipart request for a simple POST. Instead use the simpler http.post method.
Future<void> downloadData() async {
final response = await http.post(
Uri.parse('https://example.com/mycloud.php'),
body: <String, String>{
'user': 'Dia',
},
);
final decodedJson = json.decode(response.body);
// if you want to ensure the character set used, replace this with:
// json.decode(utf8.decode(response.bodyBytes));
}
If you do stick with the stream way, you have a Stream<List<int>> that you want to turn initially into a List<int>. Use the toList() method on stream for that. Then you have to decode that into characters. JSON is always encoded in utf8, so you could:
json.decode(utf8.decode(await stream.toList()));
(Under the hood, http is basically doing that for you; collecting the stream together and doing the character decoding and presenting that as body.)
First
import 'dart:convert' show utf8;
String foo = utf8.decode(bytes);
Then
Map valueMap = json.decode(foo );
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.
I am trying to send an image from Flutter application to Cloudinary using Uploading with a direct call to the REST API,but getting this error:
{"error":{"message":"Invalid file parameter. Make sure your file parameter does not include '[]'"}}
I tried to encode image as an array of bytes, base64Encode but none of that worked, I followed this documentation.
Does anybody know how to encode the file so I can send it?
thanks
EDIT:
#override
Future<void> getImageSignature(File image) async {
return await _callWithExceptionWrap(() async {
if (image != null) {
DateTime dateTime = DateTime.now();
String url = _formatUrlForUploadSignature();
Dio dio = NetworkUtils.createDioConnection();
debugPrint('REQUEST TO SERVER');
Response serverResponse = await dio.post(url, data: {
"paramsToSign": {
'public_id': 'public_id_654',
"timestamp": dateTime.millisecondsSinceEpoch,
"upload_preset": "signed_preset",
"source": "uw",
}
});
debugPrint('REQUEST TO CLOUDINARY');
String signature = serverResponse.data['signature'];
List<int> bytes = image.readAsBytesSync();
var base64Image = base64Encode(bytes);
Map<String, dynamic> map = {
'api_key': _CLOUDINARY_API_KEY,
'public_id': 'public_id_654',
'signature': signature,
'source': 'uw',
'timestamp': dateTime.millisecondsSinceEpoch,
'upload_preset': 'signed_preset',
'file': base64Image,
};
debugPrint('json : ${map}');
// FormData formData = new FormData.fromMap(map);
Response cloudinaryResponse = await dio.post(_CLOUDINARY_URL, data: map);
debugPrint('*************************** Cloudinary response : ${cloudinaryResponse.data}');
}
});
The signature is ok, since I am not getting 401 error(signature I am receiving from the server.
here is the cloudinary url:
_CLOUDINARY_URL = 'https://api.cloudinary.com/v1_1//image/upload';
That is not correct api to use on a public client (Mobile app), you shouldn't be exposing your API_KEY and API_SECRET. Check out this package instead, which uses the correct api to upload files https://pub.dev/packages/cloudinary_public
The package Olajide suggested would only work for Unsigned uploads. For anyone that wants to use Signed uploads use this package https://pub.dev/packages/cloudinary_sdk