/
githubmirror
/
aspnetcore
Обзор
Документация
Войти
/
githubmirror
/
aspnetcore
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Shared/test/Shared.Tests/UrlDecoderTests.cs
199 строк
7 KB
Korolev Dmitry
Antiforgery perf improvements (includes new DataProtection API usage) (#64751)
29 янв 2026, 23:38
Не верифицирован
29 янв 2026, 23:38
f87c18f
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Text; using Microsoft.AspNetCore.Internal; namespace Microsoft.AspNetCore.Shared.Tests; public class UrlDecoderTests { [Theory] [MemberData(nameof(PathTestData))] public void StringDecodeRequestLine(string input, string expected) { var destination = new char[input.Length]; int length = UrlDecoder.DecodeRequestLine(input.AsSpan(), destination.AsSpan()); Assert.True(destination.AsSpan(0, length).SequenceEqual(expected.AsSpan())); } [Theory] [MemberData(nameof(UriTestData))] public void ByteDecodeRequestLine(byte[] input, byte[] expected) { var destination = new byte[input.Length]; int length = UrlDecoder.DecodeRequestLine(input.AsSpan(), destination.AsSpan(), false); Assert.True(destination.AsSpan(0, length).SequenceEqual(expected.AsSpan())); } [Theory] [MemberData(nameof(PathTestData))] 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())); } [Theory] [MemberData(nameof(UriTestData))] 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())); } [Fact] public void StringDestinationShorterThanSourceDecodeRequestLineThrows() { var source = new char[2]; Assert.Throws<ArgumentException>(() => UrlDecoder.DecodeRequestLine(source.AsSpan(), source.AsSpan(0, 1))); } [Fact] public void ByteDestinationShorterThanSourceDecodeRequestLineThrows() { var source = new byte[2]; Assert.Throws<ArgumentException>(() => UrlDecoder.DecodeRequestLine(source.AsSpan(), source.AsSpan(0, 1), false)); } [Fact] public void StringDestinationLargerThanSourceDecodeRequestLineReturnsCorrectLength() { var source = "/a%20b".ToCharArray(); var length = UrlDecoder.DecodeRequestLine(source.AsSpan(), new char[source.Length + 10]); Assert.Equal(4, length); } [Fact] public void ByteDestinationLargerThanSourceDecodeRequestLineReturnsCorrectLength() { var source = Encoding.UTF8.GetBytes("/a%20b".ToCharArray()); var length = UrlDecoder.DecodeRequestLine(source.AsSpan(), new byte[source.Length + 10], false); Assert.Equal(4, length); } [Fact] public void StringInputNullCharDecodeInPlaceThrows() { var source = "%00".ToCharArray(); Assert.Throws<InvalidOperationException>(() => UrlDecoder.DecodeInPlace(source.AsSpan())); } [Fact] public void ByteInputNullCharDecodeInPlaceThrows() { var source = Encoding.UTF8.GetBytes("%00"); Assert.Throws<InvalidOperationException>(() => UrlDecoder.DecodeInPlace(source.AsSpan(), false)); } [Theory] [InlineData("%$$")] [InlineData("%1")] [InlineData("%1$")] [InlineData("%%1")] [InlineData("%%1$")] public void StringInputNonHexDecodeInPlaceLeavesUnencoded(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())); } [Theory] [InlineData("%$$")] [InlineData("%1")] [InlineData("%1$")] [InlineData("%%1")] [InlineData("%%1$")] public void ByteInputNonHexDecodeInPlaceLeavesUnencoded(string input) { var source = Encoding.UTF8.GetBytes(input.ToCharArray()); var length = UrlDecoder.DecodeInPlace(source.AsSpan(), false); Assert.Equal(source.Length, length); Assert.True(source.AsSpan(0, length).SequenceEqual(Encoding.UTF8.GetBytes(input).AsSpan())); } [Theory] [InlineData("%2F")] 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())); } [Theory] [InlineData("%FF%FF%FF%FF")] // FF invalid first byte [InlineData("%F7%BF%BF%BF")] // beyond 0x10FFFF [InlineData("%F7%C0")] // Following byte does not start with 10xx xxxx [InlineData("%F0%81")] // Not enough bytes [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())); } [Theory] [InlineData("%FF%FF%FF%FF")] // FF invalid first byte [InlineData("%F7%BF%BF%BF")] // beyond 0x10FFFF [InlineData("%F7%C0")] // Following byte does not start with 10xx xxxx [InlineData("%F0%81")] // Not enough bytes [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())); } public static IEnumerable<object[]> PathTestData { get { return new List<object[]>() { new[] { "hello", "hello" }, new[] { "/", "/" }, new[] { "http://localhost:5000/api", "http://localhost:5000/api" }, new[] { "/api/abc", "/api/abc" }, new[] { "/api/a%2Fb", "/api/a%2Fb" }, new[] { "/a%20b", "/a b" }, new[] { "/a%24b", "/a$b" }, new[] { "/a%C2%A2b", "/a¢b" }, new[] { "/a%E0%A4%B9b", "/aहb" }, new[] { "/a%E2%82%ACb", "/a€b" }, new[] { "/a%ED%95%9Cb", "/a한b" }, new[] { "/a%F0%90%8D%88b", "/a𐍈b" }, new[] { "/a%25b", "/a%b" }, new[] { "/%E4%BD%A0%E5%A5%BD", "/你好" }, new[] { "/a%%2Fb", "/a%%2Fb" }, new[] { "/a%2Fb+c", "/a%2Fb+c" }, new[] { "/%C3%C3%A1", "/%C3á" }, new[] { "/a%20%%b", "/a %%b" }, }; } } public static IEnumerable<object[]> UriTestData { get { return PathTestData.Select(x => { var input = Encoding.UTF8.GetBytes((string)x[0]); var expected = Encoding.UTF8.GetBytes((string)x[1]); return new[] { input, expected }; }); } } }