Michael
Michael

Reputation: 431

PUT File to Azure Blob without ContentLength

I am working with a company and want them to be able to PUT a file into my Azure Blobstorage. The idea is that I generate the Authorization header and pass this and the other required headers to them using their REST API. They then use this to PUT the file to my Azure Container.

The problem is that I don't know the size of the file they will be PUTting. In all my research and in testing with Postman, I have to know the size of the file in order to set the ContentLength when creating the Authorization Header. Only then will the PUT be successful. My Authorization header is in this format:

SharedKey storagename:zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz=
  1. Is it possible to create an Authorization header without knowing the ContentLength?
  2. If not, is there another way PUTting or Posting the file to a blob (or Azure File if that is more likely to succeed)?

Upvotes: 0

Views: 1045

Answers (2)

Michael
Michael

Reputation: 431

As @GuaravMantri said (and as I suspected) content length is essential when creating a file using an authorization header that will be used to PUT using a SharedKey. I hadn't got as far as thinking about the second problem he mentioned, that the link would expire before being used.

So here is what I ended up doing in C# to generate the url with Shared Access Signature:

        string blobName = $"TestFile.txt";
        string storageAccountName = "aaaaaaaa";
        string containerName = "ccccccccc";
        string key = "kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk==";

        string connectionString = $"DefaultEndpointsProtocol=https;AccountName={storageAccountName};AccountKey={key}";
        BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString);
        BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(containerName);
        BlobClient blob = containerClient.GetBlobClient(blobName);

        var sasBuilder = new Azure.Storage.Sas.BlobSasBuilder()
        {
            BlobContainerName = containerName,
            BlobName = blobName,
            Resource = "b",  
            StartsOn = DateTime.UtcNow.AddMinutes(-5),
            ExpiresOn = DateTime.UtcNow.AddMinutes(120)
        };
        sasBuilder.SetPermissions(Azure.Storage.Sas.BlobSasPermissions.Create);

        StorageSharedKeyCredential storageSharedKeyCredential = new StorageSharedKeyCredential(storageAccountName, key);
        BlobSasQueryParameters sasQueryParameters = sasBuilder.ToSasQueryParameters(storageSharedKeyCredential);

        UriBuilder fullUri = new UriBuilder()
        {
            Scheme = "https",
            Host = string.Format($"{storageAccountName}.blob.core.windows.net"),
            Path = string.Format($"{containerName}/{blobName}"),
            Query = sasQueryParameters.ToString()
        };

        BlobClient blobClient = new BlobClient(fullUri.Uri, null);

        string uriToUseInPostman = fullUri.Uri.ToString();

I used Postman to test this:

Postman Screent-print

Note that I had to set the x-ms-blob-type. Without this header the upload fails.

Upvotes: 1

Gaurav Mantri
Gaurav Mantri

Reputation: 136286

I believe the approach you're thinking is not going to work.

First, you would need to specify content length when computing authorization header which you don't know obviously.

Secondly, when you compute authorization header you have to specify the current date time (in either Date or x-ms-date header). The issue that you will run into is that your client's request will be rejected if the authorization header is not used almost immediately.

A better option for you would be to make use of Shared Access Signature with Write permission. There you don't have to worry about including the content length. Your users will simply use Shared Access Signature URL to upload the files into your blob container. You would want to create a SAS URL for the blob container in which you want your users to upload the files.

Upvotes: 1

Related Questions