Hi,
Here is my user story for a website allowing users to add files into storage.
- User clicks 'upload a file'
- Browser requests an upload Url from the service.
- Service creates a blob container in the user account
- Service creates a time-bombed SAS url on the container, say, 1hr.
- Service passes back the upload Url.
- User, meanwhile, is choosing a file from disk (fileToUpload).
- Upon selection of file and with the uploadUrl in hand, the browser does a PUT of the file to the SAS url + filename (putUrl).
- When the upload is done, the browser notifies the service which revokes the SAS and starts processing the file (say, adding an uploaded jpg to a user-managed gallery).
Unacceptable architectural work arounds:
Uploading the file to the web-role or worker using a POST, and then having the service do the write to storage. Why not: This forces me to scale out my service to manage all the inbound bandwidth, Azure Storage is there for that, I shouldn't design a
bottleneck on purpose. Also, I may not geo-replicate the service, so the user's storage account may be across the globe from any intermediate upload service.
.
This can be implemented using the following simple calls:
fileToUpload = "c:\\temp\\some.jpg"
putUrl = "http://useraccount.blob.core.windows.net/image-guid/some.jpg?st=2012-10-11T16:32:18Z&se=2012-10-11T17:32:18Z&sr=c&si=e657ca66-b4cc-44d4-a9fe-a6b000000000&sig=K1g2L0n/XYDoa5YJQ9lZzwfc63HGRHC4C400000000="
ulFile = new FileReader(fileToUpload);
req = new XMLHttpRequest();
req.open("PUT", putUrl);
req.onload = function(event) { alert(event.target.responseText); }
req.send(ulFile);
Now here is what I'm getting when that .send is called:
Outbound:
OPTIONS http://useraccount.blob.core.windows.net/image-guid/some.jpg?st=2012-10-11T16:32:18Z&se=2013-10-11T16:32:18Z&sr=c&si=e657ca66-b4cc-44d4-a9fe-a6b000000000&sig=K1g2L0n/XYDoa5YJQ9lZzwfc63HGRHC4C4000000000= HTTP/1.1
Host: useraccount.blob.core.windows.net
Connection: keep-alive
Access-Control-Request-Method: PUT
Origin: chrome://newtab
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4
Access-Control-Request-Headers: origin, content-type
Accept: */*
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Notice the request for OPTIONS to validate the cross-origin resource sharing, specifically the "Access-Control-Request-Method: PUT" and "Access-Control-Request-Headers" for origin and content type.
Responce:
HTTP/1.1 405 The resource doesn't support specified Http Verb.
Transfer-Encoding: chunked
Allow: GET,HEAD,PUT,DELETE
Server: Microsoft-HTTPAPI/2.0
x-ms-request-id: 3b0c6b92-5bbe-48a9-8ee0-901d393b0359
Date: Thu, 11 Oct 2012 19:43:31 GMT
0
Any here we see that the Azure Storage allowed HTTP verbs does not include OPTIONS.
In Chrome, this kills the upload right there and then.
Can you share plans for supporting OPTIONS which implements CORS to support simple PUTs via XMLHttpRequest, which is availabe on all modern browsers?
Otherwise, what is the recommended method for uploading from the browser directly into storage via PUTs and SAS urls?
Thanks,
Nick Drouin
Refs for CORS and the code snippet:
http://enable-cors.org/
http://www.html5rocks.com/en/tutorials/file/xhr2/
https://developer.mozilla.org/en-US/docs/FileGuide/FileUpDown
http://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#request-method