azure-sdk-for-net
azure-sdk-for-net copied to clipboard
[BUG] Ambiguous behavior downloading blobs using conditions between v11 and v12
Library name and version
Azure.Storage.Blobs 12.13.1
Describe the bug
Downloading a blob using the SDK v11, throws a StorageException
when the blob exists and a condition is passed like this:
blob.DownloadToStream(memStream2, AccessCondition.GenerateIfNoneMatchCondition(eTag));
//or
blob.DownloadTo(filePath, AccessCondition.GenerateIfNoneMatchCondition(eTag));
However, in v12. Two things are happening:
- No exception is thrown (was expecting
RequestFailedException
) - The Stream/File is empty
blob.DownloadTo(memStream2, conditions: new BlobRequestConditions
{
IfNoneMatch = new ETag(eTag),
});
//or
blob.DownloadTo(filePath, conditions: new BlobRequestConditions
{
IfNoneMatch = new ETag(eTag),
});
Expected behavior
v12 version should throw a RequestFailedException
where ErrorCode == BlobErrorCode.ConditionNotMet
Actual behavior
- No exception is thrown (was expecting
RequestFailedException
) - The Stream/File is empty
Reproduction Steps
//v11 test
//storageAcct is a valid instance of CloudStorageAccount
var blobClient = storageAcct.CreateCloudBlobClient();
var container = "test";
var blobContainer = blobClient.GetContainerReference(container);
blobContainer.CreateIfNotExists(BlobContainerPublicAccessType.Off);
var fileName = "TestFile.txt";
using(Stream fileStream = new FileStream(@"..\..\" + fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
CloudBlockBlob blob = blobContainer.GetBlockBlobReference(fileName);
blob.UploadFromStream(fileStream, AccessCondition.GenerateIfNotExistsCondition());
}
string eTag;
using(MemoryStream memStream = new MemoryStream())
{
CloudBlockBlob blob = blobContainer.GetBlockBlobReference(fileName);
blob.DownloadToStream(memStream, AccessCondition.GenerateIfExistsCondition());
eTag = blob.Properties.ETag;
Assert.IsFalse(string.IsNullOrWhiteSpace(eTag), "ETag not provided");
}
using(MemoryStream memStream2 = new MemoryStream())
{
CloudBlockBlob blob = blobContainer.GetBlockBlobReference(fileName);
//the following line throws a StorageException ex
//where -> ex.RequestInformation.HttpStatusCode == (int)System.Net.HttpStatusCode.NotModified
//this behavior is also confirmed in blob.DownloadTo(filePath)
blob.DownloadToStream(memStream2, AccessCondition.GenerateIfNoneMatchCondition(eTag));
}
//v12 test
var container = "test";
//service is a valid instance of BlobServiceClient
var blobContainerClient = service.GetBlobContainerClient(container);
blobContainerClient.CreateIfNotExists(AzureStorage.Models.PublicAccessType.None);
var fileName = "TestFile.txt";
using(Stream fileStream = new FileStream(@"..\..\" + fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
BlobClient blob = blobContainerClient.GetBlobClient(fileName);
blob.Upload(fileData);
}
string eTag;
using(MemoryStream memStream = new MemoryStream())
{
BlobClient blob = blobContainerClient.GetBlobClient(fileName);
blob.DownloadTo(memStream);
eTag = blob.GetProperties().ETag.ToString();
Assert.IsFalse(string.IsNullOrWhiteSpace(eTag), "ETag not provided");
}
using(MemoryStream memStream2 = new MemoryStream())
{
BlobClient blob = blobContainerClient.GetBlobClient(fileName);
//the following line does NOT throw a RequestFailedException
//however the stream is completely empty (memStream2.Length == 0)
//this was also confirmed with DownloadTo(filePath) => file is completely empty
blob.DownloadTo(memStream2, conditions: new BlobRequestConditions
{
IfNoneMatch = new ETag(eTag),
});
}
UPDATE:
I believe the bug is here. That case is not valid, the error should throw and not return an empty Stream
Environment
Hosting Platform and .NET runtime version: Windows 11 .NET Framework 4.6.1 IDE and version: Visual Studio 2019
Thank you for your feedback. This has been routed to the support team for assistance.
I also see the same problem.
Thanks for this information. It actually assisted a lot to what's going on.
So you are correct, I believe a 304 is being thrown because it's comparing the Etags and running into an error. However let me reconfirm if this is the correct response to do in terms of passing the 304. Because looks like we should check the BlobErrorCode
if it is Not-Modified
.
https://github.com/Azure/azure-sdk-for-net/blob/3724ce24abd58311ec7846661870213b5f826911/sdk/storage/Azure.Storage.Blobs/src/PartitionedDownloader.cs#L162
Looks like normally from the service we're expecting a 412 for the modified during in flight.
Hi @amnguye, any news on this?
Looks like the 304 is intentional considering the If-None-Match
conditional header.
Related/Duplicate(kinda) https://github.com/Azure/azure-sdk-for-net/issues/13414#issuecomment-657816714
3xx have to be checked, that's why no RequestFailedException
is not thrown. It would be a breaking change to throw a 304
error.
Adding Service team to look into this
Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc @xgithubtriage.
Issue Details
Library name and version
Azure.Storage.Blobs 12.13.1
Describe the bug
Downloading a blob using the SDK v11, throws a StorageException
when the blob exists and a condition is passed like this:
blob.DownloadToStream(memStream2, AccessCondition.GenerateIfNoneMatchCondition(eTag));
//or
blob.DownloadTo(filePath, AccessCondition.GenerateIfNoneMatchCondition(eTag));
However, in v12. Two things are happening:
- No exception is thrown (was expecting
RequestFailedException
) - The Stream/File is empty
blob.DownloadTo(memStream2, conditions: new BlobRequestConditions
{
IfNoneMatch = new ETag(eTag),
});
//or
blob.DownloadTo(filePath, conditions: new BlobRequestConditions
{
IfNoneMatch = new ETag(eTag),
});
Expected behavior
v12 version should throw a RequestFailedException
where ErrorCode == BlobErrorCode.ConditionNotMet
Actual behavior
- No exception is thrown (was expecting
RequestFailedException
) - The Stream/File is empty
Reproduction Steps
//v11 test
//storageAcct is a valid instance of CloudStorageAccount
var blobClient = storageAcct.CreateCloudBlobClient();
var container = "test";
var blobContainer = blobClient.GetContainerReference(container);
blobContainer.CreateIfNotExists(BlobContainerPublicAccessType.Off);
var fileName = "TestFile.txt";
using(Stream fileStream = new FileStream(@"..\..\" + fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
CloudBlockBlob blob = blobContainer.GetBlockBlobReference(fileName);
blob.UploadFromStream(fileStream, AccessCondition.GenerateIfNotExistsCondition());
}
string eTag;
using(MemoryStream memStream = new MemoryStream())
{
CloudBlockBlob blob = blobContainer.GetBlockBlobReference(fileName);
blob.DownloadToStream(memStream, AccessCondition.GenerateIfExistsCondition());
eTag = blob.Properties.ETag;
Assert.IsFalse(string.IsNullOrWhiteSpace(eTag), "ETag not provided");
}
using(MemoryStream memStream2 = new MemoryStream())
{
CloudBlockBlob blob = blobContainer.GetBlockBlobReference(fileName);
//the following line throws a StorageException ex
//where -> ex.RequestInformation.HttpStatusCode == (int)System.Net.HttpStatusCode.NotModified
//this behavior is also confirmed in blob.DownloadTo(filePath)
blob.DownloadToStream(memStream2, AccessCondition.GenerateIfNoneMatchCondition(eTag));
}
//v12 test
var container = "test";
//service is a valid instance of BlobServiceClient
var blobContainerClient = service.GetBlobContainerClient(container);
blobContainerClient.CreateIfNotExists(AzureStorage.Models.PublicAccessType.None);
var fileName = "TestFile.txt";
using(Stream fileStream = new FileStream(@"..\..\" + fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
BlobClient blob = blobContainerClient.GetBlobClient(fileName);
blob.Upload(fileData);
}
string eTag;
using(MemoryStream memStream = new MemoryStream())
{
BlobClient blob = blobContainerClient.GetBlobClient(fileName);
blob.DownloadTo(memStream);
eTag = blob.GetProperties().ETag.ToString();
Assert.IsFalse(string.IsNullOrWhiteSpace(eTag), "ETag not provided");
}
using(MemoryStream memStream2 = new MemoryStream())
{
BlobClient blob = blobContainerClient.GetBlobClient(fileName);
//the following line does NOT throw a RequestFailedException
//however the stream is completely empty (memStream2.Length == 0)
//this was also confirmed with DownloadTo(filePath) => file is completely empty
blob.DownloadTo(memStream2, conditions: new BlobRequestConditions
{
IfNoneMatch = new ETag(eTag),
});
}
UPDATE:
I believe the bug is here. That case is not valid, the error should throw and not return an empty Stream
Environment
Hosting Platform and .NET runtime version: Windows 11 .NET Framework 4.6.1 IDE and version: Visual Studio 2019
Author: | lumalav |
---|---|
Assignees: | - |
Labels: |
|
Milestone: | - |