diff --git a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultKeyValueAdapter.cs b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultKeyValueAdapter.cs index a272b413f..0498ba09e 100644 --- a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultKeyValueAdapter.cs +++ b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureKeyVaultReference/AzureKeyVaultKeyValueAdapter.cs @@ -4,9 +4,12 @@ using Azure; using Azure.Data.AppConfiguration; using Azure.Security.KeyVault.Secrets; +using Microsoft.Extensions.Configuration.AzureAppConfiguration.Extensions; +using Microsoft.Extensions.Configuration.AzureAppConfiguration.FeatureManagement; using System; using System.Collections.Generic; using System.Linq; +using System.Net.Mime; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -72,8 +75,15 @@ KeyVaultReferenceException CreateKeyVaultReferenceException(string message, Conf public bool CanProcess(ConfigurationSetting setting) { - string contentType = setting?.ContentType?.Split(';')[0].Trim(); - return string.Equals(contentType, KeyVaultConstants.ContentType); + if (setting == null || + string.IsNullOrWhiteSpace(setting.Value) || + string.IsNullOrWhiteSpace(setting.ContentType)) + { + return false; + } + + return setting.ContentType.TryParseContentType(out ContentType contentType) + && contentType.IsKeyVaultReference(); } public void OnChangeDetected(ConfigurationSetting setting = null) diff --git a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/Extensions/ContentTypeExtensions.cs b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/Extensions/ContentTypeExtensions.cs index 2f739a52c..ca2a9d539 100644 --- a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/Extensions/ContentTypeExtensions.cs +++ b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/Extensions/ContentTypeExtensions.cs @@ -12,16 +12,12 @@ namespace Microsoft.Extensions.Configuration.AzureAppConfiguration.Extensions { internal static class ContentTypeExtensions { - private static readonly IEnumerable ExcludedJsonContentTypes = new[] - { - FeatureManagementConstants.ContentType, - KeyVaultConstants.ContentType - }; - public static bool IsAi(this ContentType contentType) { return contentType != null && contentType.IsJson() && + !contentType.IsFeatureFlag() && + !contentType.IsKeyVaultReference() && contentType.Parameters.ContainsKey("profile") && !string.IsNullOrEmpty(contentType.Parameters["profile"]) && contentType.Parameters["profile"].StartsWith(RequestTracingConstants.AIMimeProfile); @@ -31,6 +27,8 @@ public static bool IsAiChatCompletion(this ContentType contentType) { return contentType != null && contentType.IsJson() && + !contentType.IsFeatureFlag() && + !contentType.IsKeyVaultReference() && contentType.Parameters.ContainsKey("profile") && !string.IsNullOrEmpty(contentType.Parameters["profile"]) && contentType.Parameters["profile"].StartsWith(RequestTracingConstants.AIChatCompletionMimeProfile); @@ -45,37 +43,43 @@ public static bool IsJson(this ContentType contentType) string acceptedMainType = "application"; string acceptedSubType = "json"; - string mediaType = contentType.MediaType; - - if (!ExcludedJsonContentTypes.Contains(mediaType, StringComparer.OrdinalIgnoreCase)) - { - ReadOnlySpan mediaTypeSpan = mediaType.AsSpan(); - // Since contentType has been validated using System.Net.Mime.ContentType, - // mediaType will always have exactly 2 parts after splitting on '/' - int slashIndex = mediaTypeSpan.IndexOf('/'); + ReadOnlySpan mediaTypeSpan = contentType.MediaType.AsSpan(); - if (mediaTypeSpan.Slice(0, slashIndex).Equals(acceptedMainType.AsSpan(), StringComparison.OrdinalIgnoreCase)) - { - ReadOnlySpan subTypeSpan = mediaTypeSpan.Slice(slashIndex + 1); + // Since contentType has been validated using System.Net.Mime.ContentType, + // mediaType will always have exactly 2 parts after splitting on '/' + int slashIndex = mediaTypeSpan.IndexOf('/'); - while (!subTypeSpan.IsEmpty) - { - int plusIndex = subTypeSpan.IndexOf('+'); + if (mediaTypeSpan.Slice(0, slashIndex).Equals(acceptedMainType.AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + ReadOnlySpan subTypeSpan = mediaTypeSpan.Slice(slashIndex + 1); - ReadOnlySpan currentSubType = plusIndex == -1 ? subTypeSpan : subTypeSpan.Slice(0, plusIndex); + while (!subTypeSpan.IsEmpty) + { + int plusIndex = subTypeSpan.IndexOf('+'); - if (currentSubType.Equals(acceptedSubType.AsSpan(), StringComparison.OrdinalIgnoreCase)) - { - return true; - } + ReadOnlySpan currentSubType = plusIndex == -1 ? subTypeSpan : subTypeSpan.Slice(0, plusIndex); - subTypeSpan = plusIndex == -1 ? ReadOnlySpan.Empty : subTypeSpan.Slice(plusIndex + 1); + if (currentSubType.Equals(acceptedSubType.AsSpan(), StringComparison.OrdinalIgnoreCase)) + { + return true; } + + subTypeSpan = plusIndex == -1 ? ReadOnlySpan.Empty : subTypeSpan.Slice(plusIndex + 1); } } return false; } + + public static bool IsFeatureFlag(this ContentType contentType) + { + return contentType.MediaType.Equals(FeatureManagementConstants.ContentType); + } + + public static bool IsKeyVaultReference(this ContentType contentType) + { + return contentType.MediaType.Equals(KeyVaultConstants.ContentType); + } } } diff --git a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/FeatureManagement/FeatureManagementKeyValueAdapter.cs b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/FeatureManagement/FeatureManagementKeyValueAdapter.cs index b6d137f38..76ab04e4a 100644 --- a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/FeatureManagement/FeatureManagementKeyValueAdapter.cs +++ b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/FeatureManagement/FeatureManagementKeyValueAdapter.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Mime; using System.Security.Cryptography; using System.Text; using System.Text.Json; @@ -45,10 +46,20 @@ public Task>> ProcessKeyValue(Configura public bool CanProcess(ConfigurationSetting setting) { - string contentType = setting?.ContentType?.Split(';')[0].Trim(); + if (setting == null || + string.IsNullOrWhiteSpace(setting.Value) || + string.IsNullOrWhiteSpace(setting.ContentType)) + { + return false; + } + + if (setting.Key.StartsWith(FeatureManagementConstants.FeatureFlagMarker)) + { + return true; + } - return string.Equals(contentType, FeatureManagementConstants.ContentType) || - setting.Key.StartsWith(FeatureManagementConstants.FeatureFlagMarker); + return setting.ContentType.TryParseContentType(out ContentType contentType) && + contentType.IsFeatureFlag(); } public bool NeedsRefresh() diff --git a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/JsonKeyValueAdapter.cs b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/JsonKeyValueAdapter.cs index 87c28d698..74d2b882a 100644 --- a/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/JsonKeyValueAdapter.cs +++ b/src/Microsoft.Extensions.Configuration.AzureAppConfiguration/JsonKeyValueAdapter.cs @@ -53,7 +53,9 @@ public bool CanProcess(ConfigurationSetting setting) if (setting.ContentType.TryParseContentType(out ContentType contentType)) { - return contentType.IsJson(); + return contentType.IsJson() && + !contentType.IsFeatureFlag() && + !contentType.IsKeyVaultReference(); } return false;