Image Upload Issue using gcs Upload Signed URL | React JS - javascript

Using this for to generate GCS Upload signed url v4
https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/storage/cloud-client/storage_generate_upload_signed_url_v4.py#L27
I have generated upload signed url using this function "generate_upload_signed_url_v4" as mentioned above and also I tried using GSUTIL as well using
gsutil signurl -m PUT service_account.json gs://<bucket>/file.png
I am working on a demo where I need to upload PDF, PNG to GCS bucket. File uploading is file. But when I preview file in GCS Storage Console and download/preview file form Link URL
PDF is fine. But PNG somehow got damaged and not opening/previewing.
I am using Chrome '81.0.4044.138'
When I further preview PNG file using text editor it contains some header content at the top of file.
i.e
------WebKitFormBoundarysZ3BDVaNOhqwENsp
Content-Disposition: form-data; name="file"; filename="test.png"
Content-Type: image/png
So if we remove this from top of file the file will open fine..
I have created a sample React project which can be accessed here
Demo: https://github.com/qaisershehzad/upload-gcs
I am using this code for file upload
` const url = "https://storage.googleapis.com//file.png.png?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=gitlab-ci%.iam.gserviceaccount.com%2F20200521%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20200521T175304Z&X-Goog-Expires=36000&X-Goog-SignedHeaders=content-type%3Bhost&X-Goog-Signature="
const data = new FormData()
data.append('file', this.state.selectedFile)
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader("Content-type", "application/octet-stream");
xhr.onload = function (response) {
console.log('on-load', response);
};
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log("Status OK")
} else {
console.log("Status not 200")
}
}
};
xhr.onerror = function (response) {
console.log("Response error", response)
};
xhr.upload.onprogress = function (evt) {
// For uploads
if (evt.lengthComputable) {
var percentComplete = parseInt((evt.loaded / evt.total) * 100);
console.log("progress", percentComplete)
}
}
xhr.send(data);`
I also tried same thing on Android as well and facing same issue. In Png at top these header string got added which not allowing to open Png file.
Png uploading is working fine using this CURL request.
curl -X PUT -H 'Content-Type: application/octet-stream' --upload-filen file.png 'https://storage.googleapis.com//file.png?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=gitlab-ci%.iam.gserviceaccount.com%2F20200521%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20200521T175304Z&X-Goog-Expires=36000&X-Goog-SignedHeaders=content-type%3Bhost&X-Goog-Signature='
It will be helpful if someone can help to resolve this issue.

Actually you are sending FormData which causes a problem, you will see file get uploaded but when you retrieve file its content will be different in case of image possibly image will not get rendered.
The reason why cURL is working, because you are directly sending file not FormData.
To fix this scenario directly pass the file to ajax like mentioned below:
const file = this.state.selectedFile;
ajax.setRequestHeader('Content-Type', file.type);
ajax.send(file); // direct file not FormData

Related

How to download file into memory without writing the file to the system or without creating the file in a directory using javascript

I am looking for something like this, but using javascript. I want to download the file into javascript memory and then add the file content to a file input so that I can upload that again. I have written a function to access the file.
function fileDownload(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.send();
xhr.onload = function() {
if (xhr.status != 200) { // analyze HTTP status of the response
console.log(`Error ${xhr.status}: ${xhr.statusText}`); // e.g. 404: Not Found
} else { // show the result
callback(xhr.response)
}
};
}
So xhr supports the response type as text, arraybuffer, blob and document. So which type should I use? I want to support all types of files. Can I use blob?In that case how can I assign it to an input type of file. Please help.

How to handle File Object for gapi savetodrive src?

In my react app, I have a file object and I want to upload this file to google drive.
I tried to use window.URL.createObjectURL, but the uploaded file on google drive is HTML code of my site instead of the file "f.mp4".
Is there anybody know how to upload file object to google drive in browser????
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "blob";
xhr.onload = function () {
let gDoxBlob = xhr.response;
let file = new File([gDoxBlob], "f.mp4", {
type: 'video/mp4'
})
let newUrl = window.URL.createObjectURL(file);
console.log(url, newUrl.slice(5))
gapi.savetodrive.render('savetodrive-div', {
src: newUrl.slice(5), // to remove 'blob:'
filename: 'file',
sitename: 'site'
});
}
xhr.send();
For more explanation,
The 'url' is a download url from firebase storage.
In the case of dropbox, Dropbox.save with the 'url' worked nicely.
But because of the CORS error, google drive didn't work with 'url'
I tried to set my firebase cors policy but it didn't work, so I'm trying with file object after downloading a file from the 'url'.

How to Download a file with Google File Picker API?

