Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Fix Uri.Host for IPv6 Link-local address #29829

Merged
merged 10 commits into from
May 30, 2018
Merged

Fix Uri.Host for IPv6 Link-local address #29829

merged 10 commits into from
May 30, 2018

Conversation

MarcoRossignoli
Copy link
Member

@MarcoRossignoli MarcoRossignoli commented May 21, 2018

contributes to #28863
replace PR #29769 after revert #29818 for Outerloop CI fail

this PR address the second part of issue:

  1. Uri.Host LLA (Link-local address) IPv6 address doesn't contain %number part.
  • Currently it returns [fe80::e077:c9a3:eeba:b8e9], it should return [fe80::e077:c9a3:eeba:b8e9%18].
  • Note: Uri.IdnHost correctly contains the %number part.

cc: @rmkerr @Caesar1995 @davidsh @stephentoub

@MarcoRossignoli
Copy link
Member Author

@dotnet-bot test Outerloop Linux x64 Release Build please
@dotnet-bot test Outerloop Windows x86 Release Build please

@davidsh davidsh requested review from stephentoub and a team May 21, 2018 19:09
@@ -2616,6 +2618,10 @@ private static string CreateHostStringHelper(string str, ushort idx, ushort end,
{
flags |= Flags.LoopbackHost;
}
if(linkLocalAddress)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add space after 'if'

if(linkLocalAddress)
{
flags |= Flags.LinkLocalAddress;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add newline after closing brace

[Fact]
public void IdnDnsSafeHost_IPv6HostLinkLocalAddress_ScopeIdButNoBrackets()
{
Uri test = new Uri("http://[fe80::e077:c9a3:eeba:b8e9%18]/");
Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Member Author

@MarcoRossignoli MarcoRossignoli May 21, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The 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?

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.

Copy link
Member Author

@MarcoRossignoli MarcoRossignoli May 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done with [Theory] could be useful for future new data, if you like.

@MarcoRossignoli
Copy link
Member Author

@dotnet-bot test Outerloop Linux x64 Release Build please
@dotnet-bot test Outerloop Windows x86 Release Build please

@@ -2617,11 +2617,12 @@ private static string CreateHostStringHelper(string str, ushort idx, ushort end,
if (loopback)
{
flags |= Flags.LoopbackHost;
}
if(linkLocalAddress)
}
Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@MarcoRossignoli
Copy link
Member Author

@dotnet-bot test Outerloop Linux x64 Release Build please, on my Ubuntu 18.04 outerloop works well, i want to understand if the issue is related to SO version.

@MarcoRossignoli
Copy link
Member Author

@dotnet-bot test Linux x64 Release Build please

@MarcoRossignoli
Copy link
Member Author

@dotnet-bot test Outerloop Linux x64 Release Build please
@dotnet-bot test Outerloop Windows x86 Release Build please

@stephentoub
Copy link
Member

@MarcoRossignoli
Copy link
Member Author

MarcoRossignoli commented May 22, 2018

GetAsync_IPv6LinkLocalAddressUri_Success is failing with this change with CurlHandler on several distros:

@stephentoub i need to setup an Ubuntu 14.04, i think depends on SO version(on my 18.04 it's ok, also on CI), let me try!

EDIT(22/5): i repro issue with Ubuntu 14.04, i think depends on curl version, i'm checking fix/releases

@MarcoRossignoli MarcoRossignoli changed the title Fix Uri.Host for IPv6 Link-local address [WIP]Fix Uri.Host for IPv6 Link-local address May 22, 2018
@caesar-chen
Copy link
Contributor

@dotnet-bot test Windows x64 Debug Build

@MarcoRossignoli
Copy link
Member Author

MarcoRossignoli commented May 23, 2018

UPDATE: after some research i discovered that there is a difference in ipv6 parsing between curl versions, this PR change the way of parsing Fixed in 7.37.0 - May 21 2014 Ubuntu 14.04 use curl ver 7.35.0(curl -V) now single % is supported https://github.com/curl/curl/blob/master/lib/url.c#L2358.
Now to be backward compatible my idea is to amend here https://github.com/dotnet/corefx/blob/master/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.EasyRequest.cs#L266 and in case of LLA reassemble an Url with %25 instead of %. What do you think?I did some test with code and curl command and seem to be working(i didn't to all tests outerloop/distros), but before moving on i'd like to hear your opinions.

cc @stephentoub @davidsh @rmkerr @Caesar1995

@MarcoRossignoli
Copy link
Member Author

@dotnet-bot test Outerloop Linux x64 Release Build please
@dotnet-bot test Outerloop Windows x86 Release Build please

string url = requestUri.Host == idnHost ?
requestUri.AbsoluteUri :
new UriBuilder(requestUri) { Host = idnHost }.Uri.AbsoluteUri;
string url = requestUri.Host == idnHost ?
Copy link
Member Author

@MarcoRossignoli MarcoRossignoli May 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another idea could be borrow some code from here or here and get only host name value, if in future we fix brackets on idnHost this could break, but i do not know if it is worth.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as the tests would catch that break, I think the change is probably okay. The fix to add brackets on idnHost is risky enough that it will require more investigation.

@MarcoRossignoli MarcoRossignoli changed the title [WIP]Fix Uri.Host for IPv6 Link-local address Fix Uri.Host for IPv6 Link-local address May 24, 2018
@@ -263,7 +263,8 @@ private void SetUrl()
Uri requestUri = _requestMessage.RequestUri;

long scopeId;
if (IsLinkLocal(requestUri, out scopeId))
bool isLinkLocal = false;
if ((isLinkLocal = IsLinkLocal(requestUri, out scopeId)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: indentation is off

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

new UriBuilder(requestUri) { Host = idnHost }.Uri.AbsoluteUri;
string url = requestUri.Host == idnHost ?
requestUri.AbsoluteUri :
new UriBuilder(requestUri){ Host = isLinkLocal && (scopeIdIndex = idnHost.IndexOf("%", StringComparison.OrdinalIgnoreCase)) != -1 ? idnHost.Substring(0, scopeIdIndex) : idnHost}.Uri.AbsoluteUri;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The IndexOf can just be idnHost.IndexOf('%')

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're right

@@ -31,7 +31,8 @@ internal static string ParseCanonicalName(string str, int start, ref bool isLoop
((long*)numbers)[0] = 0L;
((long*)numbers)[1] = 0L;
isLoopback = Parse(str, numbers, start, ref scopeId);
return '[' + CreateCanonicalName(numbers) + ']';
linkLocalAddress = numbers[0] == 0xfe80;
return '[' + CreateCanonicalName(numbers) + (linkLocalAddress ? scopeId : "") + ']';
Copy link
Member

@stephentoub stephentoub May 24, 2018

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 ']'.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

enlighten me...why?

Copy link
Member

@stephentoub stephentoub May 24, 2018

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 to string.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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

understood TYVM!

@@ -114,6 +114,7 @@ private enum Flags : ulong
FragmentIriCanonical = 0x40000000000,
IriCanonical = 0x78000000000,
UnixPath = 0x100000000000,
LinkLocalAddress = 0x200000000000
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"LinkLocalAddress -> "IPv6LinkLocalAddress"

@@ -2616,6 +2618,11 @@ private static string CreateHostStringHelper(string str, ushort idx, ushort end,
{
flags |= Flags.LoopbackHost;
}
if (linkLocalAddress)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add newline above this 'if' statement.

[Theory]
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
[InlineData("fe80::e077:c9a3:eeba:b8e9", "%18")]
public void IdnDnsSafeHost_IPv6HostLinkLocalAddress_ScopeIdButNoBrackets(string address, string zoneIndex)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"ScopeIdButNoBrackets" part of the test name isn't quite right since there is an Assert in this test that validates for brackets.

Normally we don't have a single test method that test multiple properties. But I see that there is already other tests that do this in this file.

I suggest, though, that you rename the test like this:

"IdnDnsSafeHost_IPv6HostLinkLocalAddress_ScopeIdCorrectlyFormatted"

[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
public void Host_IPv6LinkLocalAddress_HasScopeId(string address, string zoneIndex)
{
string scopedLiteralIpv6 = "[" + address + zoneIndex + "]";
Copy link
Contributor

Choose a reason for hiding this comment

The 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.

[InlineData("fe81::e077:c9a3:eeba:b8e9", "%18")]
public void Host_NonIPv6LinkLocalAddress_NoScopeId(string address, string zoneIndex)
{
string scopedLiteralIpv6 = "[" + address + zoneIndex + "]";
Copy link
Contributor

Choose a reason for hiding this comment

The 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.

@davidsh davidsh added this to the 2.2.0 milestone May 24, 2018
@MarcoRossignoli
Copy link
Member Author

@dotnet-bot test Outerloop Linux x64 Release Build please
@dotnet-bot test Outerloop Windows x86 Release Build please

@@ -45,6 +45,21 @@ public void IdnDnsSafeHost_IPv6Host_ScopeIdButNoBrackets()
Assert.Equal("[::1]", test.Host);
}

[Theory]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually use [Theory] for multiple test data. So here

  1. you can add more test data ([InlineData])
  2. or use [Fact], without taking any parameters, and create a constant in the test. As David mentioned here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@caesar-chen
Copy link
Contributor

@dotnet-bot test this please

@dotnet-bot test Outerloop Windows x64 Debug Build
@dotnet-bot test Outerloop Linux x64 Debug Build
@dotnet-bot test Outerloop NETFX x86 Debug Build
@dotnet-bot test Outerloop UWP CoreCLR x64 Debug Build

@MarcoRossignoli
Copy link
Member Author

@dotnet-bot test Outerloop Windows x64 Debug Build
@dotnet-bot test Outerloop Linux x64 Debug Build
@dotnet-bot test Outerloop NETFX x86 Debug Build
@dotnet-bot test Outerloop UWP CoreCLR x64 Debug Build
@dotnet-bot test Outerloop Linux x64 Release Build please
@dotnet-bot test Outerloop Windows x86 Release Build please

{
string address = "fe80::e077:c9a3:eeba:b8e9";
string zoneIndex = "%18";

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use

const string ScopedLiteralIpv6 = "fe80::e077:c9a3:eeba:b8e9%18"; 

since address and zoneIndex is not used anywhere else in the test.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yes i missed it sorry

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done, updated also other test with constants.

@MarcoRossignoli
Copy link
Member Author

@dotnet-bot test Outerloop Windows x64 Debug Build
@dotnet-bot test Outerloop Linux x64 Debug Build
@dotnet-bot test Outerloop NETFX x86 Debug Build
@dotnet-bot test Outerloop UWP CoreCLR x64 Debug Build
@dotnet-bot test Outerloop Linux x64 Release Build please
@dotnet-bot test Outerloop Windows x86 Release Build please

@caesar-chen
Copy link
Contributor

LGTM once CI is green.

@MarcoRossignoli
Copy link
Member Author

@dotnet-bot test Outerloop Windows x64 Debug Build

1 similar comment
@MarcoRossignoli
Copy link
Member Author

@dotnet-bot test Outerloop Windows x64 Debug Build

Copy link
Contributor

@caesar-chen caesar-chen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.
@dotnet/ncl Any additional feedback?

@@ -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.IPv6LinkLocalAddress) == 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: We can add a comment here to explain the purpose for the new flag. i,e,. to avoid duplicated ScopeId.

Copy link
Member Author

@MarcoRossignoli MarcoRossignoli May 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added, with new line before for readability, let me know if it's ok.

@MarcoRossignoli
Copy link
Member Author

@dotnet-bot test Outerloop Windows x64 Debug Build
@dotnet-bot test Outerloop Linux x64 Debug Build
@dotnet-bot test Outerloop NETFX x86 Debug Build
@dotnet-bot test Outerloop UWP CoreCLR x64 Debug Build
@dotnet-bot test Outerloop Linux x64 Release Build please
@dotnet-bot test Outerloop Windows x86 Release Build please

Copy link
Contributor

@rmkerr rmkerr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a solid, well scoped change to me. It's unfortunate that we have to special case the behavior on Curl, but I think that the change you made there is correct. Pending approval from either @davidsh or @stephentoub, this looks good to me.

@davidsh davidsh merged commit f7a8cf1 into dotnet:master May 30, 2018
@MarcoRossignoli MarcoRossignoli deleted the ipv6lla branch May 30, 2018 18:10
caesar-chen added a commit to caesar-chen/corefx that referenced this pull request Jun 1, 2018
caesar-chen pushed a commit that referenced this pull request Jun 4, 2018
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
Contributes to dotnet/corefx#28863

Replace PR dotnet/corefx#29769 after revert dotnet/corefx#29818 for Outerloop CI fail

This PR address the second part of issue:

Uri.Host LLA (Link-local address) IPv6 address doesn't contain %number part.
Currently it returns [fe80::e077:c9a3:eeba:b8e9], it should return [fe80::e077:c9a3:eeba:b8e9%18].

Note: Uri.IdnHost correctly contains the %number part.


Commit migrated from dotnet/corefx@f7a8cf1
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants