Skip to content

Commit

Permalink
Handle unicode in absolute URI path for combine. (#111710)
Browse files Browse the repository at this point in the history
* Handle unicode in absolute URI path for combine.
* Adding debug assert

Co-authored-by: Miha Zupan <[email protected]>
  • Loading branch information
rokonec and MihaZupan authored Jan 28, 2025
1 parent 54f41ac commit d20c35e
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 18 deletions.
48 changes: 30 additions & 18 deletions src/libraries/System.Private.Uri/src/System/UriExt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1053,30 +1053,42 @@ private void CreateThisFromUri(Uri otherUri)
{
DebugAssertInCtor();

// Clone the other URI but develop own UriInfo member
_info = null!;

_flags = otherUri._flags;
if (InFact(Flags.MinimalUriInfoSet))

if (InFact(Flags.AllUriInfoSet))
{
// We can share it now without mutation concern, for since AllUriInfoSet it is immutable.
_info = otherUri._info;
}
else
{
_flags &= ~(Flags.MinimalUriInfoSet | Flags.AllUriInfoSet | Flags.IndexMask);
// Port / Path offset
int portIndex = otherUri._info.Offset.Path;
if (InFact(Flags.NotDefaultPort))
Debug.Assert(!InFact(Flags.HasUnicode) || otherUri.IsNotAbsoluteUri);
// Clone the other URI but develop own UriInfo member
// We cannot just reference otherUri._info as this UriInfo will be mutated later
// which could be happening concurrently and in a not thread safe manner.
_info = null!;

if (InFact(Flags.MinimalUriInfoSet))
{
// Find the start of the port. Account for non-canonical ports like :00123
while (otherUri._string[portIndex] != ':' && portIndex > otherUri._info.Offset.Host)
_flags &= ~(Flags.MinimalUriInfoSet | Flags.AllUriInfoSet | Flags.IndexMask);
// Port / Path offset
int portIndex = otherUri._info.Offset.Path;
if (InFact(Flags.NotDefaultPort))
{
portIndex--;
}
if (otherUri._string[portIndex] != ':')
{
// Something wrong with the NotDefaultPort flag. Reset to path index
Debug.Fail("Uri failed to locate custom port at index: " + portIndex);
portIndex = otherUri._info.Offset.Path;
// Find the start of the port. Account for non-canonical ports like :00123
while (otherUri._string[portIndex] != ':' && portIndex > otherUri._info.Offset.Host)
{
portIndex--;
}
if (otherUri._string[portIndex] != ':')
{
// Something wrong with the NotDefaultPort flag. Reset to path index
Debug.Fail("Uri failed to locate custom port at index: " + portIndex);
portIndex = otherUri._info.Offset.Path;
}
}
_flags |= (Flags)portIndex; // Port or path
}
_flags |= (Flags)portIndex; // Port or path
}

_syntax = otherUri._syntax;
Expand Down
20 changes: 20 additions & 0 deletions src/libraries/System.Private.Uri/tests/FunctionalTests/UriTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -729,6 +730,25 @@ public static void Uri_CombineUsesNewUriString()
Assert.Equal(Combined, new Uri(baseUri, RelativeUriString).AbsoluteUri);
}

[Theory]
[InlineData("http://bar/Testue/testImage.jpg", "http://bar/Testue/testImage.jpg", "http://bar/Testue/testImage.jpg", "bar")]
[InlineData(@"\\nas\Testue\testImage.jpg", "file://nas/Testue/testImage.jpg", "file://nas/Testue/testImage.jpg", "nas")]
// Tests that internal Uri info were properly applied during a Combine operation when URI contains non-ascii character.
[InlineData("http://bar/Test\u00fc/testImage.jpg", "http://bar/Test\u00fc/testImage.jpg", "http://bar/Test%C3%BC/testImage.jpg", "bar")]
[InlineData("\\\\nas\\Test\u00fc\\testImage.jpg", "file://nas/Test\u00fc/testImage.jpg", "file://nas/Test%C3%BC/testImage.jpg", "nas")]
public static void Uri_CombineWithAbsoluteUriResultInAbsoluteSchemaIgnoringOriginalBase(string relativeUri, string expectedUri, string expectedAbsoluteUri, string expectedHost)
{
string baseUriString = "combine-scheme://foo";

var baseUri = new Uri(baseUriString, UriKind.Absolute);
var uri = new Uri(relativeUri);
var resultUri = new Uri(baseUri, uri);

Assert.Equal(expectedUri, resultUri.ToString());
Assert.Equal(expectedAbsoluteUri, resultUri.AbsoluteUri);
Assert.Equal(expectedHost, resultUri.Host);
}

[Fact]
public static void Uri_CachesIdnHost()
{
Expand Down

0 comments on commit d20c35e

Please sign in to comment.