private string GetDecodedString(ReadOnlySpan <byte> readOnlySpan) { if (readOnlySpan.Length == 0) { return(string.Empty); } else if (_encoding == Encoding.UTF8 || _encoding == Encoding.ASCII) { // UrlDecoder only works on UTF8 (and implicitly ASCII) // We need to create a Span from a ReadOnlySpan. This cast is safe because the memory is still held by the pipe // We will also create a string from it by the end of the function. var span = MemoryMarshal.CreateSpan(ref Unsafe.AsRef(readOnlySpan[0]), readOnlySpan.Length); var bytes = UrlDecoder.DecodeInPlace(span, isFormEncoding: true); span = span.Slice(0, bytes); return(_encoding.GetString(span)); } else { // Slow path for Unicode and other encodings. // Just do raw string replacement. var decodedString = _encoding.GetString(readOnlySpan); decodedString = decodedString.Replace('+', ' '); return(Uri.UnescapeDataString(decodedString)); } }
[InlineData("%ED%A0%81")] // Invalid range 0xD800-0xDFFF public void ByteOutOfUtf8RangeDecodeInPlaceLeavesUnencoded(string input) { var source = Encoding.UTF8.GetBytes(input.ToCharArray()); var length = UrlDecoder.DecodeInPlace(source.AsSpan(), true); Assert.Equal(source.Length, length); Assert.True(source.AsSpan(0, length).SequenceEqual(Encoding.UTF8.GetBytes(input).AsSpan())); }
[InlineData("%ED%A0%81")] // Invalid range 0xD800-0xDFFF public void StringOutOfUtf8RangeDecodeInPlaceLeavesUnencoded(string input) { var source = input.ToCharArray(); var length = UrlDecoder.DecodeInPlace(source.AsSpan()); Assert.Equal(input.Length, length); Assert.True(source.AsSpan(0, length).SequenceEqual(input.AsSpan())); }
public void ByteFormsEncodingDecodeInPlaceDecodesPercent2F(string input) { var source = Encoding.UTF8.GetBytes(input.ToCharArray()); var length = UrlDecoder.DecodeInPlace(source.AsSpan(), true); Assert.Equal(1, length); Assert.True(source.AsSpan(0, length).SequenceEqual(Encoding.UTF8.GetBytes("/").AsSpan())); }
public void ByteDecodeInPlace(byte[] input, byte[] expected) { var destination = new byte[input.Length]; input.AsSpan().CopyTo(destination); int length = UrlDecoder.DecodeInPlace(destination.AsSpan(), false); Assert.True(destination.AsSpan(0, length).SequenceEqual(expected.AsSpan())); }
public void StringDecodeInPlace(string input, string expected) { var destination = new char[input.Length]; input.CopyTo(destination); int length = UrlDecoder.DecodeInPlace(destination.AsSpan()); Assert.True(destination.AsSpan(0, length).SequenceEqual(expected.AsSpan())); }
public static string DecodePath(Span <byte> path, bool pathEncoded, string rawTarget, int queryLength) { int pathLength; if (pathEncoded) { // URI was encoded, unescape and then parse as UTF-8 // Disabling warning temporary pathLength = UrlDecoder.DecodeInPlace(path); // Removing dot segments must be done after unescaping. From RFC 3986: // // URI producing applications should percent-encode data octets that // correspond to characters in the reserved set unless these characters // are specifically allowed by the URI scheme to represent data in that // component. If a reserved character is found in a URI component and // no delimiting role is known for that character, then it must be // interpreted as representing the data octet corresponding to that // character's encoding in US-ASCII. // // https://tools.ietf.org/html/rfc3986#section-2.2 pathLength = RemoveDotSegments(path.Slice(0, pathLength)); return(GetUtf8String(path.Slice(0, pathLength))); } pathLength = RemoveDotSegments(path); if (path.Length == pathLength && queryLength == 0) { // If no decoding was required, no dot segments were removed and // there is no query, the request path is the same as the raw target return(rawTarget); } return(path.Slice(0, pathLength).GetAsciiStringNonNullCharacters()); }
public void StringInputNullCharDecodeInPlaceThrows() { var source = "%00".ToCharArray(); Assert.Throws <InvalidOperationException>(() => UrlDecoder.DecodeInPlace(source.AsSpan())); }
public void ByteInputNullCharDecodeInPlaceThrows() { var source = Encoding.UTF8.GetBytes("%00"); Assert.Throws <InvalidOperationException>(() => UrlDecoder.DecodeInPlace(source.AsSpan(), false)); }