Sending binary data from Qt to AngularJs over HTTP - c++

QString path = "my.file";
//QString zipcmd = QString("tar -czf %1.tar.gz %1").arg(path);
//int err = system(zipcmd.toUtf8().data());
// path += ".tar.gz";
QFile file(path);
if (!err && QFile::exists(path) && file.open(QIODevice::ReadOnly)) {
body = file.readAll();
file.close();
status = QHttpResponse::STATUS_ACCEPTED;
}
And there how I process response:
$http({ method: 'GET', url: 'myurl', respponseType: 'blob' })
.then(function success(response) {
var blob = new Blob([response.data],{type: 'application/octet-stream', charset: 'charset=utf-8'});
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.download = "myfilename";
a.href = url;
a.click();
});
When I send simple text file every thing is OK.
But when I try to send same file packed to tar.gz I receive incorrect data. I have tried to use toBase64 and atob, change respponseType to arraybuffer and MIME type without any success.
AngularJS 1.4.9 and Qt 5.4. Any help would be appreciated.
Maybe there is another way to transfer files?

Related

Flutter sending a post request to a Django API with a file as the body

I have a Django API where a user is able to upload a file through a post request with the following body:
{
"file": *attached file*
}
In Django, the file is gathered from the request with request.FILES['file']
The request has to be sent from flutter (dart) code. I have tried a few ways, this is the function from my latest attempt which shows an error - because the "file" is not in the correct format.
static void uploadProfilePhoto(File file, String fileId) async {
Uint8List fileBytes = file.readAsBytesSync();
var response = http.post(
globals.baseURL() + "/upload/",
//headers: {"Content-Type": "application/json"},
body: {
"file":base64Encode(fileBytes)
}
).then((v)=>print("v: "+v.body));
}
Any idea in what format the "file" should be sent from flutter? Else is there any other method which might work? Thank you in advance.
in flutter use
import 'dart:convert' as convert;
import 'dart:io';
import 'package:http/http.dart' as http;
#override
Future<Map<String, dynamic>> sendFiletodjango(
{File file,
}) async {
var endPoint = url;
Map data = {};
String base64file = base64Encode(file.readAsBytesSync());
String fileName = file.path.split("/").last;
data['name']=fileName;
data['file']= base64file;
try {
var response = await http.post(endPoint,headers: yourRequestHeaders, body:convert.json.encode(data));
} catch (e) {
throw (e.toString());
}
}
in python django use
from django.core.files.base import ContentFile
file = response.data.get("file")
name = response.data.get("name")
your_file = ContentFile(base64.b64decode(file),name)
model.fileField = your_file
model.save()
You can try multipart/form-data to upload files from Flutter to the Django server using HTTP post request.
From flutter, you can send multipart/form-data request in the below shown way.
Future<Response> uploadFile(File file) async {
Response response;
var uri = Uri.parse(url);
var request = http.MultipartRequest('POST', uri);
request.files.add(await http.MultipartFile.fromPath('file', file.path));
var response = await request.send();
if (response.statusCode == 200 || response.statusCode == 201) {
print('Uploaded!');
}
return response;
}
You can find more about it here Dart MultipartRequest.

Zip File downloaded from ReactJs/Axios is corrupted

