Rewrite Uri.EscapeString (dotnet/corefx#41772)
authorStephen Toub <stoub@microsoft.com>
Tue, 15 Oct 2019 16:27:31 +0000 (12:27 -0400)
committerGitHub <noreply@github.com>
Tue, 15 Oct 2019 16:27:31 +0000 (12:27 -0400)
commit94acc996414dcf6b4b60847775e0247fd959eaa8
tree54a42f255ec37092a3a00782fbce04cb92e071b0
parent7ff3a1100a4ed6f48711d6f7ec43eaba374668a3
Rewrite Uri.EscapeString (dotnet/corefx#41772)

* Rewrite Uri.EscapeString

Several public methods (Uri.EscapeDataString, Uri.EscapeUriString) and a bunch of internal call sites rely on the internal EscapeString helper.  This helper has several issues with it:
- It uses unsafe code.
- It unnecessarily requires and copies through a char[] to get to a string when a string is the required result.
- It has a lot of complexity around the handling of unicode.

This PR rewrites it to utilize Span, Rune, and other newer features in a way that enables it to be both safe and efficient.  Most inputs ends up being faster, and for very long inputs, it's much, much faster.  The use of ValueStringBuilder also results in less memory allocation, in some cases significantly.

The use of Rune also fixes two arguable bugs in the existing implementation around invalid Unicode sequences, which is why a couple tests were tweaked:
- Some but not all invalid unicode patterns result in replacement characters being used: a few invalid sequences (e.g. just a high surrogate) result in an exception.  We should be standardized on using replacement characters for all such invalid sequences.
- Some patterns with invalid unicode patterns actually result in unnecessary encoding, e.g. `Uri.EscapeDataString("\uD800\uD800a")` results in `a` being encoded.

* Address PR feedback

* Add comment about RFC 3986

Commit migrated from https://github.com/dotnet/corefx/commit/75b4e8b12815949813d83b771d5d6ed9279f924c
src/libraries/System.Private.Uri/src/System.Private.Uri.csproj
src/libraries/System.Private.Uri/src/System/Uri.cs
src/libraries/System.Private.Uri/src/System/UriBuilder.cs
src/libraries/System.Private.Uri/src/System/UriExt.cs
src/libraries/System.Private.Uri/src/System/UriHelper.cs
src/libraries/System.Private.Uri/tests/UnitTests/System.Private.Uri.Unit.Tests.csproj
src/libraries/System.Runtime/tests/System/Uri.MethodsTests.cs