Django rest +vue.js excel file download corrupted - django

Hi Have problem with downloading excel file from serve by url. The file is corrupted etc..
below is my download function vue
downloadFile() {
axios({
url: this.scenario.file,
method: 'GET',
headers: {'Accept': 'application/vnd.ms-excel'},
responseType: "arraybuffer"
}).then(response => {
const url = window.URL.createObjectURL(
new Blob([response.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'})
);
const link = document.createElement("a");
link.href = url;
link.setAttribute('download', `file.xlsx`);
this.myresponseObject = response; // this line is just to save - url= window.URL.createObjectURL
this.blobUrl=url; // this line is just to save response object fro checking
document.body.appendChild(link);
link.click();
window.URL.revokeObjectURL(url);
link.remove();
});
},
in this code the url of the file which stored in the object scenario is -
this.scenario.file = "http://127.0.0.1:8000/media/datafiles/Input_curves_bm7ionE.xlsx"
I have saved the "response" to look at it after download attempt:
myresponseObject:Object
config:Object
adapter:ƒ xhrAdapter(config)
data:undefined
headers:Object
maxContentLength:-1
method:"get"
responseType:"arraybuffer"
timeout:0
transformRequest:Array[1]
transformResponse:Array[1]
url:"http://127.0.0.1:8000/media/datafiles/Input_curves_bm7ionE.xlsx"
validateStatus:ƒ validateStatus(status)
xsrfCookieName:"XSRF-TOKEN"
xsrfHeaderName:"X-XSRF-TOKEN"
data:ArrayBuffer
headers:Object
content-length:"1345"
content-type:"text/html; charset=utf-8"
date:"Mon, 08 Jun 2020 10:24:40 GMT"
server:"WSGIServer/0.2 CPython/3.7.7"
vary:"Cookie"
x-content-type-options:"nosniff"
x-frame-options:"DENY"
request:XMLHttpRequest
status:200
statusText:"OK"
And url created by window.URL.createObjectUR is:
"blob:http://127.0.0.1:8000/8a40ab70-1ce4-42d2-9176-935c10ef1526"
Which is different from the original:
url:"http://127.0.0.1:8000/media/datafiles/Input_curves_bm7ionE.xlsx"
Guess it should be like this.
So, excel file downloaded is 2kb and is corrupted, formats or file extension is invalid
Spent day on it.....
Regards

Related

Uploading Base64 file to S3 signed URL

I need to upload an image to S3 using signed URL. I have the image in a base64 string. The below code runs without throwing any error, but at the end I see a text file with base64 content in the S3, not the binary image.
Can you please point out what I am missing?
Generate Signed URL (Lambda function JavaScript)
const signedUrlExpireSeconds = 60 * 100;
var url = s3.getSignedUrl("putObject", {
Bucket: process.env.ScreenshotBucket,
Key: s3Key,
ContentType: "image/jpeg",
ContentEncoding: "base64",
Expires: signedUrlExpireSeconds,
});
Upload to S3 (Java Code)
HttpRequest request = HttpRequest.newBuilder().PUT(HttpRequest.BodyPublishers.ofString(body))
.header("Content-Encoding", "base64").header("Content-Type", "image/jpeg").uri(URI.create(url)).build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new Exception(response.body());
}
I am not familiar with the AWS JavaScript SDK. But it seems that setting the 'Content-Type' metadata of the object (not the Content-Type of the putObject HTTP request) to 'image/jpeg' should do the trick.
Fixed it while just playing around with the combinations.
HttpRequest request = HttpRequest.newBuilder().PUT(HttpRequest.BodyPublishers.ofString(body))
Changed to
HttpRequest request = HttpRequest.newBuilder().PUT(HttpRequest.BodyPublishers.ofByteArray(body))

Trying to upload video to vimeo via API, resumable approach, getting 412 response

I'm trying to upload a video via the presumable approach, I'm able to get the upload link through PHP curl and jQuery ajax
then I'm trying to upload the file but I receive 412 error.
Failed because: Error: Tus: unable to resume upload (new upload cannot be created without an endpoint), originated from request (method: HEAD, URL: https://asia-files.tus.vimeo.com/files/vimeo-prod-src-tus-asia/123456789, response code: 412, response text: , request id: n/a) (123456789 is just a dummy number here)
I tried to remove the headers but I get 404 error which seems worse to me, so I kept the headers.
I'm unable to upload the file via Postman (testing API software)which is also weird, PATCH with binary data in body, I get a response 204 that there is no content.
When I try the HEAD request for the upload link via Postman (testing API software), I get status 200.
Expected behavior
The file should have been uploaded to Vimeo in chunks...
Used Tus-JS-client version: [1.0.0]
CDN: ttps://cdn.jsdelivr.net/npm/tus-js-client#latest/dist/tus.min.js
function resumable(url) {
let file = $('#video')[0].files[0];
var chunkSize = 128;
// Create a new tus upload
const upload = new tus.Upload(file, {
uploadUrl: url,
headers:{
"Tus-Resumable": "1.0.0",
"Accept": "application/vnd.vimeo.*+json;version=3.4"
},
//endpoint: url,
chunkSize,
retryDelays: [0, 3000, 5000, 10000, 20000],
metadata: {
filename: file.name,
filetype: file.type,
},
uploadSize: file.size,
onError(error) {
console.log(`Failed because: ${error}`);
},
onProgress(bytesUploaded, bytesTotal) {
const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2);
console.log(bytesUploaded, bytesTotal, `${percentage}%`);
},
onSuccess() {
console.log('Download %s from %s', upload.file.name, upload.url);
},
})
// Check if there are any previous uploads to continue.
upload.findPreviousUploads().then(function (previousUploads) {
// Found previous uploads so we select the first one.
if (previousUploads.length) {
upload.resumeFromPreviousUpload(previousUploads[0])
}
// Start the upload
upload.start()
})
}
tus-js-client documentation has a Vimeo-specific example

Angular10 File Upload to django Server

I'm trying to upload a CSV file using Angular HTTP Client. But when i check the request.FILES in backend it shows <MultiValueDict: {}>. Apparently the file data is coming in request.body as byte string. Below is sample angular code for you reference.
const upload_url = `${BASE_URL}/data-upload`;
// Create form data instance
const formData: FormData = new FormData();
formData.append('data_file', file, file.name);
// Update header
const headers = {'Content-Type': 'multipart/form-data'}
this.http.post(upload_url, formData, {headers: headers}).subscribe(res => {
console.log(res);
});
How can i get the same file data in request.FILES?
Problem Solved! File upload infers Content-Type Header while uploading the data to the server.
I have removed the header from the above code and uploaded the file and it worked perfectly.
Here's the response after uploading the file from request.FILES: <MultiValueDict: {'data_file': [<TemporaryUploadedFile: dummy-data.csv (application/vnd.ms-excel)>]}>

Downloaded compressed data (`gz`) from django server using ajax is inflated and broken

I'm trying to download a .gz file from a django server (Python 3.7) using Ajax post request. This is the minimal django view function and Ajax function to request download on client, compress a folder and send it (server) and receive the data on the client:
from pathlib import Path
def downloadfile(request):
folder = Path().home().joinpath('workspace')
tar_path = Path().home().joinpath('workspace.gz')
tar = tarfile.open(tar_path.as_posix(), 'w:gz')
tar.add(folder.as_posix(), arcname='workspace')
tar.close()
try:
with open(tar_path.as_posix(), 'rb') as f:
file_data = f.read()
response = HttpResponse(file_data, content_type='application/gzip')
response['Content-Disposition'] = 'attachment; filename="workspace.gz"'
except IOError:
response = HttpResponse('File not exist')
return response
This is the Ajax function on the client side:
$(function () {
$('#downloadfile').submit(function () {
$.ajax({
type: 'POST',
url: 'downloadfile',
success: function(response){
download(response,'workspace.gz', 'application/gzip');
}
});
return false;
});
});
function download(content, filename, contentType)
{
var a = document.createElement('a');
var blob = new Blob([content], {'type':contentType});
a.href = window.URL.createObjectURL(blob);
a.download = filename;
a.click();
}
A sample gzipped folder that is 36.5 KB will be inflated to 66.1 KB when downloaded and it clearly can't be extracted.
What I know:
The file is healthy and extractable on server side.
The data is transferred and downloaded on the client but inflated and broken.
The respone variable in the JavaScript function looks like binary data (no header whatsoever)
What I don't know:
Why is the data size increased even though I'm reading and sending the compressed file as binary and both content types are set to 'application/gzip'?
If something is added to the file, what is it and when is it being added?
Thank you,
After spending a few hours on this, the following worked for me.
The trick was to use the hexify on the Django view part. The sending part in the Django view should be :
try:
with open(tar_path.as_posix(), 'rb') as f:
file_data = binascii.hexlify(f.read())
response = HttpResponse(str(file_data), content_type='application/gzip')
response['Content-Disposition'] = 'attachment; filename="%s"' % userid
os.remove(tar_path.as_posix())
except IOError:
response = HttpResponse('File not exist')
return response
and the JS part should create a bytearray:
var r = response.substring(2, response.length - 1);
var typedArray = new Uint8Array(r.match(/[\da-f]{2}/gi).map(function (h) {
return parseInt(h, 16)
}));
download(typedArray, 'workspace.tar.gz', 'application/gzip');

Storing multiple files generated dynamically over browser in django

I am using RecorderJS in my django application. In this, multiple audio files are created in the browser. My question is how can I store these files in the server (directly from the browser).
I have got few leads like using upload_to in FileField (which can be stored via forms) or using file-based sessions in Django. However, I am not sure how to proceed as it seems complicated for me to combine the following reasons:
multiple files to be stored simulataneously,
and storing directly from browser (not manually uploading in the browser).
Does anyone have solution to this. Thanks in advance.
[Update]
I have proceeded the direction as shown below in the form of a code:
In urls.py
url(r'^audio_file/$', 'nalign_app_recorder.views.recorder'),
In models.py
class InputFile(models.Model):
audio_file = models.FileField(upload_to='/audio')
input_user = models.ForeignKey(User)
rec_date = models.DateTimeField('date recorded', auto_now_add=True)
I am sending the audio file (blob) via Ajax Jquery.
function uploadBlob(blob) {
var fd = new FormData();
fd.append('fname', 'test.wav');
fd.append('data', blob);
$.ajax({
type: 'POST',
url: '/audio_file/',
data: fd,
processData: false,
contentType: false,
success: function(response) {
console.log("everything worked!");
$("#audio_file").html(response);
},
error: function(obj, status, err) { alert(err); console.log(err); }
});
Then I receive this file in the Django view [views.py]. However, though the file is received but the error is generated when the save() method is invoked. Does anyone know the solution for this or is there any better method:
#csrf_exempt
def recorder(request):
if request.method=='POST' or request.is_ajax():
e1=InputFile()
e1.audio_file=request.FILES #<-- Audio file is received here
e1.input_user=request.user
e1.rec_date=datetime.datetime.now()
e1.save() #<-- When save() method is executed, **error** is generated
return HttpResponseRedirect(--another-page--)
return render_to_response('recorder2.html',RequestContext(request))
Due to security reasons browsers don't allow you to set value of <file> form field. (Imagine hiding this field and setting the value to some vulnerable file).
You need to post the file via JavaScript.