Bug 29864 - public Uri(Uri baseUri, Uri relativeUri) strips . from path
Summary: public Uri(Uri baseUri, Uri relativeUri) strips . from path
Alias: None
Product: Class Libraries
Classification: Mono
Component: System ()
Version: 3.12.0
Hardware: All All
: --- normal
Target Milestone: Untriaged
Assignee: marcos.henrich
Depends on:
Reported: 2015-05-07 17:52 UTC by Shawn
Modified: 2015-10-19 09:02 UTC (History)
4 users (show)

Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:

Description Shawn 2015-05-07 17:52:05 UTC
The public Uri(Uri baseUri, Uri relativeUri) method strips . characters in path incorrectly. 
Here is a simple unit test which should pass
public void DotInUrlTest()
    var uri = new Uri("https://blog.domain.com/en/images/topics/Misc./a.jpg", UriKind.Absolute);
    Assert.AreEqual("https://blog.domain.com/en/images/topics/Misc./a.jpg", uri.ToString());

    var baseUri = new Uri("https://blog.domain.com/", UriKind.Absolute);
    Assert.AreEqual("https://blog.domain.com/", baseUri.ToString());

    var reluri = new Uri("/en/images/topics/Misc./a.jpg", UriKind.Relative);
    Assert.AreEqual("/en/images/topics/Misc./a.jpg", reluri.ToString());

    //This test fails because the . is stripped out of /Misc./
    uri = new Uri(baseUri, reluri);
    Assert.AreEqual("https://blog.domain.com/en/images/topics/Misc./a.jpg", uri.ToString());

Test.DotInUrlTest :   Expected string length 52 but was 51. Strings differ at index 45.
  Expected: "https://blog.domain.com/en/images/topics/Misc./a.jpg"
  But was:  "https://blog.domain.com/en/images/topics/Misc/a.jpg"

Tested in 4.0 and 3.12.1 with same result
Comment 1 Jarrod 2015-05-13 13:54:51 UTC
Also seeing this issue, seems to be a regression.

The above unit test passes using mono 3.4.0 and 3.8.0
Comment 2 Jarrod 2015-05-14 15:44:28 UTC
Tested and fails in mono 3.10.0
Comment 3 Jarrod 2015-05-14 19:42:46 UTC
Stepped through the 3.12.1 source for the Uri class to see where this was happening.

Calling the Uri constructor:
public Uri (Uri baseUri, Uri relativeUri)

This constructor directly calls Merge

Down a ways inside the Merge function Reduce is call like this:
source += UriHelper.Reduce (path, true);

here true is passed as the second param which is called trimDots
internal static string Reduce (string path, bool trimDots)

When Reduce is going through the path segments one of the checks is makes is this:
if (segment == "." ||
    (trimDots && segment.EndsWith (".", StringComparison.Ordinal))) {
    segment = segment.TrimEnd ('.');

trimDots was passed as true, and this path segment as in the bug report above is "Misc." so the trailing dot in that segment is removed.

I am not sure what the intent of this code is but removing that trailing dot is incorrect for http urls at least.
Comment 4 marcos.henrich 2015-10-15 10:14:01 UTC
Hi Shawn, Jarrod,

Thank you for the bug report.

After some experiments on .NET I noticed that before .NET 4.5 dots were trimmed from the end of uri path segments.

In .NET 4.5 IRI parsing is enabled by default and dot are no longer
trimmed from the end of path segments.

Here is the pull request with the fix and test:
Comment 5 marcos.henrich 2015-10-19 09:02:47 UTC
Fixed in master a1d39d9b02ea634f8ba27b1df262f8047b07f363.