Remove unnecessary length restriction on Uri.Escape{Data/Uri}String (dotnet/corefx...
authorStephen Toub <stoub@microsoft.com>
Thu, 10 Oct 2019 10:03:29 +0000 (06:03 -0400)
committerGitHub <noreply@github.com>
Thu, 10 Oct 2019 10:03:29 +0000 (06:03 -0400)
* Remove unnecessary length restriction on Uri.Escape{Data/Uri}String

* Address PR feedback

Co-Authored-By: David Shulman <david.shulman@microsoft.com>
Commit migrated from https://github.com/dotnet/corefx/commit/1d49632bc213416d27ed6c567fd8dd08e00170a1

src/libraries/System.Net.Http/tests/FunctionalTests/FormUrlEncodedContentTest.cs
src/libraries/System.Private.Uri/src/System/UriHelper.cs
src/libraries/System.Private.Uri/tests/FunctionalTests/IriTest.cs
src/libraries/System.Private.Uri/tests/FunctionalTests/UriEscapingTest.cs
src/libraries/System.Runtime/tests/System/Uri.MethodsTests.cs

index fa505a0..be116ff 100644 (file)
@@ -4,7 +4,6 @@
 
 using System;
 using System.Collections.Generic;
-using System.Linq;
 using System.IO;
 using System.Text;
 using System.Threading.Tasks;
@@ -37,6 +36,17 @@ namespace System.Net.Http.Functional.Tests
             Assert.Equal(0, stream.Length);
         }
 
+        [Theory]
+        [InlineData('F', ushort.MaxValue + 10)]
+        [InlineData('/', ushort.MaxValue + 10)]
+        public async Task Ctor_LongSource_Succeed(char c, int length)
+        {
+            const string Key = "test";
+            var value = new string(c, length);
+            var content = new FormUrlEncodedContent(new Dictionary<string, string> { { Key, value } });
+            Assert.Equal($"{Key}={Uri.EscapeDataString(value)}", await content.ReadAsStringAsync());
+        }
+
         [Fact]
         public async Task Ctor_OneEntry_SeparatedByEquals()
         {
index cbb5046..b26c7b0 100644 (file)
@@ -134,9 +134,6 @@ namespace System
         internal static unsafe char[]? EscapeString(string input, int start, int end, char[]? dest, ref int destPos,
             bool isUriString, char force1, char force2, char rsvd)
         {
-            if (end - start >= Uri.c_MaxUriBufferSize)
-                throw new UriFormatException(SR.net_uri_SizeLimit);
-
             int i = start;
             int prevInputPos = start;
             byte* bytes = stackalloc byte[c_MaxUnicodeCharsReallocate * c_MaxUTF_8BytesPerUnicodeChar];   // 40*4=160
index 103e17e..99354ce 100644 (file)
@@ -495,36 +495,24 @@ namespace System.PrivateUri.Tests
             { }
         }
 
-        [Fact]
-        public void Iri_ValidateVeryLongInputString_EscapeDataString()
+        [Theory]
+        [InlineData(maxUriLength)]
+        [InlineData(maxUriLength + 1)]
+        [InlineData(10 + ushort.MaxValue)]
+        public void Iri_ValidateVeryLongInputString_EscapeDataString(int length)
         {
-            string bigString1 = GetUnicodeString(0, maxUriLength, 1);
-            Assert.True(Uri.EscapeDataString(bigString1).Length > bigString1.Length);
-
-            try
-            {
-                string bigString2 = GetUnicodeString(0, maxUriLength + 1, 1);
-                Uri.EscapeDataString(bigString2);
-                Assert.False(true, "Expected UriFormatException: Uri too large");
-            }
-            catch (FormatException)
-            { }
+            string s = GetUnicodeString(0, length, 1);
+            Assert.InRange(Uri.EscapeDataString(s).Length, s.Length + 1, int.MaxValue);
         }
 
-        [Fact]
-        public void Iri_ValidateVeryLongInputString_EscapeUriString()
+        [Theory]
+        [InlineData(maxUriLength)]
+        [InlineData(maxUriLength + 1)]
+        [InlineData(10 + ushort.MaxValue)]
+        public void Iri_ValidateVeryLongInputString_EscapeUriString(int length)
         {
-            string bigString1 = GetUnicodeString(0, maxUriLength, 1);
-            Assert.True(Uri.EscapeUriString(bigString1).Length > bigString1.Length);
-
-            try
-            {
-                string bigString2 = GetUnicodeString(0, maxUriLength + 1, 1);
-                Uri.EscapeUriString(bigString2);
-                Assert.False(true, "Expected UriFormatException: Uri too large");
-            }
-            catch (FormatException)
-            { }
+            string s = GetUnicodeString(0, length, 1);
+            Assert.InRange(Uri.EscapeUriString(s).Length, s.Length + 1, int.MaxValue);
         }
 
         [Theory]
index 05a3af5..87a81c3 100644 (file)
@@ -2,8 +2,10 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
-using System.Text;
 using System.Common.Tests;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
 
 using Xunit;
 
@@ -106,6 +108,26 @@ namespace System.PrivateUri.Tests
             }
         }
 
