Skip to content

Commit e23d22e

Browse files
cdbullardMihaZupan
andauthored
Encode UserName value in UriBuilder (Issue #74662) (#74953)
* Update UriBuilder.cs * Adding check to Password * Adding Unit Tests * Update src/libraries/System.Private.Uri/src/System/UriBuilder.cs Co-authored-by: Miha Zupan <mihazupan.zupan1@gmail.com> * Revising location of EncodeUserInfo to ToString() * Update src/libraries/System.Private.Uri/tests/FunctionalTests/UriBuilderTests.cs Co-authored-by: Miha Zupan <mihazupan.zupan1@gmail.com> Co-authored-by: Miha Zupan <mihazupan.zupan1@gmail.com>
1 parent a7eda3e commit e23d22e

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

src/libraries/System.Private.Uri/src/System/UriBuilder.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,24 @@ public Uri Uri
255255

256256
public override int GetHashCode() => Uri.GetHashCode();
257257

258+
private static string EncodeUserInfo(string input)
259+
{
260+
// The following characters ("/" / "\" / "?" / "#" / "@") are from the gen-delims group.
261+
// We have to escape them to avoid corrupting the rest of the Uri string.
262+
// Other characters like spaces or non-ASCII will be escaped by Uri, we can ignore them here.
263+
if (input.AsSpan().IndexOfAny(@"/\?#@") < 0)
264+
{
265+
return input;
266+
}
267+
268+
return input
269+
.Replace("/", "%2F", StringComparison.Ordinal)
270+
.Replace(@"\", "%5C", StringComparison.Ordinal)
271+
.Replace("?", "%3F", StringComparison.Ordinal)
272+
.Replace("#", "%23", StringComparison.Ordinal)
273+
.Replace("@", "%40", StringComparison.Ordinal);
274+
}
275+
258276
private void SetFieldsFromUri()
259277
{
260278
Debug.Assert(_uri is not null);
@@ -315,12 +333,12 @@ public override string ToString()
315333
vsb.Append(schemeDelimiter);
316334
}
317335

318-
string username = UserName;
336+
string username = EncodeUserInfo(UserName);
319337
if (username.Length != 0)
320338
{
321339
vsb.Append(username);
322340

323-
string password = Password;
341+
string password = EncodeUserInfo(Password);
324342
if (password.Length != 0)
325343
{
326344
vsb.Append(':');

src/libraries/System.Private.Uri/tests/FunctionalTests/UriBuilderTests.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,22 @@ public void ToString_Invalid()
385385
Assert.Throws<UriFormatException>(() => uriBuilder.ToString()); // Uri has a password but no username
386386
}
387387

388+
[Theory]
389+
[InlineData(@"user/\?#@name", "", "http://user%2F%5C%3F%23%40name@localhost/")]
390+
[InlineData(@"user/\?#@name", @"pass/\?#@word", "http://user%2F%5C%3F%23%40name:pass%2F%5C%3F%23%40word@localhost/")]
391+
public void ToString_EncodingUserInfo(string username, string password, string expectedToString)
392+
{
393+
var uriBuilder = new UriBuilder
394+
{
395+
UserName = username,
396+
Password = password
397+
};
398+
399+
Assert.Equal(expectedToString, uriBuilder.ToString());
400+
Assert.Equal(username, uriBuilder.UserName);
401+
Assert.Equal(password, uriBuilder.Password);
402+
}
403+
388404
private static void VerifyUriBuilder(UriBuilder uriBuilder, string scheme, string userName, string password, string host, int port, string path, string query, string fragment)
389405
{
390406
Assert.Equal(scheme, uriBuilder.Scheme);

0 commit comments

Comments
 (0)