I've been following this Google File Picker tutorial and I've gotten so far as to get the file picker showing and getting the URL, but I don't know how to download the file using JavaScript. If I can use VB.NET, then can someone point me in the right direction?
I've been able to download files with VB.NET from my own database, but I don't know how to get it with the Google API or with JavaScript.
All of the file picker code works, and I'm calling this from the onSelect of the FilePicker:
function downloadGDriveFile(file) {
if (file.downloadUrl) {
var accessToken = gapi.auth.getToken().access_token;
var xhr = new XMLHttpRequest();
xhr.open('GET', file.downloadUrl); // use selfLink??
xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken);
xhr.onload = function () {
var content = xhr.responseText;
};
xhr.onerror = function () {
alert('Download failure.');
};
xhr.send();
} else {
alert('Unable to download file.');
}
}
And when I click on the download URL I get this error:
"code": 403,
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup."
The error you posted is an issue with your account reaching it's max usage limit. Different issue than downloading the file. I don't have any knowledge on the google file picker api, but I'm going to assume this is in the browser.
You may have to specify req.responseType = "arraybuffer" because it could default to json.
I recommend using http://danml.com/download.html. Browser API does not expose the download modal for security reasons. The hack is to create an invisible a tag set the url to the blob of the body that you received and programmatically click the tag. The library provided does exactly that.

Uploading images via azure storage

I am trying to upload images to blob storage via azure functions. Kind of struggling to get it working.
var data = new FormData();
xhr = new XMLHttpRequest();
data.append('file', file);
data.append('name', file.name);
xhr.open('POST', 'https://[blobstorage]/api/upload/foo', true);
xhr.setRequestHeader('Content-type', 'multipart/form-data;');
xhr.send(data);
The POST gets triggered in azure functions:
if (context.req.method === 'POST') {
fs.readFile(context.req.rawBody, function (err, data) {
context.log('data', data);
blobService.createBlockBlobFromText(containerName, blob, data, {contentSettings: {contentType: 'image/png'}}, function(){
context.done();
});
});
}
This adds a file to blob storage but it isnt the image unfortunatly.
I believe context.log('data', data); showsundefined in the logs. That's why you are getting zero size file. Unfortunately multipart parsing is not part of Azure Functions functionality. You can find more details here:
How to parse Multi-part form data in an Azure Function App with HTTP Trigger? (NodeJS)

Javascript binary file download, and ajax file POST upload in Chrome Extension

I'm writing a chrome extension content script which will embed itself on some pages, and when there are certain file type links (.doc, .torrent, etc) it will download that file, and then do a file POST to a python web server which will save that file. The python server is working, and handles a normal multipart/form-data POST request, and successfully saves the file when I use the html interface I wrote for it.
I have javascript downloading the file properly:
var req = new XMLHttpRequest();
req.open('GET', 'http://foo.com/bar.torrent', false);
req.overrideMimeType('text/plain; charset=x-user-defined');
req.send(null);
if (req.status != 200) return '';
var response = req.responseText;
And then when I try to create a POST request and upload it
// Define a boundary, I stole this from IE but you can use any string AFAIK
var boundary = "---------------------------7da24f2e50046";
var xhr = new XMLHttpRequest();
var body = '--' + boundary + '\r\n'
// Parameter name is "file" and local filename is "temp.txt"
+ 'Content-Disposition: form-data; name="upfile";'
+ 'filename="temp.torrent"\r\n'
// Add the file's mime-type
+ 'Content-type: application/bittorrent\r\n\r\n'
+ response + '\r\n';
//+ boundary + '--';
xhr.open("POST", "http://python.server/", true);
xhr.setRequestHeader(
"Content-type", "multipart/form-data; boundary="+boundary
);
xhr.onreadystatechange = function ()
{
if (xhr.readyState == 4 && xhr.status == 200)
alert("File uploaded!");
}
xhr.send(body);
It thinks that it uploaded successfully, but when I try to open the file it says the data is corrupted. I think this is some kind of encoding issue, but I'm not 100% sure.
Any thoughts would be very helpful.
Your upload method does not work, because all binary characters are encoded as UTF-8. I posted the explanation and solution in an answer at this question.
In your case, you don't need to manually create the post data. Request the initial data in a smart way, and use the FormData object to post the binary data. For instance:
var x = new XMLHttpRequest();
x.onload = function() {
// Create a form
var fd = new FormData();
fd.append("upfile", x.response); // x.response is a Blob object
// Upload to your server
var y = new XMLHttpRequest();
y.onload = function() {
alert('File uploaded!');
};
y.open('POST', 'http://python/server/');
y.send(fd);
};
x.responseType = 'blob'; // <-- This is necessary!
x.open('GET', 'http://foo.com/bar.torrent', true);
x.send();
Note: I replaced false with true at the initial request. Avoid using synchronous XMLHttpRequest when it's also possible to asynchronously create the request.
If you don't understand the answer, here are more examples with thorough explanations:
XMLHttpRequest: Multipart/Related POST with XML and image as payload - FormData is not used, but the post data is manually created instead.
Upload a File in a Google Chrome Extension - A sample Chrome extension which uses Web Workers (with a FormData polyfill) to upload files
Google chrome rehost image extension - Scrapes an image from the page, and upload the image to imgur using a Chrome extension.

Categories