Damien Pontifex
Damien Pontifex

Reputation: 1262

Uploading to azure blob storage from SAS URL returns 404 status

I am using Azure Mobile Services API endpoint to return a private shared access signature URL to my azure storage container like so:

var blobService = azure.createBlobService(accountName, key, host);

blobService.createContainerIfNotExists(containerName, function(err) {

    if (err) {
        cb(err, null);
        return;
    }

    // Generate a 5 minute access
    var expiryDate = minutesFromNow(5);
    var sharedAccessPolicy = {
        AccessPolicy: {
            Permissions: azure.Constants.BlobConstants.SharedAccessPermissions.WRITE,
            Expiry: expiryDate
        }
    };

    // Generate the URL with read access token
    var sasURL = blobService.generateSharedAccessSignature(containerName, blobName, sharedAccessPolicy);

    var urlForDownloading = sasURL.baseUrl + sasURL.path + '?' + qs.stringify(sasURL.queryString);

    cb(null, urlForDownloading);
});

function minutesFromNow(minutes) {
    var date = new Date();
    date.setMinutes(date.getMinutes() + minutes);
    return date;
};

I then return this URL to my iOS client to upload the file and process it as:

client.invokeAPI("document/\(document.idValue).\(document.fileExtension)",
                    body: nil,
                    HTTPMethod: "PUT",
                    parameters: nil,
                    headers: nil) { result, response, error in
                        if let dictResult = result as? NSDictionary {

                            // Get the SAS URL to write directly to the blob storage
                            if let location = dictResult["location"] as? String {
                                let url = NSURL(string: location)

                                let request = NSURLRequest(URL: url)
                                let uploadTask = session.uploadTaskWithRequest(request, fromFile: localFile) { data, response, error in
                                    if completionBlock != nil {
                                        let success = (error == nil && httpResponse.statusCode == 200)
                                        completionBlock!(success)
                                     }
                                 }
                             }
                         }
} 

uploadTask.resume()

The iOS client gets a 404 response with a message of

<?xml version="1.0" encoding="utf-8"?><Error><Code>ResourceNotFound</Code><Message>The specified resource does not exist.

The container does exist in the storage account and requests to get blobs from the container with the access keys are successful. This new blob won't exist as it is a new upload, but why am I getting a 404 for a write request to the container?

Upvotes: 1

Views: 2536

Answers (1)

Damien Pontifex
Damien Pontifex

Reputation: 1262

Found the solution...

let request = NSURLRequest(URL: url) produces a GET request and even passing it to uploadTaskWithRequest persists this request type, whereas I thought this call would change it to a PUT or POST request signifying the upload.

Defining the iOS request as

let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "PUT"

was successful. And the response returned was a 201 created.

Upvotes: 1

Related Questions