3
votes

I followed this great article by Gaurav Mantri in order to upload files using HTML5/Javascript directly into blob storage.

http://gauravmantri.com/2013/02/16/uploading-large-files-in-windows-azure-blob-storage-using-shared-access-signature-html-and-javascript/

However I am finding that during the upload portion this portion of his code fails with the 403 error.

And the funny thing is, this happens randomly. Sometimes the upload actually works and everything completes successfully however majority of the time it is failing with the 403 error.

One thing to note: I am hoping that CORS support will be added soon to Azure however for time being I am using Chrome (with the chrome.exe --disable-web-security option) to get around the issue.

PUT https://mystorage.blob.core.windows.net/asset-38569007-3316-4350…Giv17ye4bocVWDbA/EQ+riNiG3wEGrFucbd1BKI9E=&comp=block&blockid=YmxvY2stMA==

403 (Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.)

$.ajax({
    url: uri,
    type: "PUT",
    data: requestData,
    processData: false,
    beforeSend: function(xhr) {
        xhr.setRequestHeader('x-ms-blob-type', 'BlockBlob');
        xhr.setRequestHeader('Content-Length', requestData.length);
    },
    success: function (data, status) {
        console.log(data);
        console.log(status);
        bytesUploaded += requestData.length;
        var percentComplete = ((parseFloat(bytesUploaded) / parseFloat(selectedFile.size)) * 100).toFixed(2);
        $("#fileUploadProgress").text(percentComplete + " %");
        uploadFileInBlocks();
    },
    error: function(xhr, desc, err) {
        console.log(desc);
        console.log(err);
    }
});

I have put a 30-sec delay after creating the asset/locator/file in Azure before actually starting the upload portion in order to give time for the Locator to be propagated.

Any suggestion to what I could be missing?

2
Can you ensure that your shared access signature is not expired? As an alternate test, you could try to upload the file using SAS and .Net SDK as well. You could also run Fiddler to see the detailed message returned from the storage service. As far as CORS is concerned, it is coming pretty soon. It was announced and demonstrated during //Build/ conference last week.Gaurav Mantri
Gaurav, I was at //Build and am looking forward to CORS but hopefully in the meantime can resolve this issue. I provided my asset/locator/policy creation code below. I have had no problems using the .NET SDK to upload files using the same style of code so I am not sure what the issue is.Gautam

2 Answers

2
votes

Many thanks to Gaurav for pointing me in the direction of the issue.

It turns out that I was making JSON calls to the server which would create the assets/locators/policies and then return the upload uri back.

However my upload uri was of type Uri and when JSON serialized it, it didn't properly encode it.

After changing my uri object (on the server) to a string (and calling uploaduri = (new UriBuilder(theuri)).ToString(); ) the uri returned back to the web client was properly encoded and I no longer got the 403 errors.

So as a heads up to others, if you get this same issue, you may want to look at the encoding of your upload uri.

0
votes

Gaurav here's the code I use to create the empty asset (w/ locator and file):

/// <summary>
/// Creates an empty asset on Azure and prepares it to upload
/// </summary>
public FileModel Create(FileModel file)
{
    // Update the file model with file and asset id
    file.FileId = Guid.NewGuid().ToString();

    // Create the new asset
    var createdAsset = this.Context.Assets.Create(file.AssetName.ToString(), AssetCreationOptions.None);

    // Create the file inside the asset and set its size
    var createdFile = createdAsset.AssetFiles.Create(file.Filename);
    createdFile.ContentFileSize = file.Size;

    // Create a policy to allow uploading to this asset
    var writePolicy = this.Context.AccessPolicies.Create("Policy For Copying", TimeSpan.FromDays(365 * 10), AccessPermissions.Read | AccessPermissions.Write | AccessPermissions.List);

    // Get the upload locator
    var destinationLocator = this.Context.Locators.CreateSasLocator(createdAsset, writePolicy);

    // Get the SAS Uri and save it to file
    var uri = new UriBuilder(new Uri(destinationLocator.Path));
    uri.Path += "/" + file.Filename;
    file.UploadUri = uri.Uri;

    // Return the updated file
    return file;
}