-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Fix Uri.Host for IPv6 Link-local address #29829
Changes from 3 commits
f2ded59
2d9edda
64f3c78
36d25f6
b565053
6684fbb
0ed1e60
e729a15
192781b
4517b55
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -114,6 +114,7 @@ private enum Flags : ulong | |
FragmentIriCanonical = 0x40000000000, | ||
IriCanonical = 0x78000000000, | ||
UnixPath = 0x100000000000, | ||
LinkLocalAddress = 0x200000000000 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "LinkLocalAddress -> "IPv6LinkLocalAddress" |
||
} | ||
|
||
private Flags _flags; | ||
|
@@ -1193,7 +1194,7 @@ public string DnsSafeHost | |
if (HostType == Flags.IPv6HostType) | ||
{ | ||
ret = ret.Substring(1, ret.Length - 2); | ||
if ((object)_info.ScopeId != null) | ||
if ((object)_info.ScopeId != null && (_flags & Flags.LinkLocalAddress) == 0) | ||
{ | ||
ret += _info.ScopeId; | ||
} | ||
|
@@ -2565,6 +2566,7 @@ private unsafe void CreateHostString() | |
private static string CreateHostStringHelper(string str, ushort idx, ushort end, ref Flags flags, ref string scopeId) | ||
{ | ||
bool loopback = false; | ||
bool linkLocalAddress = false; | ||
string host; | ||
switch (flags & Flags.HostTypeMask) | ||
{ | ||
|
@@ -2574,7 +2576,7 @@ private static string CreateHostStringHelper(string str, ushort idx, ushort end, | |
|
||
case Flags.IPv6HostType: | ||
// The helper will return [...] string that is not suited for Dns.Resolve() | ||
host = IPv6AddressHelper.ParseCanonicalName(str, idx, ref loopback, ref scopeId); | ||
host = IPv6AddressHelper.ParseCanonicalName(str, idx, ref loopback, ref linkLocalAddress, ref scopeId); | ||
break; | ||
|
||
case Flags.IPv4HostType: | ||
|
@@ -2615,7 +2617,12 @@ private static string CreateHostStringHelper(string str, ushort idx, ushort end, | |
if (loopback) | ||
{ | ||
flags |= Flags.LoopbackHost; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There seems to be extra whitespace (space or tabs) after this closing brace. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
if (linkLocalAddress) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add newline above this 'if' statement. |
||
{ | ||
flags |= Flags.LinkLocalAddress; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add newline after closing brace |
||
|
||
return host; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,6 +45,17 @@ public void IdnDnsSafeHost_IPv6Host_ScopeIdButNoBrackets() | |
Assert.Equal("[::1]", test.Host); | ||
} | ||
|
||
[Fact] | ||
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] | ||
public void IdnDnsSafeHost_IPv6HostLinkLocalAddress_ScopeIdButNoBrackets() | ||
{ | ||
Uri test = new Uri("http://[fe80::e077:c9a3:eeba:b8e9%18]/"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should refactor this duplicated string, "fe80::e077:c9a3:eeba:b8e9%18" into a constant in this test. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i copied the pattern from test above https://github.com/MarcoRossignoli/corefx/blob/2d9eddafdf568afab7a8bb730415bfce9b885a15/src/System.Private.Uri/tests/FunctionalTests/IdnDnsSafeHostTest.cs#L41 do you confirm this refactoring? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Following existing code and test patterns can be useful. But it doesn't work in all cases. Sometimes there are bad patterns in the code. And we don't change them all, but try to add better code for new PRs. Also, the pattern you cited uses simpler IP literals. This test uses a long IPv6 literal. So, for code cleanliness and ease of maintenance, it's better to consolidate if possible. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done with |
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use const string ScopedLiteralIpv6 = "fe80::e077:c9a3:eeba:b8e9%18"; since There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh yes i missed it sorry There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done, updated also other test with constants. |
||
Assert.Equal("fe80::e077:c9a3:eeba:b8e9%18", test.DnsSafeHost); | ||
Assert.Equal("fe80::e077:c9a3:eeba:b8e9%18", test.IdnHost); | ||
Assert.Equal("[fe80::e077:c9a3:eeba:b8e9%18]", test.Host); | ||
} | ||
|
||
[Fact] | ||
public void IdnDnsSafeHost_MixedCase_ToLowerCase() | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -234,6 +234,34 @@ private void ParseBadIPv4Address(string badIpv4String) | |
|
||
#region IPv6 | ||
|
||
[Theory] | ||
[InlineData("fe80::e077:c9a3:eeba:b8e9", "%18")] | ||
[InlineData("Fe80::e077:c9a3:eeba:b8e9", "%18")] | ||
[InlineData("fE80::e077:c9a3:eeba:b8e9", "%18")] | ||
[InlineData("FE80::e077:c9a3:eeba:b8e9", "%18")] | ||
[InlineData("FE80::e077:c9a3:eeba:b8e9", "%eth10")] | ||
[InlineData("FE80::e077:c9a3:eeba:b8e9", "")] | ||
[InlineData("FE80::e077:c9a3:eeba:b8e9", "%")] | ||
[InlineData("fe80::e077:c9a3:eeba:b8e9", "%\u30AF\u20E7")] | ||
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] | ||
public void Host_IPv6LinkLocalAddress_HasScopeId(string address, string zoneIndex) | ||
{ | ||
string scopedLiteralIpv6 = "[" + address + zoneIndex + "]"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "scopedLiteralIpv6" -> "scopedLiteralIpv6Brackets" to be more consistent with variable naming in the tests above. |
||
string literalIpV6Uri = "http://" + scopedLiteralIpv6; | ||
var uri = new Uri(literalIpV6Uri); | ||
Assert.Equal(scopedLiteralIpv6, uri.Host, ignoreCase: true); | ||
} | ||
|
||
[Theory] | ||
[InlineData("fe81::e077:c9a3:eeba:b8e9", "%18")] | ||
public void Host_NonIPv6LinkLocalAddress_NoScopeId(string address, string zoneIndex) | ||
{ | ||
string scopedLiteralIpv6 = "[" + address + zoneIndex + "]"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "scopedLiteralIpv6" -> "scopedLiteralIpv6Brackets" to be more consistent with variable naming in the tests above. |
||
string literalIpV6Uri = "http://" + scopedLiteralIpv6; | ||
var uri = new Uri(literalIpV6Uri); | ||
Assert.Equal("[" + address + "]", uri.Host); | ||
} | ||
|
||
[Fact] | ||
public void UriIPv6Host_CanonicalCollonHex_Success() | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: the compiler will help fix this up, but it'd be better to use
"["
and"]"
rather than'['
and']'
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
enlighten me...why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because we want this to compile down to the efficient
string.Concat(string, string, string, string)
call. If the compiler didn't help here, this would end up being a call tostring.Concat(params object[] args)
, which would result in an object[] allocation, the chars getting boxed (so two more allocations), and then having ToString called on them (so two more allocations), plus having a string array allocated in the Concat implementation to store the ToString on each input. As of dotnet/roslyn#415, the C# compiler should do the conversion from e.g. '[' to "[" for you, but why make it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
understood TYVM!