Created
July 20, 2022 01:45
-
-
Save juliusl/5f4a3ade5440be1f71ffd531fb7dc401 to your computer and use it in GitHub Desktop.
Self-Contained NameValidator port
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Provides helpers to validate resource names across the Microsoft Azure Storage Services. | |
/// </summary> | |
public static class NameValidator | |
{ | |
/// <summary> | |
/// Checks if a container name is valid. | |
/// </summary> | |
/// <param name="containerName">A string representing the container name to validate.</param> | |
public static void ValidateContainerName(string containerName) | |
{ | |
if (!("$root".Equals(containerName, StringComparison.Ordinal) || "$logs".Equals(containerName, StringComparison.Ordinal))) | |
{ | |
ValidateShareContainerQueueHelper(containerName, Container); | |
} | |
} | |
/// <summary> | |
/// Checks if a queue name is valid. | |
/// </summary> | |
/// <param name="queueName">A string representing the queue name to validate.</param> | |
public static void ValidateQueueName(string queueName) | |
{ | |
ValidateShareContainerQueueHelper(queueName, Queue); | |
} | |
/// <summary> | |
/// Checks if a share name is valid. | |
/// </summary> | |
/// <param name="shareName">A string representing the share name to validate.</param> | |
public static void ValidateShareName(string shareName) | |
{ | |
ValidateShareContainerQueueHelper(shareName, Share); | |
} | |
private static void ValidateShareContainerQueueHelper(string resourceName, string resourceType) | |
{ | |
if (string.IsNullOrWhiteSpace(resourceName)) | |
{ | |
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, ResourceNameEmpty, resourceType)); | |
} | |
if (resourceName.Length < NameValidator.ContainerShareQueueTableMinLength || resourceName.Length > ContainerShareQueueTableMaxLength) | |
{ | |
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, InvalidResourceNameLength, resourceType, ContainerShareQueueTableMinLength, ContainerShareQueueTableMaxLength)); | |
} | |
if (!ShareContainerQueueRegex.IsMatch(resourceName)) | |
{ | |
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, InvalidResourceName, resourceType)); | |
} | |
} | |
/// <summary> | |
/// Checks if a blob name is valid. | |
/// </summary> | |
/// <param name="blobName">A string representing the blob name to validate.</param> | |
public static void ValidateBlobName(string blobName) | |
{ | |
if (string.IsNullOrWhiteSpace(blobName)) | |
{ | |
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, ResourceNameEmpty, Blob)); | |
} | |
if (blobName.Length < BlobFileDirectoryMinLength || blobName.Length > BlobMaxLength) | |
{ | |
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, InvalidResourceNameLength, Blob, BlobFileDirectoryMinLength, BlobMaxLength)); | |
} | |
int slashCount = 0; | |
foreach (char c in blobName) | |
{ | |
if (c == '/') | |
{ | |
slashCount++; | |
} | |
} | |
// 254 slashes means 255 path segments; max 254 segments for blobs, 255 includes container. | |
if (slashCount >= 254) | |
{ | |
throw new ArgumentException(TooManyPathSegments); | |
} | |
} | |
/// <summary> | |
/// Checks if a file name is valid. | |
/// </summary> | |
/// <param name="fileName">A string representing the file name to validate.</param> | |
public static void ValidateFileName(string fileName) | |
{ | |
ValidateFileDirectoryHelper(fileName, File); | |
if (fileName.EndsWith("/", StringComparison.Ordinal)) | |
{ | |
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, InvalidResourceName, File)); | |
} | |
foreach (string s in ReservedFileNames) | |
{ | |
if (s.Equals(fileName, StringComparison.OrdinalIgnoreCase)) | |
{ | |
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, InvalidResourceReservedName, File)); | |
} | |
} | |
} | |
/// <summary> | |
/// Checks if a directory name is valid. | |
/// </summary> | |
/// <param name="directoryName">A string representing the directory name to validate.</param> | |
public static void ValidateDirectoryName(string directoryName) | |
{ | |
ValidateFileDirectoryHelper(directoryName, Directory); | |
} | |
private static void ValidateFileDirectoryHelper(string resourceName, string resourceType) | |
{ | |
if (string.IsNullOrWhiteSpace(resourceName)) | |
{ | |
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, ResourceNameEmpty, resourceType)); | |
} | |
if (resourceName.Length < BlobFileDirectoryMinLength || resourceName.Length > FileDirectoryMaxLength) | |
{ | |
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, InvalidResourceNameLength, resourceType, BlobFileDirectoryMinLength, FileDirectoryMaxLength)); | |
} | |
if (!FileDirectoryRegex.IsMatch(resourceName)) | |
{ | |
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, InvalidResourceName, resourceType)); | |
} | |
} | |
/// <summary> | |
/// Checks if a table name is valid. | |
/// </summary> | |
/// <param name="tableName">A string representing the table name to validate.</param> | |
public static void ValidateTableName(string tableName) | |
{ | |
if (string.IsNullOrWhiteSpace(tableName)) | |
{ | |
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, ResourceNameEmpty, Table)); | |
} | |
if (tableName.Length < ContainerShareQueueTableMinLength || tableName.Length > ContainerShareQueueTableMaxLength) | |
{ | |
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, InvalidResourceNameLength, Table, ContainerShareQueueTableMinLength, ContainerShareQueueTableMaxLength)); | |
} | |
if (!(TableRegex.IsMatch(tableName) || MetricsTableRegex.IsMatch(tableName) || tableName.Equals("$MetricsCapacityBlob", StringComparison.OrdinalIgnoreCase))) | |
{ | |
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, InvalidResourceName, Table)); | |
} | |
} | |
#region Private | |
const int BlobFileDirectoryMinLength = 1; | |
const int ContainerShareQueueTableMinLength = 3; | |
const int ContainerShareQueueTableMaxLength = 63; | |
const int FileDirectoryMaxLength = 255; | |
const int BlobMaxLength = 1024; | |
static readonly string[] ReservedFileNames = { ".", "..", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "PRN", "AUX", "NUL", "CON", "CLOCK$" }; | |
static readonly RegexOptions RegexOptions = RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.CultureInvariant; | |
static readonly Regex FileDirectoryRegex = new Regex(@"^[^""\\/:|<>*?]*\/{0,1}$", RegexOptions); | |
static readonly Regex ShareContainerQueueRegex = new Regex("^[a-z0-9]+(-[a-z0-9]+)*$", RegexOptions); | |
static readonly Regex TableRegex = new Regex("^[A-Za-z][A-Za-z0-9]*$", RegexOptions); | |
static readonly Regex MetricsTableRegex = new Regex(@"^\$Metrics(HourPrimary|MinutePrimary|HourSecondary|MinuteSecondary)?(Transactions)(Blob|Queue|Table)$", RegexOptions); | |
const string InvalidResourceName = "Invalid {0} name. Check MSDN for more information about valid {0} naming."; | |
const string Table = "table"; | |
const string InvalidResourceNameLength = "Invalid {0} name length. The {0} name must be between {1} and {2} characters long."; | |
const string ResourceNameEmpty = "Invalid {0} name. The {0} name may not be null, empty, or whitespace only."; | |
const string File = "file"; | |
const string InvalidResourceReservedName = "Invalid {0} name. This {0} name is reserved."; | |
const string Share = "share"; | |
const string Directory = "directory"; | |
const string Blob = "blob"; | |
const string Queue = "queue"; | |
const string Container = "container"; | |
const string TooManyPathSegments = "The count of URL path segments (strings between '/' characters) as part of the blob name cannot exceed 254."; | |
#endregion | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment