Skip to content

Commit a40325d

Browse files
committed
.NET Standard 2.0 compatibility fix
1 parent 0857b94 commit a40325d

File tree

1 file changed

+31
-46
lines changed

1 file changed

+31
-46
lines changed

src/ModelContextProtocol/Authentication/AuthorizationHelpers.cs

Lines changed: 31 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public class AuthorizationHelpers
1515
private static readonly Lazy<HttpClient> _defaultHttpClient = new(() => new HttpClient());
1616

1717
/// <summary>
18-
/// The common well-known path prefix for resource metadata.
18+
/// The well-known path prefix for resource metadata.
1919
/// </summary>
2020
private static readonly string WellKnownPathPrefix = "/.well-known/";
2121

@@ -82,30 +82,27 @@ private static bool VerifyResourceMatch(ProtectedResourceMetadata protectedResou
8282
}
8383

8484
/// <summary>
85-
/// Normalizes a URI for consistent comparison by removing ports and trailing slashes.
85+
/// Normalizes a URI for consistent comparison.
8686
/// </summary>
8787
/// <param name="uri">The URI to normalize.</param>
8888
/// <returns>A normalized string representation of the URI.</returns>
8989
private static string NormalizeUri(Uri uri)
9090
{
91-
// Create a builder that will normalize the URI
9291
var builder = new UriBuilder(uri)
9392
{
94-
Port = -1 // Always remove port specification regardless of whether it's default or not
93+
Port = -1 // Always remove port
9594
};
9695

97-
// Ensure consistent path representation (remove trailing slash if it's just "/")
9896
if (builder.Path == "/")
9997
{
10098
builder.Path = string.Empty;
10199
}
102-
// Remove trailing slash for other paths
103100
else if (builder.Path.Length > 1 && builder.Path.EndsWith("/"))
104101
{
105102
builder.Path = builder.Path.TrimEnd('/');
106103
}
107104

108-
return builder.Uri.ToString().TrimEnd('/');
105+
return builder.Uri.ToString();
109106
}
110107

111108
/// <summary>
@@ -116,38 +113,27 @@ private static string NormalizeUri(Uri uri)
116113
/// <exception cref="InvalidOperationException">Thrown when the URI does not contain a valid well-known path.</exception>
117114
private Uri ExtractBaseResourceUri(Uri metadataUri)
118115
{
119-
// Get the absolute URI path to check for well-known path
120-
string absoluteUriString = metadataUri.AbsoluteUri;
116+
// Check for well-known path
117+
int wellKnownIndex = metadataUri.AbsolutePath.IndexOf(WellKnownPathPrefix, StringComparison.OrdinalIgnoreCase);
121118

122-
// Find the well-known path index directly with string operations
123-
// This avoids the allocation from WellKnownPathPrefix.AsSpan()
124-
int wellKnownIndex = absoluteUriString.IndexOf(WellKnownPathPrefix, StringComparison.OrdinalIgnoreCase);
125-
126-
// Validate that the URL contains the well-known path
127-
if (wellKnownIndex <= 0)
119+
// Validate the URL contains a valid well-known path
120+
if (wellKnownIndex < 0)
128121
{
129122
throw new InvalidOperationException(
130123
$"Resource metadata URL '{metadataUri}' does not contain a valid well-known path format (/.well-known/)");
131124
}
132125

133-
// Get just the path segment before .well-known directly on the URI
134-
int wellKnownPathIndex = metadataUri.AbsolutePath.IndexOf(WellKnownPathPrefix, StringComparison.OrdinalIgnoreCase);
135-
136-
// Create a new URI builder using the original scheme and authority
126+
// Create URI with just the base part
137127
var baseUriBuilder = new UriBuilder(metadataUri)
138128
{
139-
Path = wellKnownPathIndex > 0 ? metadataUri.AbsolutePath.Substring(0, wellKnownPathIndex) : "/",
129+
Path = wellKnownIndex > 0 ? metadataUri.AbsolutePath.Substring(0, wellKnownIndex) : "/",
140130
Fragment = string.Empty,
141-
Query = string.Empty
131+
Query = string.Empty,
132+
Port = -1 // Remove port
142133
};
143134

144-
// Ensure the path ends with exactly one slash for consistency
145-
string path = baseUriBuilder.Path;
146-
if (string.IsNullOrEmpty(path))
147-
{
148-
baseUriBuilder.Path = "/";
149-
}
150-
else if (!path.EndsWith("/"))
135+
// Ensure path ends with a slash
136+
if (!baseUriBuilder.Path.EndsWith("/"))
151137
{
152138
baseUriBuilder.Path += "/";
153139
}
@@ -230,35 +216,34 @@ public async Task<ProtectedResourceMetadata> ExtractProtectedResourceMetadata(
230216
/// <returns>The value of the parameter, or null if not found.</returns>
231217
private static string? ParseWwwAuthenticateParameters(string parameters, string parameterName)
232218
{
233-
if (!parameters.Contains(parameterName, StringComparison.OrdinalIgnoreCase))
219+
if (parameters.IndexOf(parameterName, StringComparison.OrdinalIgnoreCase) == -1)
234220
{
235221
return null;
236222
}
237223

238-
var parts = parameters.Split(',');
239-
foreach (var part in parts)
224+
foreach (var part in parameters.Split(','))
240225
{
241-
int equalsIndex = part.IndexOf('=');
242-
if (equalsIndex <= 0 || equalsIndex == part.Length - 1)
243-
{
244-
continue;
245-
}
226+
string trimmedPart = part.Trim();
227+
int equalsIndex = trimmedPart.IndexOf('=');
246228

247-
string key = part.Substring(0, equalsIndex).Trim();
248-
249-
if (string.IsNullOrEmpty(key) || !string.Equals(key, parameterName, StringComparison.OrdinalIgnoreCase))
229+
if (equalsIndex <= 0)
250230
{
251231
continue;
252232
}
253-
254-
string value = part.Substring(equalsIndex + 1).Trim();
255-
256-
if (value.Length >= 2 && value[0] == '"' && value[^1] == '"')
233+
234+
string key = trimmedPart.Substring(0, equalsIndex).Trim();
235+
236+
if (string.Equals(key, parameterName, StringComparison.OrdinalIgnoreCase))
257237
{
258-
value = value.Substring(1, value.Length - 2);
238+
string value = trimmedPart.Substring(equalsIndex + 1).Trim();
239+
240+
if (value.StartsWith("\"") && value.EndsWith("\""))
241+
{
242+
value = value.Substring(1, value.Length - 2);
243+
}
244+
245+
return value;
259246
}
260-
261-
return value;
262247
}
263248

264249
return null;

0 commit comments

Comments
 (0)