Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GSUTIL Signed Url PUT to Google Cloud Storage fails

I'd like users of a site to be able to upload files to google cloud storage without using the web app servers resources so signed urls seem like the way to go.

When a user selects a file to upload jquery sends a GET request to django for a signed url. The url is generated using gsutil signurl command. Django then returns the signed url to the template and on submit a jquery PUT request is sent with the signed url.

However:

  • the PUT request fails with 'SignatureDoesNotMatch'.
  • GET requests for storage objects work fine using this method.

Are there required headers that must be sent with the PUT request?

gsutil command (assuming user selected file 'map.html')...

gsutil signurl -p notasecret -m PUT -d 10m /path/to/.p12 gs://bucket_name/map.html

jquery PUT code...

    $.ajax( {
  url: g_url,
  type: 'PUT',
  crossDomain: true,
  success: console.log('success'),
  error: function(XMLHttpRequest, textStatus, errorThrown){
    alert('status:' + XMLHttpRequest.status + ', status text: ' + XMLHttpRequest.statusText);
},
  data: file,
} );

g_url looks like...

https://storage.googleapis.com/bucket_name/map.html?GoogleAccessId=__retracted__&Expires=1408889274&Signature=rDJAZQG4MIyMupy0M8HJ17r8rkEJcAbYSWpcq084SdzRh%2BnZavTfuWl4Q%2F6ytkSkN2c2%2B4b4pPRF5eWOEOL1InRxlB5pEBedPFZPpgDrRvR9tFybtH%2BkesKLhIZ3WjJ0utzAwhl%2BgAlQY6ulvO0Djib20zcG5fkHOigpRf1xBUk%3D
like image 716
mhabiger Avatar asked Nov 10 '22 02:11

mhabiger


1 Answers

Turns out my problem was related to CORS. In order to get this to work on Django 1.6, I had to do the following:

  • Install django-cors-headers and follow configuration instructions https://github.com/ottoyiu/django-cors-headers
  • Configure CORS on the GCS bucket with the appropriate verbs and to accept requests from my domain https://developers.google.com/storage/docs/cross-origin
  • Add the jquery code provided in the Django docs to my template https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#how-it-works

With that PUT and DELETE requests started working. The only other issue I ran into was incompatible content-headers. So you my need to set your content-type in the signed url and before sending the request.

gsutil command would look like

gsutil signurl -p notasecret -m PUT -d 10m -c 'multipart/formdata; charset=UTF-8' /path/to/.p12 gs://bucket_name/map.html

add beforeSend to jquery request

beforeSend: function (request){
request.setRequestHeader("Content-Type", 'multipart/formdata; charset=UTF-8')
;},
like image 126
mhabiger Avatar answered Nov 15 '22 08:11

mhabiger