Skip to content

Handle unicode in absolute URI path for combine. #111710

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading