Handshake Exception when trying to upload a file using MultipartRequest in flutter - flutter

I tried to upload a file to s3 using MultipartRequest in flutter but upon reach "response.send()" i get
I/flutter ( 8307): HandshakeException: Handshake error in client (OS Error:
I/flutter ( 8307): CERTIFICATE_VERIFY_FAILED: self signed certificate in certificate chain(handshake.cc:354))
I turned 'SSL Certificate Verification' off in Postman for it work, so is there any way to turn it off in flutter whilst uploading?
here is the code i used:
var request = http.MultipartRequest('POST', uri)
..fields['key'] = data.key
..fields['x-amz-algorithm'] = data.algorithm
..fields['x-amz-credential'] = data.credential
..fields['x-amz-date'] = data.date
..fields['x-amz-security-token'] = data.securityToken
..fields['policy'] = data.policy
..files.add(await http.MultipartFile.fromPath('File', imagePath, filename: imageName));
print(request.toString());
try {
var response = await request.send();
await for (var value in response.stream.transform(utf8.decoder)) {
print(value);
}
} catch (e) {
print(e.toString());
}

If anyone faces the same, I was able to fix the above issue using "Dio" package like so
Dio _client = Dio();
_client.interceptors.add(LogInterceptor());
FormData formData = FormData.fromMap({
'key': data.key,
'x-amz-algorithm': data.algorithm,
'x-amz-credential': data.credential,
'x-amz-date': data.date,
'x-amz-security-token': data.securityToken,
'policy': data.policy,
'x-amz-signature': data.signature,
'File': await MultipartFile.fromFile(
filePath,
filename: fileName,
)
});
(_client.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(HttpClient dioClient) {
dioClient.badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
return dio;
};
try {
await _client.post(
data.uploadUrl,
data: formData,
);
_client.close();
} catch (e) {
print(e.toString());
_client.close();
}

Related

Image not uploading in DIO 4 and above

Greeting everyone, my image is not uploading to my server when i update to DIO 4.0.0 and above. The same code works for DIO version below 4.0.0 . Below is the upload code. Kindly help me out. Thanks
Future<dynamic> upload(String url, BuildContext context,
{List<File> files,
Map body,
FileCount count = FileCount.MULTIPLE,
authorize = true}) async {
BaseOptions options = await getOptions(validate: authorize);
dynamic response, serverResponse;
List<MultipartFile> uploadFiles = [];
FormData requestData;
try {
Dio dio = new Dio(options)..interceptors.add(Logging());
(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(client) {
SecurityContext sc = new SecurityContext();
HttpClient httpClient = new HttpClient(context: sc);
//allow all cert
httpClient.badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
return httpClient;
};
// add files to uploadFiles array
if (files.length > 0) {
for (var index = 0; index < files.length; index++) {
MultipartFile file = MultipartFile.fromFileSync(files[index].path,
filename: basename(files[index].path),contentType:MediaType.parse('image/jpg'));
uploadFiles.add(file);
}
print("file the request: $uploadFiles");
requestData = FormData.fromMap({"file": uploadFiles});
} else {
requestData = FormData();
}
body.forEach((key, value) {
MapEntry<String, String> data = new MapEntry(key, '$value');
requestData.fields.add(data);
});
print("sending the request: ${uploadFiles.asMap().values}");
serverResponse = await dio.post(
url,
data: requestData,
options: new Options(contentType: 'multipart/form-data'),
onSendProgress: (int sent, int total) {
print('$sent $total');
},
);
print("Server Replied: $serverResponse}");
print(serverResponse.data);
//check for connection errors
if (serverResponse.statusCode < 200 || serverResponse.statusCode > 400) {
return _decoder.convert(
'{"success":false,"message":"${LocalText.of(context).load("error_executing_request")}"}');
}
response = _decoder.convert(serverResponse.data);
print("Response: $response");
} on DioError catch (e) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx and is also not 304.
if (e.response != null) {
print(e.response.data);
print(e.response.headers);
// print(e.response.request);
response = _decoder.convert(
'{"success":false,"message":"${LocalText.of(context).load("server_error")}"}');
} else {
// Something happened in setting up or sending the request that triggered an Error
print(e.message);
response =
_decoder.convert('{"success":false,"message":"' + e.message + '"}');
}
} catch (error) {
return _decoder.convert(
'{"success":false,"message":"${LocalText.of(context).load("error_executing_request")}"}');
}
return response;
}

CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate in MultipartFile

HandshakeException: Handshake error in client (OS Error:
CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:354))
getting HandshakeException while upload file and fields
const TestMode = true;
addAssets(Map formFields, List files) async {
Map resp = {
'Status' : false,
'Msg' : "Unable to add asset"
};
try {
Uri url = Uri.parse("$BaseUrl$AddAssetUrl");
http.MultipartRequest multi = http.MultipartRequest("POST", url);
formFields.forEach((key, val) {
multi.fields[key] = val;
});
for (var val in files) {
var myFile = await http.MultipartFile.fromPath('MediaFiles[]', val);
multi.files.add(
myFile,
);
}
http.StreamedResponse streamedResponse = await multi.send().then((response) async {
return response;
});
String body = await streamedResponse.stream.bytesToString();
if(streamedResponse.statusCode == 200 && isJSON(body)){
Map data = json.decode(body);
resp['Status'] = data['Status'];
resp['Msg'] = data['Msg'];
}
debugPrint(body);
} catch (e) {
if(TestMode) print(e.toString());
}
return resp;
}
Upload file using MultipartFile
TestMode is constant
http is alias of package:http/http.
Reference: Github
Just send your request via IOClient
example:
addAssets(Map formFields, List files) async {
Map resp = {
'Status' : false,
'Msg' : "Unable to add asset"
};
try {
Uri url = Uri.parse("$BaseUrl$AddAssetUrl");
http.MultipartRequest multi = http.MultipartRequest("POST", url);
formFields.forEach((key, val) {
multi.fields[key] = val;
});
for (var val in files) {
var myFile = await http.MultipartFile.fromPath('MediaFiles[]', val);
multi.files.add(
myFile,
);
}
HttpClient httpClient = HttpClient();
httpClient .badCertificateCallback = (X509Certificate cert,String host,int port) {
return getBaseUrl() == host;
};
http.StreamedResponse streamedResponse = await IOClient(
httpClient
).send(multi);
String body = await streamedResponse.stream.bytesToString();
if(streamedResponse.statusCode == 200 && isJSON(body)){
Map data = json.decode(body);
resp['Status'] = data['Status'];
resp['Msg'] = data['Msg'];
}
debugPrint(body);
} catch (e) {
if(TestMode) print(e.toString());
}
return resp;
}
String getBaseUrl(){
String url = 'https://hostname.com/api_dir/'; // Your api url
url = url.substring(url.indexOf('://')+3);
return url.substring(0,url.indexOf('/'));
}