I'm trying to download a zip file from a Django api and have the user download it. There are two .csv files in the zip.
I am able to download a single .csv files individually, but when I try to download the zip and unzip, I get errors that the zip is corrupted. For sanity check, I am able to send the request via Postman. I am able to successfully download and unzip the file using that.
Here is my code fragment:
axios
.post('http://0.0.0.0:8000/sheets/', data,
{
headers: {
'Content-Type': 'multipart/form-data',
'responseType': 'arraybuffer'
}
})
.then(res => {
console.log(res.data)
const disposition = res.request.getResponseHeader('Content-Disposition')
var fileName = "";
var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
var matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) {
fileName = matches[1].replace(/['"]/g, '');
}
let blob = new Blob([res.data], { type: 'application/zip' })
const downloadUrl = URL.createObjectURL(blob)
let a = document.createElement("a");
a.href = downloadUrl;
a.download = fileName;
document.body.appendChild(a);
a.click();
To add to btbam91's reply: responseType has to be part of the config. In the above example:
axios
.post('http://0.0.0.0:8000/sheets/', data,
{
responseType: 'arraybuffer',
headers: {
'Content-Type': 'multipart/form-data',
}
})
The problem was that 'responseType': 'arraybuffer' should not be in "headers."

Spring MVC File Upload with multipart data and unit test

I am using Spring 4 latest, and I generally have no problem writing RESTful controllers. There is a legacy web-app, which is using java.net.HTTPUrlConnection to do a multi-part upload. There are 3 pieces of data we are uploading:
1 is a PDF file, and we have the bytes, then the other two pieces of data are just 2 string fields.
First let me show you the Spring REST controller to accept the data:
#RequestMapping(value = "/save", method = RequestMethod.POST, produces = "application/json", consumes = "multipart/form-data")
public #ResponseBody boolean saveData(#RequestPart(value = "field1") String field1, #RequestPart(value = "field2") String field2, #RequestParam(value = "pdfbytes") String pdfbytes)
{
System.out.println("saveData: field1=" + field1);
System.out.println("saveData: field2=" + field2);
System.out.println("saveData: pdfbytes=" + pdfbytes);
boolean response = true;
return response;
}
The code in front-end, for sending the data using 'java.net.HttpURLConnection'
looks like this:
String boundary = MultiPartFormOutputStream.createBoundary();
URL uploadDocumentUrl = new URL(protocol + "://" + host + UPLOAD_EDITED_DOCUMENT);
HttpURLConnection urlConn = (HttpURLConnection) MultiPartFormOutputStream.createConnection(uploadDocumentUrl);
urlConn.setRequestProperty("Content-Type", MultiPartFormOutputStream.getContentType(boundary));
urlConn.setRequestProperty("Connection", "Keep-Alive");
urlConn.setRequestProperty("Cache-Control", "no-cache");
urlConn.setRequestProperty("User-Agent", userAgent);
urlConn.setRequestMethod("POST");
MultiPartFormOutputStream out = new MultiPartFormOutputStream(urlConn.getOutputStream(), boundary);
String pdfbytes= getEncodedDocument(pdf);
out.writeField("field1", field1);
out.writeField("field2", field2);
out.writeField("pdfbytes", pdfbytes);
out.close();
int responseCode = urlConn.getResponseCode();
String responseMessage = urlConn.getResponseMessage();
"MultiPartFormOutputStream" is a custom object that was created to send data via HttpUrlConnection, it's pretty standard code. I do trust it at this time.
So, based on how we are sending the data, do I need to change the Controller to do anything different, or does that look ok?
Now here is the code, that I am using to Unit Test that controller:
#Test
public void testMockUpload() throws Exception
{
// Load resource being uploaded
byte[] pdfbytes = getByteArrayFromFile(FILENAME);
MockMultipartFile firstFile = new MockMultipartFile("field1", "", "text/plain", "field1 data".getBytes());
MockMultipartFile secondFile = new MockMultipartFile("field2", "", "text/plain", "field2 data".getBytes());
MockMultipartFile jsonFile = new MockMultipartFile("pdfbytes", "", "text/plain", pdfbytes);
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.fileUpload(BASE_URL + "/save").file(firstFile).file(secondFile).file(jsonFile)
.with(user(USERNAME).roles("role1", "role2")).contentType(MediaType.MULTIPART_FORM_DATA_VALUE);
this.mockMvc.perform(requestBuilder).andDo(print()).andExpect(status().isOk());
}
And the error I get back now, is:
org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException
which I am looking into. If I need to make any changes on how I need to create my test, I am very open to that. Eventually, I will get everything to sync up between the sending code, the receiving controller, and the unit test.
Thanks in advance! As usual, if there is any other data, or information, I can provide, please let me know. Thanks!
To upload one file you would define the RequestParam type as org.springframework.web.multipart.MultipartFile;
#RequestMapping(value = "/save", method = RequestMethod.POST, produces = "application/json", consumes = "multipart/form-data")
public #ResponseBody boolean saveData(#RequestParam(value = "file") MultipartFile file)
{
return response;
}
For Multiple files I'd try creating a Wrapper form:
public class UploadForm{
private List<MultipartFile> files;
}
Bind to this in the controller:
#RequestMapping(value = "/save", method = RequestMethod.POST, produces = "application/json", consumes = "multipart/form-data")
public #ResponseBody boolean saveData(#ModelAttribute uploadForm)
{
return response;
}
and then use Spring's support for indexed fields to bind to a collection:
Test:
MockMultipartFile firstFile = new MockMultipartFile("files[0]", "", "text/plain", "field1 data".getBytes());
MockMultipartFile secondFile = new MockMultipartFile("files[1]", "", "text/plain", "field2 data".getBytes());
MockMultipartFile jsonFile = new MockMultipartFile("files[2]", "", "text/plain", pdfbytes);
Client:
out.writeField("files[0]", file1Bytes);
out.writeField("files[1]", file2Bytes);
...

Read content of SP.File object as text using JSOM

as the title suggests, I am trying to read the contents of a simple text file using JSOM. I am using a Sharepoint-hosted addin for this, the file I am trying to read resides on the host web in a document library.
Here's my JS code:
function printAllListNamesFromHostWeb() {
context = new SP.ClientContext(appweburl);
factory = new SP.ProxyWebRequestExecutorFactory(appweburl);
context.set_webRequestExecutorFactory(factory);
appContextSite = new SP.AppContextSite(context, hostweburl);
this.web = appContextSite.get_web();
documentslist = this.web.get_lists().getByTitle('Documents');
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml('<View><ViewFields><FieldRef Name="Name"/></ViewFields></View>');
listitems = documentslist.getItems(camlQuery);
context.load(listitems, 'Include(File,FileRef)');
context.executeQueryAsync(
Function.createDelegate(this, successHandler),
Function.createDelegate(this, errorHandler)
);
function successHandler() {
var enumerator = listitems.getEnumerator();
while (enumerator.moveNext()) {
var results = enumerator.get_current();
var file = results.get_file();
//Don't know how to get this to work...
var fr = new FileReader();
fr.readAsText(file.get);
}
}
function errorHandler(sender, args) {
console.log('Could not complete cross-domain call: ' + args.get_message());
}
}
However, in my succes callback function, I don't know how I can extract the contents of the SP.File object. I tried using the FileReader object from HTML5 API but I couldn't figure out how to convert the SP.File object to a blob.
Can anybody give me a push here?
Once file url is determined file content could be loaded from the server using a regular HTTP GET request (e.g. using jQuery.get() function)
Example
The example demonstrates how to retrieve the list of files in library and then download files content
loadItems("Documents",
function(items) {
var promises = $.map(items.get_data(),function(item){
return getFileContent(item.get_item('FileRef'));
});
$.when.apply($, promises)
.then(function(content) {
console.log("Done");
//print files content
$.each(arguments, function (idx, args) {
console.log(args[0])
});
},function(e) {
console.log("Failed");
});
},
function(sender,args){
console.log(args.get_message());
}
);
where
function loadItems(listTitle,success,error){
var ctx = SP.ClientContext.get_current();
var web = ctx.get_web();
var list = web.get_lists().getByTitle(listTitle);
var items = list.getItems(createAllFilesQuery());
ctx.load(items, 'Include(File,FileRef)');
ctx.executeQueryAsync(
function() {
success(items);
},
error);
}
function createAllFilesQuery(){
var qry = new SP.CamlQuery();
qry.set_viewXml('<View Scope="RecursiveAll"><Query><Where><Eq><FieldRef Name="FSObjType" /><Value Type="Integer">0</Value></Eq></Where></Query></View>');
return qry;
}
function getFileContent(fileUrl){
return $.ajax({
url: fileUrl,
type: "GET"
});
}

Upload an image to Drupal 7 / Services 3 from Titanium?

This must be close but I can't figure out what's causing the error.
In my Titanium app, I have a Webview with a canvas element and this code:
function getImageData() {
return canvas.toDataURL('image/png');
}
I am moving that data to the Titanium app like this:
var imageBase64data = webview.evalJS('getImageData()')
The data looks good starting with "data:image/png;base64,"...
Then in Titanium, I have a logged-in drupal session and call this function:
function uploadImage(imageBase64data, callback) {
var url = REST_PATH + "file.json";
var file = {
filename: utils.createRandomString() + ".png",
file: imageBase64data
// uid: Titanium.App.Properties.getString("userUid"),
// filesize: ""+Titanium.Utils.base64decode(imageBase64data).length,
};
var xhr = Titanium.Network.createHTTPClient({timeout: 30000});
xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
var authString = Titanium.App.Properties.getString("userSessionName")+'='+Titanium.App.Properties.getString("userSessionId");
xhr.setRequestHeader("Cookie", authString);
xhr.onload = function() {
if(xhr.status == 200) {
var response = xhr.responseText;
callback(response);
}
};
xhr.onerror = function(e) {
alert("There was an error: " + e.error);
Ti.API.info(JSON.stringify(this));
};
xhr.open("POST", url);
xhr.send(file);
}
xhr.onerror is being called with e.error = "undefined"
The trace looks like this:
{
"responseData":{},
"readyState":4,
"connected":true,"UNSENT":0,"DONE":4,"HEADERS_RECEIVED":2,"OPENED":1,"LOADING":3,
"responseText":null,"status":406
}
I think authentication is working because I was previously getting a "need authentication" error until I added the Cookie header.
That was with the installation provided by Drupanium. I just did a fresh Drupal and fresh Services 3 install and my file is uploading nicely.