Bug 29864

Summary: public Uri(Uri baseUri, Uri relativeUri) strips . from path
Product: [Mono] Class Libraries Reporter: Shawn <shawn.bissell>
Component: SystemAssignee: marcos.henrich
Severity: normal CC: jarrod.connolly, marcos.henrich, mono-bugs+mono, shawn.bissell
Priority: ---    
Version: 3.12.0   
Target Milestone: Untriaged   
Hardware: All   
OS: All   
Tags: Is this bug a regression?: ---
Last known good build:

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.