+        public static IEnumerable<object[]> UriEscapeUnescapeDataString_Roundtrip_MemberData()
+        {
+            // Test the no-longer-existing "c_MaxUriBufferSize" limit of 0xFFF0,
+            // as well as lengths longer than the max Uri length of ushort.MaxValue.
+            foreach (int length in new[] { 1, 0xFFF0, 0xFFF1, ushort.MaxValue + 10 })
+            {
+                yield return new object[] { new string('s', length), string.Concat(Enumerable.Repeat("s", length)) };
+                yield return new object[] { new string('/', length), string.Concat(Enumerable.Repeat("%2F", length)) };
+            }
+        }
+
+        [Theory]
+        [MemberData(nameof(UriEscapeUnescapeDataString_Roundtrip_MemberData))]
+        public void UriEscapeUnescapeDataString_Roundtrip(string input, string expectedEscaped)
+        {
+            string output = Uri.EscapeDataString(input);
+            Assert.Equal(expectedEscaped, output);
+            Assert.Equal(input, Uri.UnescapeDataString(output));
+        }
+
         #endregion EscapeDataString
 
         #region UnescapeDataString
@@ -286,6 +308,24 @@ namespace System.PrivateUri.Tests
             Assert.Equal(input, output);
         }
 
+        public static IEnumerable<object[]> UriEscapingUriString_Long_MemberData()
+        {
+            // Test the no-longer-existing "c_MaxUriBufferSize" limit of 0xFFF0,
+            // as well as lengths longer than the max Uri length of ushort.MaxValue.
+            foreach (int length in new[] { 1, 0xFFF0, 0xFFF1, ushort.MaxValue + 10 })
+            {
+                yield return new object[] { new string('s', length), string.Concat(Enumerable.Repeat("s", length)) };
+                yield return new object[] { new string('<', length), string.Concat(Enumerable.Repeat("%3C", length)) };
+            }
+        }
+
+        [Theory]
+        [MemberData(nameof(UriEscapingUriString_Long_MemberData))]
+        public void UriEscapingUriString_Long_Escaped(string input, string expectedEscaped)
+        {
+            Assert.Equal(expectedEscaped, Uri.EscapeUriString(input));
+        }
+
         #endregion EscapeUriString
 
         #region AbsoluteUri escaping
index aac30b3..241c420 100644 (file)
@@ -3,6 +3,7 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Collections.Generic;
+using System.Linq;
 using System.Runtime.InteropServices;
 using Xunit;
 
@@ -421,10 +422,22 @@ namespace System.Tests
         }
 
         [Fact]
+        public void EscapeDataString_Long_Success()
+        {
+            string s;
+            const int LongCount = 65520 + 1;
+
+            s = new string('a', LongCount);
+            Assert.Equal(s, Uri.EscapeDataString(s));
+
+            s = new string('/', LongCount);
+            Assert.Equal(string.Concat(Enumerable.Repeat("%2F", LongCount)), Uri.EscapeDataString(s));
+        }
+
+        [Fact]
         public void EscapeDataString_Invalid()
         {
             AssertExtensions.Throws<ArgumentNullException>("stringToEscape", () => Uri.EscapeDataString(null)); // StringToEscape is null
-            Assert.Throws<UriFormatException>(() => Uri.EscapeDataString(UriCreateStringTests.s_longString)); // StringToEscape is too long
 
             Assert.Throws<UriFormatException>(() => Uri.EscapeDataString("\uD800")); // Incomplete surrogate pair provided
             Assert.Throws<UriFormatException>(() => Uri.EscapeDataString("abc\uD800")); // Incomplete surrogate pair provided
@@ -463,10 +476,22 @@ namespace System.Tests
         }
 
         [Fact]
+        public void EscapeUriString_Long_Success()
+        {
+            string s;
+            const int LongCount = 65520 + 1;
+
+            s = new string('a', LongCount);
+            Assert.Equal(s, Uri.EscapeUriString(s));
+
+            s = new string('<', LongCount);
+            Assert.Equal(string.Concat(Enumerable.Repeat("%3C", LongCount)), Uri.EscapeUriString(s));
+        }
+
+        [Fact]
         public void EscapeUriString_Invalid()
         {
             AssertExtensions.Throws<ArgumentNullException>("stringToEscape", () => Uri.EscapeUriString(null)); // StringToEscape is null
-            Assert.Throws<UriFormatException>(() => Uri.EscapeUriString(UriCreateStringTests.s_longString)); // StringToEscape is too long
 
             Assert.Throws<UriFormatException>(() => Uri.EscapeUriString("\uD800")); // Incomplete surrogate pair provided
             Assert.Throws<UriFormatException>(() => Uri.EscapeUriString("abc\uD800")); // Incomplete surrogate pair provided