Reputation: 2732
I am implementing an API to store files in Azure Blob Storage.
I am using the Microsoft library to validate the container and blob name.
NameValidator.ValidateContainerName(containerName);
NameValidator.ValidateBlobName(blobFullName);
However, it is returning some names as valid even though, by their own docs I know they are not and when I try to save them, blob storage is returning a 400 bad request, as expected. So aside from the question as to why the MS validation libraries are incomplete, how can I perform the rest of the validation in C#? Specifically, I am now failing on the part
"some ASCII or Unicode characters, like control characters (0x00 to 0x1F, \u0081, etc.)"
I have a file with \u0081 in the filename. What are the remaining invalid characters. They point us to ietf docs, but then say "some" of those characters are not allowed? Which ones? Just all control characters?
Just for clarity, here's the part that returns the 400
CloudBlockBlob blob = documentContainer.GetBlockBlobReference(blobFullName);
await blob.UploadFromStreamAsync(fileStream, token).ConfigureAwait(false);
Thanks for your help!
Update: I've added this bit of logic to check for control characters at least. If I can get something somewhat robust, I will issue a PR against Microsoft's validation code
if (blobFullName.ToCharArray().Any(c => Char.IsControl(c))) {
throw new HissyFitException(); // or do other stuff to fail validation
}
Upvotes: 6
Views: 4807
Reputation: 310
I now wrote my own implementation for checking the validity of the storage account name, the container name and the blob name. In my implementation, the whole name has to be passed to the method in the form: Storage_Account_name/Container_name/Blob_name, e. g. mystorageaccount/containername/this/is_a/blob.jpg The blob name may contain "/".
// Use like this:
public static bool IsBlobFilenameValid(string blobFilename)
{
// e. g. blobFilename = "mystorageaccount/containername/this/is_a/blob.jpg
string storageAccount = GetStorageAccount(blobFilename);
string container = GetContainer(blobFilename);
string blobName = GetBlobFilename(blobFilename);
if(string.IsNullOrWhiteSpace(storageAccount)
|| string.IsNullOrWhiteSpace(container)
|| string.IsNullOrWhiteSpace(blobName)
|| !IsAzureBlobFilenameValid(blobFilename))
{
return false;
}
return true;
}
private static bool IsAzureBlobFilenameValid(string filename)
{
if (filename.Count(c => c == '/') < 2)
{
return false;
}
var storageAccount = GetStorageAccount(filename);
var container = GetContainer(filename);
var blob = GetBlobFilename(filename);
string patternAccount = @"^[a-z0-9]{3,24}$";
string patternContainer = @"^[a-z0-9-]{3,63}$";
string patternBlob = @"^.{1,1024}$";
if (!Regex.IsMatch(container, patternContainer)
|| !Regex.IsMatch(storageAccount, patternAccount)
|| !Regex.IsMatch(blob, patternBlob))
{
return false;
}
return true;
}
private static string GetStorageAccount(string file)
{
int charLocation = file.IndexOf('/', StringComparison.Ordinal);
if (charLocation > 0)
{
return file.Substring(0, charLocation);
}
return string.Empty;
}
private static string GetContainer(string file)
{
int charLocation = IndexOfSecond(file, "/");
if (charLocation > 0)
{
return file.Substring(0, charLocation);
}
return string.Empty;
}
private static string GetBlobFilename(string file)
{
int charLocation = IndexOfSecond(file, "/");
if (charLocation > 0)
{
return file.Substring(charLocation + 1, file.Length - (charLocation + 1));
}
return string.Empty;
}
private static int IndexOfSecond(string theString, string toFind)
{
int first = theString.IndexOf(toFind);
if (first == -1) return -1;
// Find the "next" occurrence by starting just past the first
return theString.IndexOf(toFind, first + 1);
}
Upvotes: 2
Reputation: 29985
"some ASCII or Unicode characters, like control characters (0x00 to 0x1F, \u0081, etc.)"
The doc is not clear with the word "some", you can raise a doc issue at azure doc site and ask them update doc by providing the full list of these.
Upvotes: 1