I'm trying to use Dropzone.js to upload directly to Google Cloud Storage using a Signed URL. I've managed to override the upload URL for each file added to Dropzone. Chrome dev tools says a PUT
request is occurring but I inevitably receive a HTTP 400 error in response.
Here's my Dropzone.js config
Dropzone.options.myAwesomeDropzone = {
url: '/',
uploadMultiple: false,
method: 'PUT',
parallelUploads: 1,
uploadMultiple: false,
header: '',
autoProcessQueue: false,
autoDiscover: false,
maxFiles: 1,
acceptedFiles: 'image/*,video/*',
accept: function(file, done) {
var self = this;
$.post('/api/v1/signed_file_upload', {key: window.apiKey, name: file.name, type: file.type}, function(data) {
if(data.success) {
file.uploadURL = data.data;
done()
setTimeout(function() {
self.processFile(file)
}, 0)
} else {
done(data.message)
}
})
},
init: function() {
var self = this;
this.on('processing', function(file) {
self.options.url = file.uploadURL
})
this.on('sending', function(file, xhr, formData) {
var _send = xhr.send
xhr.send = function() {
_send.call(xhr, file)
}
});
}
};
My signed URL has the following structure:
https://www.googleapis.com/upload/storage/v1/b/{bucket_name}/o/{object_name}.png?GoogleAccessId=xxx@xxx.iam.gserviceaccount.com&Expires=1521610072&Signature=xxx
Chrome Dev Tools shows this for the upload request:
I inevitably receive an HTTP 400 response. Sometimes the body is empty and sometimes it returns a JSON object saying
{
"error": {
"errors": [
{
"domain": "global",
"reason": "badContent",
"message": "Unsupported content with type: image/jpeg"
}
],
"code": 400,
"message": "Unsupported content with type: image/jpeg"
}
}
My signature generating function is
function storage_url($file_name, $bucket_name = '', $content_type = '', $method = 'PUT', $duration = 3000) {
$expires = time() + $duration;
$signature = '';
$to_sign = ($method . "\n\n" . $content_type . "\n" . $expires . "\n" . '/' . $bucket_name . '/' . $file_name);
$private_key = json_decode(file_get_contents('xxx.json'))->private_key;
if(!openssl_sign( $to_sign, $signature, $private_key, 'sha256' ))
{
return false;
}
else
{
$signature = urlencode(base64_encode($signature));
}
error_log($to_sign);
return 'https://www.googleapis.com/upload/storage/v1/b/' . $bucket_name . '/o/' . urlencode($file_name) .
'?GoogleAccessId=' . 'xxx@xxx.iam.gserviceaccount.com' .
'&Expires=' . $expires .
'&Signature=' . $signature;
}