flutter dio upload files [pdf/ docs]

I am trying to upload files using dio package in my flutter application. I am sending my files through formdata. Here is my implementation:
Future<FormData> formData1() async {
return FormData.fromMap({
"title": "from app2",
"description": "app upload test",
"files": [
for (var i = 0; i < pathNames.length; i++)
await MultipartFile.fromFile(pathNames[i],
filename: fileNames[i])
]
});
}
Here is how I am sending my files.
_sendToServer() async {
Dio dio = Dio(
BaseOptions(
contentType: 'multipart/form-data',
headers: {
"Authorization": "$token",
},
),
);
dio.interceptors.add(
LogInterceptor(requestBody: true, request: true, responseBody: true));
FormData formData = await formData1();
try {
var response = await dio.post("http://url/api/upload",
data: formData, onSendProgress: (int send, int total) {
print((send / total) * 100);
});
print(response);
} on DioError catch (e) {
if (e.response != null) {
print(e.response.data);
print(e.response.headers);
print(e.response.request);
} else {
print(e.request.headers);
print(e.message);
}
}
}
The other fields in formdata are sent to the server but not the multipartfile. When I try and do the same from postman form-data, it uploads correctly. Am I doing something wrong here?
If you want to upload the file you can convert multipart array before calling API function because even if you put await in form data dio response will not wait for formdata object or you can use MultipartFile.fromFileSync() to get rid of await.
Let me show you in a simple way using my example. try to understand.
Multipart conversion
List multipartArray = [];
for (var i = 0; i < pathNames.length; i++){
multipartArray.add(MultipartFile.fromFileSync(pathNames[i], filename:
basename(pathNames[i])));
}
Api side
static Future<Response> createPostApi(multipartArray) async {
var uri = Uri.parse('http://your_base_url/post');
return await Dio()
.post('$uri',
data: FormData.fromMap({
"title": "from app2",
"description": "app upload test",
"files": multipartArray
}))
.catchError((e) {
print(e.response.data);
print(e.response.headers);
print(e.response.request);
});
}
Here is my code where I used file_picker flutter library and MediaType('application', 'pdf') to ensure that the content passed to the API was indeed a .pdf file.
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:http_parser/http_parser.dart';
static Future<dynamic> uploadfile(int userid, File file, String token) async {
var fileName = file.path.split('/').last;
print(fileName);
var formData = FormData.fromMap({
'title': 'Upload Dokumen',
'uploaded_file': await MultipartFile.fromFile(file.path,
filename: fileName, contentType: MediaType('application', 'pdf')),
"type": "application/pdf"
});
var response = await Dio().post('${urlapi}request/',
options: Options(
contentType: 'multipart/form-data',
headers: {HttpHeaders.authorizationHeader: 'Token $token'}),
data: formData);
print(response);
return response;
}
The file picker:
FilePickerResult? result = await FilePicker.platform.pickFiles();
if (result != null) {
File file = File(result.files.single.path ??'file.pdf');
BlocProvider.of<UploadCubit>(context)
.uploadFile(statelogin.user.id, file,
statelogin.user.token);
}
Change formdata with following rest is fine
import 'package:path/path.dart' as pathManager;
import 'package:mime/mime.dart' as mimeManager;
FormData formdata = FormData();
formdata.add(
"files",
[UploadFileInfo(img, pathManager.basename(img.path),
contentType:
ContentType.parse(mimeManager.lookupMimeType(img.path)))]);
// here attachmentFile is File instance, which is set by File Picker
Map<String, dynamic> _documentFormData = {};
if (attachmentFile != null) {
_documentFormData['document_file'] = MultipartFile.fromFileSync(attachmentFile.path);
}
FormData formData = FormData.fromMap(_documentFormData);
try {
var response = await dio.post("http://url/api/upload",
data: formData, onSendProgress: (int send, int total) {
print((send / total) * 100);
});
print(response);
} on DioError catch (e) {
if (e.response != null) {
print(e.response.data);
print(e.response.headers);
print(e.response.request);
} else {
print(e.request.headers);
print(e.message);
}
}
Here you can use MultipartRequest class without using any of library to upload any kind of files using restAPI.
void uploadFile(File file) async {
// string to uri
var uri = Uri.parse("enter here upload URL");
// create multipart request
var request = new http.MultipartRequest("POST", uri);
// if you need more parameters to parse, add those like this. i added "user_id". here this "user_id" is a key of the API request
request.fields["user_id"] = "text";
// multipart that takes file.. here this "idDocumentOne_1" is a key of the API request
MultipartFile multipartFile = await http.MultipartFile.fromPath(
'idDocumentOne_1',
file.path
);
// add file to multipart
request.files.add(multipartFile);
// send request to upload file
await request.send().then((response) async {
// listen for response
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}).catchError((e) {
print(e);
});
}
I used file picker to pick file. Here is the codes for pick file.
Future getPdfAndUpload(int position) async {
File file = await FilePicker.getFile(
type: FileType.custom,
allowedExtensions: ['pdf','docx'],
);
if(file != null) {
setState(() {
file1 = file; //file1 is a global variable which i created
});
}
}
here file_picker flutter library.

