diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.cs index e059ce638f..463ce0a237 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Http/Frame.cs @@ -1228,7 +1228,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http if (needDecode) { // Read raw target before mutating memory. - rawTarget = target.GetAsciiString() ?? string.Empty; + rawTarget = target.GetAsciiStringNonNullCharacters(); // URI was encoded, unescape and then parse as utf8 int pathLength = UrlEncoder.Decode(path, path); @@ -1237,7 +1237,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http else { // URI wasn't encoded, parse as ASCII - requestUrlPath = path.GetAsciiString() ?? string.Empty; + requestUrlPath = path.GetAsciiStringNonNullCharacters(); if (query.Length == 0) { @@ -1247,21 +1247,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http } else { - rawTarget = target.GetAsciiString() ?? string.Empty; + rawTarget = target.GetAsciiStringNonNullCharacters(); } } var normalizedTarget = PathNormalizer.RemoveDotSegments(requestUrlPath); if (method != HttpMethod.Custom) { - Method = HttpUtilities.MethodToString(method) ?? String.Empty; + Method = HttpUtilities.MethodToString(method) ?? string.Empty; } else { - Method = customMethod.GetAsciiString() ?? string.Empty; + Method = customMethod.GetAsciiStringNonNullCharacters(); } - QueryString = query.GetAsciiString() ?? string.Empty; + QueryString = query.GetAsciiStringNonNullCharacters(); RawTarget = rawTarget; HttpVersion = HttpUtilities.VersionToString(version); @@ -1289,7 +1289,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http { RejectRequest(RequestRejectionReason.TooManyHeaders); } - var valueString = value.GetAsciiString() ?? string.Empty; + var valueString = value.GetAsciiStringNonNullCharacters(); FrameRequestHeaders.Append(name, valueString); } diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Infrastructure/HttpUtilities.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Infrastructure/HttpUtilities.cs index 719e27eff4..e38ad9fd6e 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Infrastructure/HttpUtilities.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Internal/Infrastructure/HttpUtilities.cs @@ -94,6 +94,28 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure } } + public unsafe static string GetAsciiStringNonNullCharacters(this Span span) + { + if (span.IsEmpty) + { + return string.Empty; + } + + var asciiString = new string('\0', span.Length); + + fixed (char* output = asciiString) + fixed (byte* buffer = &span.DangerousGetPinnableReference()) + { + // This version if AsciiUtilities returns null if there are any null (0 byte) characters + // in the string + if (!AsciiUtilities.TryGetAsciiString(buffer, output, span.Length)) + { + throw new InvalidOperationException(); + } + } + return asciiString; + } + public static string GetAsciiStringEscaped(this Span span, int maxChars) { var sb = new StringBuilder();