diff --git a/aspnetcore-features/UrlEncodingAndDecoding/Tests/Tests.csproj b/aspnetcore-features/UrlEncodingAndDecoding/Tests/Tests.csproj index c5ecdf5955..8226e5e78e 100644 --- a/aspnetcore-features/UrlEncodingAndDecoding/Tests/Tests.csproj +++ b/aspnetcore-features/UrlEncodingAndDecoding/Tests/Tests.csproj @@ -1,7 +1,7 @@ - net7.0 + net10.0 enable enable @@ -10,10 +10,10 @@ - - - - + + + + diff --git a/aspnetcore-features/UrlEncodingAndDecoding/Tests/UrlEncodingDecodingUnitTest.cs b/aspnetcore-features/UrlEncodingAndDecoding/Tests/UrlEncodingDecodingUnitTest.cs index 1003e561b8..ac6e1395e4 100644 --- a/aspnetcore-features/UrlEncodingAndDecoding/Tests/UrlEncodingDecodingUnitTest.cs +++ b/aspnetcore-features/UrlEncodingAndDecoding/Tests/UrlEncodingDecodingUnitTest.cs @@ -1,4 +1,5 @@ using System.Net; +using System.Text.Encodings.Web; using System.Web; namespace Tests @@ -22,7 +23,7 @@ public void GivenAUrl_WhenEncodingWithHttpUtility_ThenCharactersEncoded() [DataRow(EncodedUrlLowerPlus)] [DataRow(EncodedUrlUpperPercent)] [DataRow(EncodedUrlUpperPlus)] - [DataTestMethod] + [TestMethod] public void GivenAUrl_WhenDecodingWithHttpUtility_ThenCharactersDecoded(string encodedUrl) { var decoded = HttpUtility.UrlDecode(encodedUrl); @@ -41,7 +42,7 @@ public void GivenAUrl_WhenEncodingWithWebUtility_ThenCharactersEncoded() [DataRow(EncodedUrlLowerPlus)] [DataRow(EncodedUrlUpperPercent)] [DataRow(EncodedUrlUpperPlus)] - [DataTestMethod] + [TestMethod] public void GivenAUrl_WhenDecodingWithWebUtility_ThenCharactersDecoded(string encodedUrl) { var decoded = WebUtility.UrlDecode(encodedUrl); @@ -58,7 +59,7 @@ public void GivenAUrl_WhenEncodingWithUri_ThenCharactersEncoded() } [DataRow(EncodedUrlUpperPercent)] - [DataTestMethod] + [TestMethod] public void GivenAUrl_WhenDecodingWithUri_ThenCharactersDecoded(string encodedUrl) { var decoded = Uri.UnescapeDataString(encodedUrl); @@ -68,12 +69,73 @@ public void GivenAUrl_WhenDecodingWithUri_ThenCharactersDecoded(string encodedUr [DataRow(EncodedUrlLowerPlus)] [DataRow(EncodedUrlUpperPlus)] - [DataTestMethod] + [TestMethod] public void GivenAUrl_WhenDecodingWithUri_ThenCharactersNotDecoded(string encodedUrl) { var decoded = Uri.UnescapeDataString(encodedUrl); Assert.AreNotEqual(Url, decoded); //Uri.UnescapeDataString does not decode + character to space } + + [TestMethod] + public void GivenAUrl_WhenEncodingWithUrlEncoder_ThenCharactersEncoded() + { + var encoded = UrlEncoder.Default.Encode(Url); + + Assert.AreEqual(EncodedUrlUpperPercent, encoded); + } + + [TestMethod] + public void GivenAVeryLongString_WhenEscapingWithUri_ThenNoLengthLimitApplies() + { + var longValue = new string('a', 100_000) + " "; + + var encoded = Uri.EscapeDataString(longValue); + + Assert.AreEqual(100_003, encoded.Length); + } + + [TestMethod] + public void GivenTheEncodeUriComponentSafeCharacters_WhenEscapingWithUri_ThenTheyAreEscaped() + { + var encoded = Uri.EscapeDataString("!'()*~"); + + Assert.AreEqual("%21%27%28%29%2A~", encoded); + } + + [TestMethod] + public void GivenABarePath_WhenConstructingAUri_ThenTheOutcomeIsPlatformDependent() + { + if (OperatingSystem.IsWindows()) + { + //A bare path is not an absolute URI on Windows and not a rooted local path either. + Assert.ThrowsExactly(() => new Uri("/foo")); + Assert.IsFalse(Uri.TryCreate("/foo", UriKind.Absolute, out _)); + } + else + { + //On Unix a bare path IS a rooted local path, so it parses as an absolute file URI. + var uri = new Uri("/foo"); + + Assert.AreEqual("file", uri.Scheme); + Assert.AreEqual("file:///foo", uri.AbsoluteUri); + Assert.IsTrue(Uri.TryCreate("/foo", UriKind.Absolute, out _)); + } + + //The relative remedy works the same way on every platform. + Assert.IsTrue(Uri.TryCreate("/foo", UriKind.Relative, out _)); + Assert.IsFalse(new Uri("/foo", UriKind.Relative).IsAbsoluteUri); + } + + [TestMethod] + public void GivenAProtocolRelativeUrl_WhenConstructingAUri_ThenItParsesAsAFileUri() + { + //Same on Windows and on Unix: this does not throw, it becomes a file URI. + var uri = new Uri("//example.com"); + + Assert.AreEqual("file", uri.Scheme); + Assert.AreEqual("file://example.com/", uri.AbsoluteUri); + Assert.IsTrue(Uri.TryCreate("//example.com", UriKind.Absolute, out _)); + } } } \ No newline at end of file diff --git a/aspnetcore-features/UrlEncodingAndDecoding/UrlEncodingAndDecoding/Program.cs b/aspnetcore-features/UrlEncodingAndDecoding/UrlEncodingAndDecoding/Program.cs index 8fd07966e0..87b6fb2eb9 100644 --- a/aspnetcore-features/UrlEncodingAndDecoding/UrlEncodingAndDecoding/Program.cs +++ b/aspnetcore-features/UrlEncodingAndDecoding/UrlEncodingAndDecoding/Program.cs @@ -1,4 +1,5 @@ using System.Net; +using System.Text.Encodings.Web; using System.Web; var url = @"http://example.com/resource?foo=bar with space#fragment"; @@ -12,10 +13,18 @@ var uriEncoded = Uri.EscapeDataString(url); var uriDecoded = Uri.UnescapeDataString(uriEncoded); +var urlEncoderEncoded = UrlEncoder.Default.Encode(url); + Console.WriteLine(httpUtilityEncoded); Console.WriteLine(webUtilityEncoded); Console.WriteLine(uriEncoded); +Console.WriteLine(urlEncoderEncoded); Console.WriteLine(httpUtilityDecoded); Console.WriteLine(webUtilityDecoded); -Console.WriteLine(uriDecoded); \ No newline at end of file +Console.WriteLine(uriDecoded); + +// In real code we encode a single value, not the address it goes into: +var searchUrl = $"https://example.com/search?q={Uri.EscapeDataString("bar with space")}"; + +Console.WriteLine(searchUrl); \ No newline at end of file diff --git a/aspnetcore-features/UrlEncodingAndDecoding/UrlEncodingAndDecoding/UrlEncodingAndDecoding.csproj b/aspnetcore-features/UrlEncodingAndDecoding/UrlEncodingAndDecoding/UrlEncodingAndDecoding.csproj index f02677bf64..dfb40caafc 100644 --- a/aspnetcore-features/UrlEncodingAndDecoding/UrlEncodingAndDecoding/UrlEncodingAndDecoding.csproj +++ b/aspnetcore-features/UrlEncodingAndDecoding/UrlEncodingAndDecoding/UrlEncodingAndDecoding.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net10.0 enable enable