Why Dio with Flutter does not post file with values using json header

I am new to Flutter
I am trying to pass data in json format and file on same request using dio framework. code I'm using is below, anything wrong I'm doing?
return FormData.fromMap({
'value1' : value.value1(),
'value2' : value.value2(),
"attachments": [
await MultipartFile.fromFile(fileImage.path,
filename: "storeName.jpeg")
]
});
}
static Future<bool> createStore(File fileImage, StoreDetails store) async{
bool isDone = false;
var dio = Dio();
dio.options.baseUrl = UrlHelper.BASE_CORE_URL;
dio.options.headers['Authorization'] = 'Bearer '+ token;
dio.options.headers['Content-Type'] = 'application/json';
Response response;
try{
response = await dio.post(
'Url',
data: await formData(fileImage, values),
onSendProgress: (received, total) {
if (total != -1) {
print((received / total * 100).toStringAsFixed(0) + "%");
}
},
);
print(response.data);
return true;
}catch(e){
print(e.toString());
return true;
}
}
How I post data on postman
And I get this error DioError [DioErrorType.RESPONSE]: Http status error [415]
I am able to post image and json object from postman successfully.

I am not able to upload images and form data to rest api using DIO package in flutter

I am not able to upload image to rest api in flutter I have checked the api its working fine.
I am not able to convert the file (image) to a uploadable form, can any one help me with that?
I have run flutter doctor -v everything is fine :)
Here is the code I am using to post form data:
Future<void> uploadAccountDetails(AccountDetailsModel details) async {
var url = baseUrl + '/api/uploads/images';
try {
Dio dio = new Dio();
FormData formData = new FormData.fromMap(
{
'city': details.cityName,
'country': details.countryName,
'residence_address': details.address,
'dob': details.dob,
'id_num': details.id,
'passport_num': details.passportNo,
'driving_license_nim': details.drivingLicNo,
'user_id': 162,
'postal_code': details.postalCode,
'id_pic': await MultipartFile.fromFile(details.idPic.path,
filename: basename(details.idPic.path)),
'driving_license_pic':
await MultipartFile.fromFile(details.drivingLicPic.path,
filename: basename(
details.drivingLicPic.path,
)),
'birth_certificate': await MultipartFile.fromFile(
details.drivingLicPic.path,
filename: basename(details.birthCertPic.path),
),
'residence_permit_pic': await MultipartFile.fromFile(
details.resPermitPic.path,
filename: basename(details.resPermitPic.path),
),
'profile_pic': await MultipartFile.fromFile(details.profilePic.path,
filename: basename(details.profilePic.path)),
},
);
print(formData);
Response response = await dio.post(
url,
data: formData,
onSendProgress: (received, total) {
if (total != -1) {
print((received / total * 100).toStringAsFixed(0) + "%");
}
},
);
print(response.statusCode);
// print(response);
} catch (e) {
print(e);
throw (e);
}
}
The logs of error are as follows:
I/flutter (22523): DioError [DioErrorType.RESPONSE]: Http status error
[500] I/flutter (22523): DioError [DioErrorType.RESPONSE]: Http status
error [500]
The status error is:
I/flutter (22523): DioError [DioErrorType.RESPONSE]: Http status error
[500]
I searched this error but didnt find any solution, can anyone help me with that?
I used dio for post a file path with some other information in this way:
Dio dio = new Dio();
FormData formData = new FormData();
formData.add(
"apiKey",
"my_api_key",
);
formData.add(
"file",
"image_path",
);
Response response = await dio.post(
"https://localhost",
data: formData,
onSendProgress: (int sent, int total) {
// do something
},
).catchError((onError) {
throw Exception('something');
});