You've already forked linux-packaging-mono
Imported Upstream version 5.4.0.167
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
This commit is contained in:
parent
e49d6f06c0
commit
536cd135cc
@@ -2,7 +2,8 @@
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\dir.props" />
|
||||
<PropertyGroup>
|
||||
<AssemblyVersion>4.1.0.0</AssemblyVersion>
|
||||
<AssemblyVersion>4.1.1.0</AssemblyVersion>
|
||||
<AssemblyKey>MSFT</AssemblyKey>
|
||||
<IsNETCoreApp>true</IsNETCoreApp>
|
||||
<IsUAP>true</IsUAP>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
Compat issues with assembly System.Net.Primitives:
|
||||
TypesMustExist : Type 'System.Net.Cookie' does not exist in the implementation but it does exist in the contract.
|
||||
MembersMustExist : Member 'System.Net.CookieCollection.Add(System.Net.Cookie)' does not exist in the implementation but it does exist in the contract.
|
||||
MembersMustExist : Member 'System.Net.CookieCollection.CopyTo(System.Net.Cookie[], System.Int32)' does not exist in the implementation but it does exist in the contract.
|
||||
MembersMustExist : Member 'System.Net.CookieCollection.Item.get(System.Int32)' does not exist in the implementation but it does exist in the contract.
|
||||
MembersMustExist : Member 'System.Net.CookieCollection.Item.get(System.String)' does not exist in the implementation but it does exist in the contract.
|
||||
MembersMustExist : Member 'System.Net.CookieContainer.Add(System.Net.Cookie)' does not exist in the implementation but it does exist in the contract.
|
||||
MembersMustExist : Member 'System.Net.CookieContainer.Add(System.Uri, System.Net.Cookie)' does not exist in the implementation but it does exist in the contract.
|
||||
TypesMustExist : Type 'System.Net.CookieException' does not exist in the implementation but it does exist in the contract.
|
||||
Total Issues: 8
|
||||
@@ -103,6 +103,9 @@
|
||||
<data name="net_collection_readonly" xml:space="preserve">
|
||||
<value>The collection is read-only.</value>
|
||||
</data>
|
||||
<data name="net_nodefaultcreds" xml:space="preserve">
|
||||
<value>Default credentials cannot be supplied for the {0} authentication scheme.</value>
|
||||
</data>
|
||||
<data name="InvalidOperation_EnumFailedVersion" xml:space="preserve">
|
||||
<value>Collection was modified after the enumerator was instantiated.</value>
|
||||
</data>
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
<ProjectGuid>{8772BC91-7B55-49B9-94FA-4B1BE5BEAB55}</ProjectGuid>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<DefineConstants Condition="'$(TargetGroup)' == 'uap'">$(DefineConstants);uap</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<!-- Help VS understand available configurations -->
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='uap-Windows_NT-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='uap-Windows_NT-Release|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcoreapp-Unix-Debug|AnyCPU'" />
|
||||
@@ -39,12 +35,13 @@
|
||||
<Compile Include="System\Net\IPAddress.cs" />
|
||||
<Compile Include="System\Net\IPAddressParser.cs" />
|
||||
<Compile Include="System\Net\IPEndPoint.cs" />
|
||||
<Compile Include="System\Net\IPv4AddressHelper.cs" />
|
||||
<Compile Include="System\Net\IPv6AddressHelper.cs" />
|
||||
<Compile Include="System\Net\IWebProxy.cs" />
|
||||
<Compile Include="System\Net\NetEventSource.Primitives.cs" />
|
||||
<Compile Include="System\Net\NetworkCredential.cs" />
|
||||
<Compile Include="System\Net\TransportContext.cs" />
|
||||
<Compile Include="System\Net\SocketException.cs" />
|
||||
<Compile Include="System\Net\SocketException.netstandard.cs" />
|
||||
<Compile Include="System\Net\SecureProtocols\NegotiateEnumTypes.cs" />
|
||||
<Compile Include="System\Net\SecureProtocols\SslEnumTypes.cs" />
|
||||
<Compile Include="System\Net\Security\SslPolicyErrors.cs" />
|
||||
@@ -61,6 +58,15 @@
|
||||
<Compile Include="$(CommonPath)\System\Net\ByteOrder.cs">
|
||||
<Link>Common\System\Net\ByteOrder.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\Net\CookieComparer.cs">
|
||||
<Link>ProductionCode\System\Net\CookieComparer.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\Net\CookieFields.cs">
|
||||
<Link>Common\System\Net\CookieFields.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\Net\CookieParser.cs">
|
||||
<Link>Common\System\Net\CookieParser.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\Net\IPAddressParserStatics.cs">
|
||||
<Link>Common\System\Net\IPAddressParserStatics.cs</Link>
|
||||
</Compile>
|
||||
@@ -76,6 +82,9 @@
|
||||
<Compile Include="$(CommonPath)\System\Net\SocketAddress.cs">
|
||||
<Link>Common\System\Net\SocketAddress.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\Net\NegotiationInfoClass.cs">
|
||||
<Link>Common\System\Net\NegotiationInfoClass.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\Net\NetworkInformation\HostInformation.cs">
|
||||
<Link>Common\System\Net\NetworkInformation\HostInformation.cs</Link>
|
||||
</Compile>
|
||||
@@ -103,7 +112,6 @@
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" '$(TargetsWindows)' == 'true'">
|
||||
<Compile Include="System\Net\IPAddressPal.Windows.cs" />
|
||||
<Compile Include="System\Net\SocketException.Windows.cs" />
|
||||
<Compile Include="$(CommonPath)\System\Net\SocketAddressPal.Windows.cs">
|
||||
<Link>Common\System\Net\SocketAddressPal.Windows.cs</Link>
|
||||
@@ -123,21 +131,6 @@
|
||||
<Compile Include="$(CommonPath)\Interop\Windows\NtDll\Interop.NtStatus.cs">
|
||||
<Link>Common\Interop\Windows\NtDll\Interop.NtStatus.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\Interop\Windows\NtDll\Interop.RtlIpv4AddressToStringEx.cs">
|
||||
<Link>Common\Interop\Windows\NtDll\Interop.RtlIpv4AddressToStringEx.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\Interop\Windows\NtDll\Interop.RtlIpv4StringToAddressEx.cs">
|
||||
<Link>Common\Interop\Windows\NtDll\Interop.RtlIpv4StringToAddressEx.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\Interop\Windows\NtDll\Interop.RtlIpv6AddressToStringEx.cs">
|
||||
<Link>Common\Interop\Windows\NtDll\Interop.RtlIpv6AddressToStringEx.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\Interop\Windows\NtDll\Interop.RtlIpv6StringToAddressEx.cs">
|
||||
<Link>Common\Interop\Windows\NtDll\Interop.RtlIpv6StringToAddressEx.cs</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<!-- Windows : Win32 only -->
|
||||
<ItemGroup Condition="'$(TargetsWindows)' == 'true' AND '$(TargetGroup)' != 'uap'">
|
||||
<Compile Include="$(CommonPath)\System\Net\NetworkInformation\HostInformationPal.Windows.cs">
|
||||
<Link>Common\System\Net\NetworkInformation\HostInformationPal.Windows.cs</Link>
|
||||
</Compile>
|
||||
@@ -157,14 +150,7 @@
|
||||
<Link>Common\Interop\Windows\kernel32\Interop.LocalFree.cs</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<!-- Windows : Win32 + WinRT -->
|
||||
<ItemGroup Condition="'$(TargetsWindows)' == 'true' AND '$(TargetGroup)' == 'uap'">
|
||||
<Compile Include="$(CommonPath)\System\Net\NetworkInformation\HostInformationPal.Uap.cs">
|
||||
<Link>Common\System\Net\NetworkInformation\HostInformationPal.Uap.cs</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" '$(TargetsUnix)' == 'true'">
|
||||
<Compile Include="System\Net\IPAddressPal.Unix.cs" />
|
||||
<Compile Include="System\Net\SocketException.Unix.cs" />
|
||||
<Compile Include="$(CommonPath)\System\Net\SocketAddressPal.Unix.cs">
|
||||
<Link>Common\System\Net\SocketAddressPal.Unix.cs</Link>
|
||||
@@ -200,10 +186,6 @@
|
||||
<Link>Interop\Unix\System.Native\Interop.SocketAddress.cs</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetGroup)' == 'uap'">
|
||||
<Reference Include="Windows" />
|
||||
<Reference Include="mscorlib" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Win32.Primitives" />
|
||||
<Reference Include="System.Collections" />
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,9 +4,6 @@
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
#if uap
|
||||
using System.Net.Internal;
|
||||
#endif
|
||||
|
||||
namespace System.Net
|
||||
{
|
||||
@@ -14,6 +11,9 @@ namespace System.Net
|
||||
//
|
||||
// A list of cookies maintained in Sorted order. Only one cookie with matching Name/Domain/Path
|
||||
[Serializable]
|
||||
#if !MONO
|
||||
[System.Runtime.CompilerServices.TypeForwardedFrom("System, Version=4.0.0.0, PublicKeyToken=b77a5c561934e089")]
|
||||
#endif
|
||||
public class CookieCollection : ICollection
|
||||
{
|
||||
internal enum Stamp
|
||||
@@ -24,10 +24,10 @@ namespace System.Net
|
||||
SetToMaxUsed = 3,
|
||||
}
|
||||
|
||||
private readonly List<Cookie> _list = new List<Cookie>();
|
||||
private readonly ArrayList m_list = new ArrayList();
|
||||
|
||||
private DateTime _timeStamp = DateTime.MinValue;
|
||||
private bool _hasOtherVersions;
|
||||
private DateTime m_timeStamp = DateTime.MinValue; // Do not rename (binary serialization)
|
||||
private bool m_has_other_versions; // Do not rename (binary serialization)
|
||||
|
||||
public CookieCollection()
|
||||
{
|
||||
@@ -37,11 +37,11 @@ namespace System.Net
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index < 0 || index >= _list.Count)
|
||||
if (index < 0 || index >= m_list.Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
return _list[index];
|
||||
return m_list[index] as Cookie;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace System.Net
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (Cookie c in _list)
|
||||
foreach (Cookie c in m_list)
|
||||
{
|
||||
if (string.Equals(c.Name, name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
@@ -69,11 +69,11 @@ namespace System.Net
|
||||
int idx = IndexOf(cookie);
|
||||
if (idx == -1)
|
||||
{
|
||||
_list.Add(cookie);
|
||||
m_list.Add(cookie);
|
||||
}
|
||||
else
|
||||
{
|
||||
_list[idx] = cookie;
|
||||
m_list[idx] = cookie;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace System.Net
|
||||
{
|
||||
throw new ArgumentNullException(nameof(cookies));
|
||||
}
|
||||
foreach (Cookie cookie in cookies._list)
|
||||
foreach (Cookie cookie in cookies.m_list)
|
||||
{
|
||||
Add(cookie);
|
||||
}
|
||||
@@ -101,7 +101,7 @@ namespace System.Net
|
||||
{
|
||||
get
|
||||
{
|
||||
return _list.Count;
|
||||
return m_list.Count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,12 +123,12 @@ namespace System.Net
|
||||
|
||||
public void CopyTo(Array array, int index)
|
||||
{
|
||||
((ICollection)_list).CopyTo(array, index);
|
||||
((ICollection)m_list).CopyTo(array, index);
|
||||
}
|
||||
|
||||
public void CopyTo(Cookie[] array, int index)
|
||||
{
|
||||
_list.CopyTo(array, index);
|
||||
m_list.CopyTo(array, index);
|
||||
}
|
||||
|
||||
internal DateTime TimeStamp(Stamp how)
|
||||
@@ -136,19 +136,19 @@ namespace System.Net
|
||||
switch (how)
|
||||
{
|
||||
case Stamp.Set:
|
||||
_timeStamp = DateTime.Now;
|
||||
m_timeStamp = DateTime.Now;
|
||||
break;
|
||||
case Stamp.SetToMaxUsed:
|
||||
_timeStamp = DateTime.MaxValue;
|
||||
m_timeStamp = DateTime.MaxValue;
|
||||
break;
|
||||
case Stamp.SetToUnused:
|
||||
_timeStamp = DateTime.MinValue;
|
||||
m_timeStamp = DateTime.MinValue;
|
||||
break;
|
||||
case Stamp.Check:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return _timeStamp;
|
||||
return m_timeStamp;
|
||||
}
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace System.Net
|
||||
{
|
||||
get
|
||||
{
|
||||
return _hasOtherVersions;
|
||||
return m_has_other_versions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ namespace System.Net
|
||||
if (isStrict)
|
||||
{
|
||||
int idx = 0;
|
||||
foreach (Cookie c in _list)
|
||||
foreach (Cookie c in m_list)
|
||||
{
|
||||
if (CookieComparer.Compare(cookie, c) == 0)
|
||||
{
|
||||
@@ -180,24 +180,24 @@ namespace System.Net
|
||||
// Cookie2 spec requires that new Variant cookie overwrite the old one.
|
||||
if (c.Variant <= cookie.Variant)
|
||||
{
|
||||
_list[idx] = cookie;
|
||||
m_list[idx] = cookie;
|
||||
}
|
||||
break;
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
if (idx == _list.Count)
|
||||
if (idx == m_list.Count)
|
||||
{
|
||||
_list.Add(cookie);
|
||||
m_list.Add(cookie);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_list.Add(cookie);
|
||||
m_list.Add(cookie);
|
||||
}
|
||||
if (cookie.Version != Cookie.MaxSupportedVersion)
|
||||
{
|
||||
_hasOtherVersions = true;
|
||||
m_has_other_versions = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -205,7 +205,7 @@ namespace System.Net
|
||||
internal int IndexOf(Cookie cookie)
|
||||
{
|
||||
int idx = 0;
|
||||
foreach (Cookie c in _list)
|
||||
foreach (Cookie c in m_list)
|
||||
{
|
||||
if (CookieComparer.Compare(cookie, c) == 0)
|
||||
{
|
||||
@@ -218,12 +218,12 @@ namespace System.Net
|
||||
|
||||
internal void RemoveAt(int idx)
|
||||
{
|
||||
_list.RemoveAt(idx);
|
||||
m_list.RemoveAt(idx);
|
||||
}
|
||||
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
return _list.GetEnumerator();
|
||||
return m_list.GetEnumerator();
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
||||
@@ -7,9 +7,6 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Text;
|
||||
#if uap
|
||||
using System.Net.Internal;
|
||||
#endif
|
||||
|
||||
// Relevant cookie specs:
|
||||
//
|
||||
@@ -91,6 +88,9 @@ namespace System.Net
|
||||
//
|
||||
// Manage cookies for a user (implicit). Based on RFC 2965.
|
||||
[Serializable]
|
||||
#if !MONO
|
||||
[System.Runtime.CompilerServices.TypeForwardedFrom("System, Version=4.0.0.0, PublicKeyToken=b77a5c561934e089")]
|
||||
#endif
|
||||
public class CookieContainer
|
||||
{
|
||||
public const int DefaultCookieLimit = 300;
|
||||
@@ -103,19 +103,19 @@ namespace System.Net
|
||||
};
|
||||
|
||||
// NOTE: all accesses of _domainTable must be performed with _domainTable locked.
|
||||
private readonly Dictionary<string, PathList> _domainTable = new Dictionary<string, PathList>();
|
||||
private int _maxCookieSize = DefaultCookieLengthLimit;
|
||||
private int _maxCookies = DefaultCookieLimit;
|
||||
private int _maxCookiesPerDomain = DefaultPerDomainCookieLimit;
|
||||
private int _count = 0;
|
||||
private string _fqdnMyDomain = string.Empty;
|
||||
private readonly Dictionary<string, PathList> m_domainTable = new Dictionary<string, PathList>(); // Do not rename (binary serialization)
|
||||
private int m_maxCookieSize = DefaultCookieLengthLimit; // Do not rename (binary serialization)
|
||||
private int m_maxCookies = DefaultCookieLimit; // Do not rename (binary serialization)
|
||||
private int m_maxCookiesPerDomain = DefaultPerDomainCookieLimit; // Do not rename (binary serialization)
|
||||
private int m_count = 0; // Do not rename (binary serialization)
|
||||
private string m_fqdnMyDomain = string.Empty; // Do not rename (binary serialization)
|
||||
|
||||
public CookieContainer()
|
||||
{
|
||||
string domain = HostInformation.DomainName;
|
||||
if (domain != null && domain.Length > 1)
|
||||
{
|
||||
_fqdnMyDomain = '.' + domain;
|
||||
m_fqdnMyDomain = '.' + domain;
|
||||
}
|
||||
// Otherwise it will remain string.Empty.
|
||||
}
|
||||
@@ -126,7 +126,7 @@ namespace System.Net
|
||||
{
|
||||
throw new ArgumentException(SR.net_toosmall, "Capacity");
|
||||
}
|
||||
_maxCookies = capacity;
|
||||
m_maxCookies = capacity;
|
||||
}
|
||||
|
||||
public CookieContainer(int capacity, int perDomainCapacity, int maxCookieSize) : this(capacity)
|
||||
@@ -135,12 +135,12 @@ namespace System.Net
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(perDomainCapacity), SR.Format(SR.net_cookie_capacity_range, "PerDomainCapacity", 0, capacity));
|
||||
}
|
||||
_maxCookiesPerDomain = perDomainCapacity;
|
||||
m_maxCookiesPerDomain = perDomainCapacity;
|
||||
if (maxCookieSize <= 0)
|
||||
{
|
||||
throw new ArgumentException(SR.net_toosmall, "MaxCookieSize");
|
||||
}
|
||||
_maxCookieSize = maxCookieSize;
|
||||
m_maxCookieSize = maxCookieSize;
|
||||
}
|
||||
|
||||
// NOTE: after shrinking the capacity, Count can become greater than Capacity.
|
||||
@@ -148,20 +148,20 @@ namespace System.Net
|
||||
{
|
||||
get
|
||||
{
|
||||
return _maxCookies;
|
||||
return m_maxCookies;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value <= 0 || (value < _maxCookiesPerDomain && _maxCookiesPerDomain != Int32.MaxValue))
|
||||
if (value <= 0 || (value < m_maxCookiesPerDomain && m_maxCookiesPerDomain != Int32.MaxValue))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(value), SR.Format(SR.net_cookie_capacity_range, "Capacity", 0, _maxCookiesPerDomain));
|
||||
throw new ArgumentOutOfRangeException(nameof(value), SR.Format(SR.net_cookie_capacity_range, "Capacity", 0, m_maxCookiesPerDomain));
|
||||
}
|
||||
if (value < _maxCookies)
|
||||
if (value < m_maxCookies)
|
||||
{
|
||||
_maxCookies = value;
|
||||
m_maxCookies = value;
|
||||
AgeCookies(null);
|
||||
}
|
||||
_maxCookies = value;
|
||||
m_maxCookies = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ namespace System.Net
|
||||
{
|
||||
get
|
||||
{
|
||||
return _count;
|
||||
return m_count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ namespace System.Net
|
||||
{
|
||||
get
|
||||
{
|
||||
return _maxCookieSize;
|
||||
return m_maxCookieSize;
|
||||
}
|
||||
set
|
||||
{
|
||||
@@ -188,7 +188,7 @@ namespace System.Net
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(value));
|
||||
}
|
||||
_maxCookieSize = value;
|
||||
m_maxCookieSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,20 +199,20 @@ namespace System.Net
|
||||
{
|
||||
get
|
||||
{
|
||||
return _maxCookiesPerDomain;
|
||||
return m_maxCookiesPerDomain;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value <= 0 || (value > _maxCookies && value != Int32.MaxValue))
|
||||
if (value <= 0 || (value > m_maxCookies && value != Int32.MaxValue))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(value));
|
||||
}
|
||||
if (value < _maxCookiesPerDomain)
|
||||
if (value < m_maxCookiesPerDomain)
|
||||
{
|
||||
_maxCookiesPerDomain = value;
|
||||
m_maxCookiesPerDomain = value;
|
||||
AgeCookies(null);
|
||||
}
|
||||
_maxCookiesPerDomain = value;
|
||||
m_maxCookiesPerDomain = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@ namespace System.Net
|
||||
|
||||
// We don't know cookie verification status, so re-create the cookie and verify it.
|
||||
Cookie new_cookie = cookie.Clone();
|
||||
new_cookie.VerifySetDefaults(new_cookie.Variant, uri, IsLocalDomain(uri.Host), _fqdnMyDomain, true, true);
|
||||
new_cookie.VerifySetDefaults(new_cookie.Variant, uri, IsLocalDomain(uri.Host), m_fqdnMyDomain, true, true);
|
||||
|
||||
Add(new_cookie, true);
|
||||
}
|
||||
@@ -272,22 +272,22 @@ namespace System.Net
|
||||
{
|
||||
PathList pathList;
|
||||
|
||||
if (cookie.Value.Length > _maxCookieSize)
|
||||
if (cookie.Value.Length > m_maxCookieSize)
|
||||
{
|
||||
if (throwOnError)
|
||||
{
|
||||
throw new CookieException(SR.Format(SR.net_cookie_size, cookie.ToString(), _maxCookieSize));
|
||||
throw new CookieException(SR.Format(SR.net_cookie_size, cookie.ToString(), m_maxCookieSize));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
lock (_domainTable)
|
||||
lock (m_domainTable)
|
||||
{
|
||||
if (!_domainTable.TryGetValue(cookie.DomainKey, out pathList))
|
||||
if (!m_domainTable.TryGetValue(cookie.DomainKey, out pathList))
|
||||
{
|
||||
_domainTable[cookie.DomainKey] = (pathList = PathList.Create());
|
||||
m_domainTable[cookie.DomainKey] = (pathList = PathList.Create());
|
||||
}
|
||||
}
|
||||
int domain_count = pathList.GetCookiesCount();
|
||||
@@ -313,18 +313,18 @@ namespace System.Net
|
||||
if (idx != -1)
|
||||
{
|
||||
cookies.RemoveAt(idx);
|
||||
--_count;
|
||||
--m_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is about real cookie adding, check Capacity first
|
||||
if (domain_count >= _maxCookiesPerDomain && !AgeCookies(cookie.DomainKey))
|
||||
if (domain_count >= m_maxCookiesPerDomain && !AgeCookies(cookie.DomainKey))
|
||||
{
|
||||
return; // Cannot age: reject new cookie
|
||||
}
|
||||
else if (_count >= _maxCookies && !AgeCookies(null))
|
||||
else if (m_count >= m_maxCookies && !AgeCookies(null))
|
||||
{
|
||||
return; // Cannot age: reject new cookie
|
||||
}
|
||||
@@ -332,7 +332,7 @@ namespace System.Net
|
||||
// About to change the collection
|
||||
lock (cookies)
|
||||
{
|
||||
_count += cookies.InternalAdd(cookie, true);
|
||||
m_count += cookies.InternalAdd(cookie, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -360,8 +360,8 @@ namespace System.Net
|
||||
// Param. 'domain' == null means to age in the whole container.
|
||||
private bool AgeCookies(string domain)
|
||||
{
|
||||
Debug.Assert(_maxCookies != 0);
|
||||
Debug.Assert(_maxCookiesPerDomain != 0);
|
||||
Debug.Assert(m_maxCookies != 0);
|
||||
Debug.Assert(m_maxCookiesPerDomain != 0);
|
||||
|
||||
int removed = 0;
|
||||
DateTime oldUsed = DateTime.MaxValue;
|
||||
@@ -377,15 +377,15 @@ namespace System.Net
|
||||
float remainingFraction = 1.0F;
|
||||
|
||||
// The container was shrunk, might need additional cleanup for each domain
|
||||
if (_count > _maxCookies)
|
||||
if (m_count > m_maxCookies)
|
||||
{
|
||||
// Means the fraction of the container to be left.
|
||||
// Each domain will be cut accordingly.
|
||||
remainingFraction = (float)_maxCookies / (float)_count;
|
||||
remainingFraction = (float)m_maxCookies / (float)m_count;
|
||||
}
|
||||
lock (_domainTable)
|
||||
lock (m_domainTable)
|
||||
{
|
||||
foreach (KeyValuePair<string, PathList> entry in _domainTable)
|
||||
foreach (KeyValuePair<string, PathList> entry in m_domainTable)
|
||||
{
|
||||
if (domain == null)
|
||||
{
|
||||
@@ -395,7 +395,7 @@ namespace System.Net
|
||||
else
|
||||
{
|
||||
tempDomain = domain;
|
||||
_domainTable.TryGetValue(domain, out pathList);
|
||||
m_domainTable.TryGetValue(domain, out pathList);
|
||||
}
|
||||
|
||||
domain_count = 0; // Cookies in the domain
|
||||
@@ -406,7 +406,7 @@ namespace System.Net
|
||||
CookieCollection cc = pair.Value;
|
||||
itemp = ExpireCollection(cc);
|
||||
removed += itemp;
|
||||
_count -= itemp; // Update this container's count
|
||||
m_count -= itemp; // Update this container's count
|
||||
domain_count += cc.Count;
|
||||
|
||||
// We also find the least used cookie collection in ENTIRE container.
|
||||
@@ -421,7 +421,7 @@ namespace System.Net
|
||||
}
|
||||
|
||||
// Check if we have reduced to the limit of the domain by expiration only.
|
||||
int min_count = Math.Min((int)(domain_count * remainingFraction), Math.Min(_maxCookiesPerDomain, _maxCookies) - 1);
|
||||
int min_count = Math.Min((int)(domain_count * remainingFraction), Math.Min(m_maxCookiesPerDomain, m_maxCookies) - 1);
|
||||
if (domain_count > min_count)
|
||||
{
|
||||
// This case requires sorting all domain collections by timestamp.
|
||||
@@ -449,7 +449,7 @@ namespace System.Net
|
||||
{
|
||||
cc.RemoveAt(0);
|
||||
--domain_count;
|
||||
--_count;
|
||||
--m_count;
|
||||
++removed;
|
||||
}
|
||||
}
|
||||
@@ -492,10 +492,10 @@ namespace System.Net
|
||||
// Remove oldest cookies from the least used collection.
|
||||
lock (lruCc)
|
||||
{
|
||||
while (_count >= _maxCookies && lruCc.Count > 0)
|
||||
while (m_count >= m_maxCookies && lruCc.Count > 0)
|
||||
{
|
||||
lruCc.RemoveAt(0);
|
||||
--_count;
|
||||
--m_count;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -556,7 +556,7 @@ namespace System.Net
|
||||
}
|
||||
|
||||
// Test domain membership.
|
||||
if (string.Compare(_fqdnMyDomain, 0, host, dot, _fqdnMyDomain.Length, StringComparison.OrdinalIgnoreCase) == 0)
|
||||
if (string.Compare(m_fqdnMyDomain, 0, host, dot, m_fqdnMyDomain.Length, StringComparison.OrdinalIgnoreCase) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -614,7 +614,7 @@ namespace System.Net
|
||||
throw new ArgumentNullException(nameof(cookie));
|
||||
}
|
||||
Cookie new_cookie = cookie.Clone();
|
||||
new_cookie.VerifySetDefaults(new_cookie.Variant, uri, IsLocalDomain(uri.Host), _fqdnMyDomain, true, true);
|
||||
new_cookie.VerifySetDefaults(new_cookie.Variant, uri, IsLocalDomain(uri.Host), m_fqdnMyDomain, true, true);
|
||||
|
||||
Add(new_cookie, true);
|
||||
}
|
||||
@@ -634,7 +634,7 @@ namespace System.Net
|
||||
foreach (Cookie c in cookies)
|
||||
{
|
||||
Cookie new_cookie = c.Clone();
|
||||
new_cookie.VerifySetDefaults(new_cookie.Variant, uri, isLocalDomain, _fqdnMyDomain, true, true);
|
||||
new_cookie.VerifySetDefaults(new_cookie.Variant, uri, isLocalDomain, m_fqdnMyDomain, true, true);
|
||||
Add(new_cookie, true);
|
||||
}
|
||||
}
|
||||
@@ -690,7 +690,7 @@ namespace System.Net
|
||||
|
||||
// This will set the default values from the response URI
|
||||
// AND will check for cookie validity
|
||||
if (!cookie.VerifySetDefaults(variant, uri, isLocalDomain, _fqdnMyDomain, true, isThrow))
|
||||
if (!cookie.VerifySetDefaults(variant, uri, isLocalDomain, m_fqdnMyDomain, true, isThrow))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -730,7 +730,7 @@ namespace System.Net
|
||||
|
||||
internal CookieCollection InternalGetCookies(Uri uri)
|
||||
{
|
||||
if (_count == 0)
|
||||
if (m_count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -755,11 +755,11 @@ namespace System.Net
|
||||
// DNS.resolve may return short names even for other inet domains ;-(
|
||||
// We _don't_ know what the exact domain is, so try also grab short hostname cookies.
|
||||
// Grab long name from the local domain
|
||||
if (_fqdnMyDomain != null && _fqdnMyDomain.Length != 0)
|
||||
if (m_fqdnMyDomain != null && m_fqdnMyDomain.Length != 0)
|
||||
{
|
||||
domainAttributeMatchAnyCookieVariant.Add(fqdnRemote + _fqdnMyDomain);
|
||||
domainAttributeMatchAnyCookieVariant.Add(fqdnRemote + m_fqdnMyDomain);
|
||||
// Grab the local domain itself
|
||||
domainAttributeMatchAnyCookieVariant.Add(_fqdnMyDomain);
|
||||
domainAttributeMatchAnyCookieVariant.Add(m_fqdnMyDomain);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -810,9 +810,9 @@ namespace System.Net
|
||||
bool found = false;
|
||||
bool defaultAdded = false;
|
||||
PathList pathList;
|
||||
lock (_domainTable)
|
||||
lock (m_domainTable)
|
||||
{
|
||||
if (!_domainTable.TryGetValue(domainAttribute[i], out pathList))
|
||||
if (!m_domainTable.TryGetValue(domainAttribute[i], out pathList))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -858,9 +858,9 @@ namespace System.Net
|
||||
// (This is the only place that does domain removal)
|
||||
if (pathList.Count == 0)
|
||||
{
|
||||
lock (_domainTable)
|
||||
lock (m_domainTable)
|
||||
{
|
||||
_domainTable.Remove(domainAttribute[i]);
|
||||
m_domainTable.Remove(domainAttribute[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -881,7 +881,7 @@ namespace System.Net
|
||||
{
|
||||
// If expired, remove from container and don't add to the destination
|
||||
source.RemoveAt(idx);
|
||||
--_count;
|
||||
--m_count;
|
||||
--idx;
|
||||
}
|
||||
else
|
||||
@@ -963,7 +963,7 @@ namespace System.Net
|
||||
|
||||
optCookie2 = cookies.IsOtherVersionSeen ?
|
||||
(Cookie.SpecialAttributeLiteral +
|
||||
Cookie.VersionAttributeName +
|
||||
CookieFields.VersionAttributeName +
|
||||
Cookie.EqualsLiteral +
|
||||
Cookie.MaxSupportedVersionString) : string.Empty;
|
||||
|
||||
@@ -989,14 +989,14 @@ namespace System.Net
|
||||
{
|
||||
// Usage of PathList depends on it being shallowly immutable;
|
||||
// adding any mutable fields to it would result in breaks.
|
||||
private readonly SortedList<string, CookieCollection> _list;
|
||||
private readonly SortedList<string, CookieCollection> m_list; // Do not rename (binary serialization)
|
||||
|
||||
public static PathList Create() => new PathList(new SortedList<string, CookieCollection>(PathListComparer.StaticInstance));
|
||||
|
||||
private PathList(SortedList<string, CookieCollection> list)
|
||||
{
|
||||
Debug.Assert(list != null, $"{nameof(list)} must not be null.");
|
||||
_list = list;
|
||||
m_list = list;
|
||||
}
|
||||
|
||||
public int Count
|
||||
@@ -1005,7 +1005,7 @@ namespace System.Net
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return _list.Count;
|
||||
return m_list.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1015,7 +1015,7 @@ namespace System.Net
|
||||
int count = 0;
|
||||
lock (SyncRoot)
|
||||
{
|
||||
foreach (KeyValuePair<string, CookieCollection> pair in _list)
|
||||
foreach (KeyValuePair<string, CookieCollection> pair in m_list)
|
||||
{
|
||||
CookieCollection cc = pair.Value;
|
||||
count += cc.Count;
|
||||
@@ -1031,7 +1031,7 @@ namespace System.Net
|
||||
lock (SyncRoot)
|
||||
{
|
||||
CookieCollection value;
|
||||
_list.TryGetValue(s, out value);
|
||||
m_list.TryGetValue(s, out value);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -1040,7 +1040,7 @@ namespace System.Net
|
||||
lock (SyncRoot)
|
||||
{
|
||||
Debug.Assert(value != null);
|
||||
_list[s] = value;
|
||||
m_list[s] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1049,7 +1049,7 @@ namespace System.Net
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return _list.GetEnumerator();
|
||||
return m_list.GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1057,8 +1057,8 @@ namespace System.Net
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(_list != null, $"{nameof(PathList)} should never be default initialized and only ever created with {nameof(Create)}.");
|
||||
return _list;
|
||||
Debug.Assert(m_list != null, $"{nameof(PathList)} should never be default initialized and only ever created with {nameof(Create)}.");
|
||||
return m_list;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,19 +4,7 @@
|
||||
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
// The uap #define is used in some source files to indicate we are compiling classes
|
||||
// directly into the UWP System.Net.Http.dll implementation assembly in order to use internal class
|
||||
// methods. Internal methods are needed in order to map cookie response headers from the WinRT Windows.Web.Http APIs.
|
||||
// Windows.Web.Http is used underneath the System.Net.Http classes on .NET Native. Having other similarly
|
||||
// named classes would normally conflict with the public System.Net namespace classes.
|
||||
// So, we need to move the classes to a different namespace. Those classes are never
|
||||
// exposed up to user code so there isn't a problem. In the future, we might expose some of the internal methods
|
||||
// as new public APIs and then we can remove this duplicate source code inclusion in the binaries.
|
||||
#if uap
|
||||
namespace System.Net.Internal
|
||||
#else
|
||||
namespace System.Net
|
||||
#endif
|
||||
{
|
||||
[Serializable]
|
||||
public class CookieException : FormatException, ISerializable
|
||||
@@ -36,11 +24,12 @@ namespace System.Net
|
||||
protected CookieException(SerializationInfo serializationInfo, StreamingContext streamingContext)
|
||||
: base(serializationInfo, streamingContext)
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
void ISerializable.GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
|
||||
{
|
||||
GetObjectData(serializationInfo, streamingContext);
|
||||
base.GetObjectData(serializationInfo, streamingContext);
|
||||
}
|
||||
|
||||
public override void GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
|
||||
|
||||
@@ -31,6 +31,15 @@ namespace System.Net
|
||||
{
|
||||
throw new ArgumentNullException(nameof(authType));
|
||||
}
|
||||
|
||||
if ((cred is SystemNetworkCredential)
|
||||
&& !((string.Equals(authType, NegotiationInfoClass.NTLM, StringComparison.OrdinalIgnoreCase))
|
||||
|| (string.Equals(authType, NegotiationInfoClass.Kerberos, StringComparison.OrdinalIgnoreCase))
|
||||
|| (string.Equals(authType, NegotiationInfoClass.Negotiate, StringComparison.OrdinalIgnoreCase)))
|
||||
)
|
||||
{
|
||||
throw new ArgumentException(SR.Format(SR.net_nodefaultcreds, authType), nameof(authType));
|
||||
}
|
||||
|
||||
++_version;
|
||||
|
||||
@@ -67,6 +76,15 @@ namespace System.Net
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(port));
|
||||
}
|
||||
|
||||
if ((credential is SystemNetworkCredential)
|
||||
&& !((string.Equals(authenticationType, NegotiationInfoClass.NTLM, StringComparison.OrdinalIgnoreCase))
|
||||
|| (string.Equals(authenticationType, NegotiationInfoClass.Kerberos, StringComparison.OrdinalIgnoreCase))
|
||||
|| (string.Equals(authenticationType, NegotiationInfoClass.Negotiate, StringComparison.OrdinalIgnoreCase)))
|
||||
)
|
||||
{
|
||||
throw new ArgumentException(SR.Format(SR.net_nodefaultcreds, authenticationType), nameof(authenticationType));
|
||||
}
|
||||
|
||||
++_version;
|
||||
|
||||
|
||||
@@ -173,9 +173,25 @@ namespace System.Net
|
||||
PrivateScopeId = (uint)scopeid;
|
||||
}
|
||||
|
||||
internal unsafe IPAddress(ushort* numbers, int numbersLength, uint scopeid)
|
||||
{
|
||||
Debug.Assert(numbers != null);
|
||||
Debug.Assert(numbersLength == NumberOfLabels);
|
||||
|
||||
var arr = new ushort[NumberOfLabels];
|
||||
for (int i = 0; i < arr.Length; i++)
|
||||
{
|
||||
arr[i] = numbers[i];
|
||||
}
|
||||
|
||||
_numbers = arr;
|
||||
PrivateScopeId = scopeid;
|
||||
}
|
||||
|
||||
private IPAddress(ushort[] numbers, uint scopeid)
|
||||
{
|
||||
Debug.Assert(numbers != null);
|
||||
Debug.Assert(numbers.Length == NumberOfLabels);
|
||||
|
||||
_numbers = numbers;
|
||||
PrivateScopeId = scopeid;
|
||||
@@ -267,8 +283,9 @@ namespace System.Net
|
||||
byte[] bytes;
|
||||
if (IsIPv6)
|
||||
{
|
||||
bytes = new byte[NumberOfLabels * 2];
|
||||
Debug.Assert(_numbers != null && _numbers.Length == NumberOfLabels);
|
||||
|
||||
bytes = new byte[IPAddressParserStatics.IPv6AddressBytes];
|
||||
int j = 0;
|
||||
for (int i = 0; i < NumberOfLabels; i++)
|
||||
{
|
||||
@@ -347,8 +364,8 @@ namespace System.Net
|
||||
if (_toString == null)
|
||||
{
|
||||
_toString = IsIPv4 ?
|
||||
IPAddressParser.IPv4AddressToString(GetAddressBytes()) :
|
||||
IPAddressParser.IPv6AddressToString(GetAddressBytes(), PrivateScopeId);
|
||||
IPAddressParser.IPv4AddressToString(PrivateAddress) :
|
||||
IPAddressParser.IPv6AddressToString(_numbers, PrivateScopeId);
|
||||
}
|
||||
|
||||
return _toString;
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Net
|
||||
{
|
||||
internal static class IPAddressPal
|
||||
{
|
||||
public const uint SuccessErrorCode = 0;
|
||||
|
||||
public static unsafe uint Ipv4AddressToString(byte[] address, StringBuilder buffer)
|
||||
{
|
||||
Debug.Assert(address != null);
|
||||
Debug.Assert(address.Length == IPAddressParserStatics.IPv4AddressBytes);
|
||||
Debug.Assert(buffer != null);
|
||||
Debug.Assert(buffer.Capacity >= IPAddressParser.INET_ADDRSTRLEN);
|
||||
|
||||
return Interop.Sys.IPAddressToString(address, false, buffer);
|
||||
}
|
||||
|
||||
public static unsafe uint Ipv6AddressToString(byte[] address, uint scopeId, StringBuilder buffer)
|
||||
{
|
||||
Debug.Assert(address != null);
|
||||
Debug.Assert(address.Length == IPAddressParserStatics.IPv6AddressBytes);
|
||||
Debug.Assert(buffer != null);
|
||||
Debug.Assert(buffer.Capacity >= IPAddressParser.INET6_ADDRSTRLEN);
|
||||
|
||||
return Interop.Sys.IPAddressToString(address, true, buffer, scopeId);
|
||||
}
|
||||
|
||||
public static unsafe uint Ipv4StringToAddress(string ipString, byte* bytes, int bytesLength, out ushort port)
|
||||
{
|
||||
Debug.Assert(ipString != null);
|
||||
Debug.Assert(bytes != null);
|
||||
Debug.Assert(bytesLength >= IPAddressParserStatics.IPv4AddressBytes);
|
||||
|
||||
return unchecked((uint)Interop.Sys.IPv4StringToAddress(ipString, bytes, bytesLength, out port));
|
||||
}
|
||||
|
||||
private static bool IsHexString(string input, int startIndex)
|
||||
{
|
||||
// "0[xX][A-Fa-f0-9]+"
|
||||
if (startIndex >= input.Length - 3 ||
|
||||
input[startIndex] != '0' ||
|
||||
(input[startIndex + 1] != 'x' && input[startIndex + 1] != 'X'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = startIndex + 2; i < input.Length; i++)
|
||||
{
|
||||
char c = input[i];
|
||||
if ((c < 'A' || c > 'F') && (c < 'a' || c > 'f') && (c < '0' || c > '9'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Splits an IPv6 address of the form '[.*]:.*' into its host and port parts and removes
|
||||
// surrounding square brackets, if any.
|
||||
private static bool TryPreprocessIPv6Address(string input, out string host, out string port)
|
||||
{
|
||||
Debug.Assert(input != null);
|
||||
|
||||
if (input == "")
|
||||
{
|
||||
host = null;
|
||||
port = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasLeadingBracket = input[0] == '[';
|
||||
int trailingBracketIndex = -1;
|
||||
int portSeparatorIndex = -1;
|
||||
for (int i = input.Length - 1; i >= 0; i--)
|
||||
{
|
||||
if (input[i] == ']')
|
||||
{
|
||||
trailingBracketIndex = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (input[i] == ':')
|
||||
{
|
||||
if (i >= 1 && input[i - 1] == ']')
|
||||
{
|
||||
trailingBracketIndex = i - 1;
|
||||
portSeparatorIndex = i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool hasTrailingBracket = trailingBracketIndex != -1;
|
||||
if (hasLeadingBracket != hasTrailingBracket)
|
||||
{
|
||||
host = null;
|
||||
port = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hasLeadingBracket)
|
||||
{
|
||||
host = input;
|
||||
port = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
host = input.Substring(1, trailingBracketIndex - 1);
|
||||
port = portSeparatorIndex != -1 && !IsHexString(input, portSeparatorIndex + 1) ?
|
||||
input.Substring(portSeparatorIndex + 1) :
|
||||
null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static unsafe uint Ipv6StringToAddress(string ipString, byte* bytes, int bytesLength, out uint scope)
|
||||
{
|
||||
Debug.Assert(ipString != null);
|
||||
Debug.Assert(bytes != null);
|
||||
Debug.Assert(bytesLength >= IPAddressParserStatics.IPv6AddressBytes);
|
||||
|
||||
string host, port;
|
||||
if (!TryPreprocessIPv6Address(ipString, out host, out port))
|
||||
{
|
||||
scope = 0;
|
||||
return unchecked((uint)Interop.Sys.GetAddrInfoErrorFlags.EAI_NONAME);
|
||||
}
|
||||
|
||||
return unchecked((uint)Interop.Sys.IPv6StringToAddress(host, port, bytes, bytesLength, out scope));
|
||||
}
|
||||
|
||||
public static SocketError GetSocketErrorForErrorCode(uint status)
|
||||
{
|
||||
switch (unchecked((int)status))
|
||||
{
|
||||
case 0:
|
||||
return SocketError.Success;
|
||||
case (int)Interop.Sys.GetAddrInfoErrorFlags.EAI_BADFLAGS:
|
||||
case (int)Interop.Sys.GetAddrInfoErrorFlags.EAI_NONAME:
|
||||
return SocketError.InvalidArgument;
|
||||
default:
|
||||
return (SocketError)status;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Net
|
||||
{
|
||||
internal static class IPAddressPal
|
||||
{
|
||||
public const uint SuccessErrorCode = Interop.StatusOptions.STATUS_SUCCESS;
|
||||
|
||||
public static uint Ipv4AddressToString(byte[] address, StringBuilder buffer)
|
||||
{
|
||||
Debug.Assert(address != null);
|
||||
Debug.Assert(address.Length == IPAddressParserStatics.IPv4AddressBytes);
|
||||
Debug.Assert(buffer != null);
|
||||
Debug.Assert(buffer.Capacity >= IPAddressParser.INET_ADDRSTRLEN);
|
||||
|
||||
uint length = (uint)buffer.Capacity;
|
||||
return Interop.NtDll.RtlIpv4AddressToStringExW(address, 0, buffer, ref length);
|
||||
}
|
||||
|
||||
public static uint Ipv6AddressToString(byte[] address, uint scopeId, StringBuilder buffer)
|
||||
{
|
||||
Debug.Assert(address != null);
|
||||
Debug.Assert(address.Length == IPAddressParserStatics.IPv6AddressBytes);
|
||||
Debug.Assert(buffer != null);
|
||||
Debug.Assert(buffer.Capacity >= IPAddressParser.INET6_ADDRSTRLEN);
|
||||
|
||||
uint length = (uint)buffer.Capacity;
|
||||
return Interop.NtDll.RtlIpv6AddressToStringExW(address, scopeId, 0, buffer, ref length);
|
||||
}
|
||||
|
||||
public static unsafe uint Ipv4StringToAddress(string ipString, byte* bytes, int bytesLength, out ushort port)
|
||||
{
|
||||
Debug.Assert(ipString != null);
|
||||
Debug.Assert(bytes != null);
|
||||
Debug.Assert(bytesLength == IPAddressParserStatics.IPv4AddressBytes);
|
||||
|
||||
return Interop.NtDll.RtlIpv4StringToAddressExW(ipString, false, bytes, out port);
|
||||
}
|
||||
|
||||
public static unsafe uint Ipv6StringToAddress(string ipString, byte* bytes, int bytesLength, out uint scope)
|
||||
{
|
||||
Debug.Assert(ipString != null);
|
||||
Debug.Assert(bytes != null);
|
||||
Debug.Assert(bytesLength == IPAddressParserStatics.IPv6AddressBytes);
|
||||
|
||||
ushort port;
|
||||
return Interop.NtDll.RtlIpv6StringToAddressExW(ipString, bytes, out scope, out port);
|
||||
}
|
||||
|
||||
public static SocketError GetSocketErrorForErrorCode(uint status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case Interop.StatusOptions.STATUS_SUCCESS:
|
||||
return SocketError.Success;
|
||||
case Interop.StatusOptions.STATUS_INVALID_PARAMETER:
|
||||
return SocketError.InvalidArgument;
|
||||
default:
|
||||
return (SocketError)status;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
@@ -9,9 +11,6 @@ namespace System.Net
|
||||
{
|
||||
internal class IPAddressParser
|
||||
{
|
||||
internal const int INET_ADDRSTRLEN = 22;
|
||||
internal const int INET6_ADDRSTRLEN = 65;
|
||||
|
||||
internal static unsafe IPAddress Parse(string ipString, bool tryParse)
|
||||
{
|
||||
if (ipString == null)
|
||||
@@ -23,41 +22,23 @@ namespace System.Net
|
||||
throw new ArgumentNullException(nameof(ipString));
|
||||
}
|
||||
|
||||
uint error = 0;
|
||||
|
||||
// IPv6 Changes: Detect probable IPv6 addresses and use separate parse method.
|
||||
if (ipString.IndexOf(':') != -1)
|
||||
{
|
||||
// If the address string contains the colon character
|
||||
// then it can only be an IPv6 address. Use a separate
|
||||
// parse method to unpick it all. Note: we don't support
|
||||
// port specification at the end of address and so can
|
||||
// make this decision.
|
||||
// If the address string contains the colon character then it can only be an IPv6 address.
|
||||
// This is valid because we don't support/parse a port specification at the end of an IPv4 address.
|
||||
uint scope;
|
||||
byte* bytes = stackalloc byte[IPAddressParserStatics.IPv6AddressBytes];
|
||||
error = IPAddressPal.Ipv6StringToAddress(ipString, bytes, IPAddressParserStatics.IPv6AddressBytes, out scope);
|
||||
|
||||
if (error == IPAddressPal.SuccessErrorCode)
|
||||
ushort* numbers = stackalloc ushort[IPAddressParserStatics.IPv6AddressShorts];
|
||||
if (Ipv6StringToAddress(ipString, numbers, IPAddressParserStatics.IPv6AddressShorts, out scope))
|
||||
{
|
||||
// AppCompat: .Net 4.5 ignores a correct port if the address was specified in brackets.
|
||||
// Will still throw for an incorrect port.
|
||||
return new IPAddress(bytes, IPAddressParserStatics.IPv6AddressBytes, (long)scope);
|
||||
return new IPAddress(numbers, IPAddressParserStatics.IPv6AddressShorts, scope);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ushort port;
|
||||
byte* bytes = stackalloc byte[IPAddressParserStatics.IPv4AddressBytes];
|
||||
error = IPAddressPal.Ipv4StringToAddress(ipString, bytes, IPAddressParserStatics.IPv4AddressBytes, out port);
|
||||
|
||||
if (error == IPAddressPal.SuccessErrorCode)
|
||||
long address;
|
||||
if (Ipv4StringToAddress(ipString, out address))
|
||||
{
|
||||
if (port != 0)
|
||||
{
|
||||
throw new FormatException(SR.dns_bad_ip_address);
|
||||
}
|
||||
|
||||
return new IPAddress(bytes, IPAddressParserStatics.IPv4AddressBytes);
|
||||
return new IPAddress(address);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,38 +47,217 @@ namespace System.Net
|
||||
return null;
|
||||
}
|
||||
|
||||
Exception e = new SocketException(IPAddressPal.GetSocketErrorForErrorCode(error), error);
|
||||
throw new FormatException(SR.dns_bad_ip_address, e);
|
||||
throw new FormatException(SR.dns_bad_ip_address, new SocketException(SocketError.InvalidArgument));
|
||||
}
|
||||
|
||||
internal static string IPv4AddressToString(byte[] numbers)
|
||||
internal static unsafe string IPv4AddressToString(uint address)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(INET_ADDRSTRLEN);
|
||||
uint errorCode = IPAddressPal.Ipv4AddressToString(numbers, sb);
|
||||
const int MaxLength = 15;
|
||||
char* addressString = stackalloc char[MaxLength];
|
||||
int offset = MaxLength;
|
||||
|
||||
if (errorCode == IPAddressPal.SuccessErrorCode)
|
||||
FormatIPv4AddressNumber((int)((address >> 24) & 0xFF), addressString, ref offset);
|
||||
addressString[--offset] = '.';
|
||||
FormatIPv4AddressNumber((int)((address >> 16) & 0xFF), addressString, ref offset);
|
||||
addressString[--offset] = '.';
|
||||
FormatIPv4AddressNumber((int)((address >> 8) & 0xFF), addressString, ref offset);
|
||||
addressString[--offset] = '.';
|
||||
FormatIPv4AddressNumber((int)(address & 0xFF), addressString, ref offset);
|
||||
|
||||
return new string(addressString, offset, MaxLength - offset);
|
||||
}
|
||||
|
||||
internal static string IPv6AddressToString(ushort[] address, uint scopeId)
|
||||
{
|
||||
Debug.Assert(address != null);
|
||||
Debug.Assert(address.Length == IPAddressParserStatics.IPv6AddressShorts);
|
||||
|
||||
const int INET6_ADDRSTRLEN = 65;
|
||||
StringBuilder buffer = StringBuilderCache.Acquire(INET6_ADDRSTRLEN);
|
||||
|
||||
if (IPv6AddressHelper.ShouldHaveIpv4Embedded(address))
|
||||
{
|
||||
return sb.ToString();
|
||||
// We need to treat the last 2 ushorts as a 4-byte IPv4 address,
|
||||
// so output the first 6 ushorts normally, followed by the IPv4 address.
|
||||
AppendSections(address, 0, 6, buffer);
|
||||
if (buffer[buffer.Length - 1] != ':')
|
||||
{
|
||||
buffer.Append(':');
|
||||
}
|
||||
buffer.Append(IPAddressParser.IPv4AddressToString(ExtractIPv4Address(address)));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new SocketException(IPAddressPal.GetSocketErrorForErrorCode(errorCode), errorCode);
|
||||
// No IPv4 address. Output all 8 sections as part of the IPv6 address
|
||||
// with normal formatting rules.
|
||||
AppendSections(address, 0, 8, buffer);
|
||||
}
|
||||
|
||||
// If there's a scope ID, append it.
|
||||
if (scopeId != 0)
|
||||
{
|
||||
buffer.Append('%').Append(scopeId);
|
||||
}
|
||||
|
||||
return StringBuilderCache.GetStringAndRelease(buffer);
|
||||
}
|
||||
|
||||
internal static string IPv6AddressToString(byte[] numbers, uint scopeId)
|
||||
private static unsafe void FormatIPv4AddressNumber(int number, char* addressString, ref int offset)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(INET6_ADDRSTRLEN);
|
||||
uint errorCode = IPAddressPal.Ipv6AddressToString(numbers, scopeId, sb);
|
||||
|
||||
if (errorCode == IPAddressPal.SuccessErrorCode)
|
||||
int i = offset;
|
||||
do
|
||||
{
|
||||
return sb.ToString();
|
||||
int rem;
|
||||
number = Math.DivRem(number, 10, out rem);
|
||||
addressString[--i] = (char)('0' + rem);
|
||||
} while (number != 0);
|
||||
offset = i;
|
||||
}
|
||||
|
||||
public static unsafe bool Ipv4StringToAddress(string ipString, out long address)
|
||||
{
|
||||
Debug.Assert(ipString != null);
|
||||
|
||||
long tmpAddr;
|
||||
int end = ipString.Length;
|
||||
fixed (char* ipStringPtr = ipString)
|
||||
{
|
||||
tmpAddr = IPv4AddressHelper.ParseNonCanonical(ipStringPtr, 0, ref end, notImplicitFile: true);
|
||||
}
|
||||
|
||||
if (tmpAddr != IPv4AddressHelper.Invalid && end == ipString.Length)
|
||||
{
|
||||
// IPv4AddressHelper.ParseNonCanonical returns the bytes in the inverse order.
|
||||
// Reverse them and return success.
|
||||
address =
|
||||
((0xFF000000 & tmpAddr) >> 24) |
|
||||
((0x00FF0000 & tmpAddr) >> 8) |
|
||||
((0x0000FF00 & tmpAddr) << 8) |
|
||||
((0x000000FF & tmpAddr) << 24);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new SocketException(IPAddressPal.GetSocketErrorForErrorCode(errorCode), errorCode);
|
||||
// Failed to parse the address.
|
||||
address = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe bool Ipv6StringToAddress(string ipString, ushort* numbers, int numbersLength, out uint scope)
|
||||
{
|
||||
Debug.Assert(ipString != null);
|
||||
Debug.Assert(numbers != null);
|
||||
Debug.Assert(numbersLength >= IPAddressParserStatics.IPv6AddressShorts);
|
||||
|
||||
int end = ipString.Length;
|
||||
fixed (char* name = ipString)
|
||||
{
|
||||
if (IPv6AddressHelper.IsValidStrict(name, 0, ref end) || (end != ipString.Length))
|
||||
{
|
||||
string scopeId = null;
|
||||
IPv6AddressHelper.Parse(ipString, numbers, 0, ref scopeId);
|
||||
|
||||
long result = 0;
|
||||
if (!string.IsNullOrEmpty(scopeId))
|
||||
{
|
||||
if (scopeId.Length < 2)
|
||||
{
|
||||
scope = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 1; i < scopeId.Length; i++)
|
||||
{
|
||||
char c = scopeId[i];
|
||||
if (c < '0' || c > '9')
|
||||
{
|
||||
scope = 0;
|
||||
return false;
|
||||
}
|
||||
result = (result * 10) + (c - '0');
|
||||
if (result > uint.MaxValue)
|
||||
{
|
||||
scope = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scope = (uint)result;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
scope = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends each of the numbers in address in indexed range [fromInclusive, toExclusive),
|
||||
/// while also replacing the longest sequence of 0s found in that range with "::", as long
|
||||
/// as the sequence is more than one 0.
|
||||
/// </summary>
|
||||
private static void AppendSections(ushort[] address, int fromInclusive, int toExclusive, StringBuilder buffer)
|
||||
{
|
||||
// Find the longest sequence of zeros to be combined into a "::"
|
||||
(int zeroStart, int zeroEnd) = IPv6AddressHelper.FindCompressionRange(address, fromInclusive, toExclusive);
|
||||
bool needsColon = false;
|
||||
|
||||
// Output all of the numbers before the zero sequence
|
||||
for (int i = fromInclusive; i < zeroStart; i++)
|
||||
{
|
||||
if (needsColon)
|
||||
{
|
||||
buffer.Append(':');
|
||||
}
|
||||
needsColon = true;
|
||||
AppendHex(address[i], buffer);
|
||||
}
|
||||
|
||||
// Output the zero sequence if there is one
|
||||
if (zeroStart >= 0)
|
||||
{
|
||||
buffer.Append("::");
|
||||
needsColon = false;
|
||||
fromInclusive = zeroEnd;
|
||||
}
|
||||
|
||||
// Output everything after the zero sequence
|
||||
for (int i = fromInclusive; i < toExclusive; i++)
|
||||
{
|
||||
if (needsColon)
|
||||
{
|
||||
buffer.Append(':');
|
||||
}
|
||||
needsColon = true;
|
||||
AppendHex(address[i], buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Appends a number as hexadecimal (without the leading "0x") to the StringBuilder.</summary>
|
||||
private static unsafe void AppendHex(ushort value, StringBuilder buffer)
|
||||
{
|
||||
const int MaxLength = sizeof(ushort) * 2; // two hex chars per byte
|
||||
char* chars = stackalloc char[MaxLength];
|
||||
int pos = MaxLength;
|
||||
|
||||
do
|
||||
{
|
||||
int rem = value % 16;
|
||||
value /= 16;
|
||||
chars[--pos] = rem < 10 ? (char)('0' + rem) : (char)('a' + (rem - 10));
|
||||
Debug.Assert(pos >= 0);
|
||||
}
|
||||
while (value != 0);
|
||||
|
||||
buffer.Append(chars + pos, MaxLength - pos);
|
||||
}
|
||||
|
||||
/// <summary>Extracts the IPv4 address from the end of the IPv6 address byte array.</summary>
|
||||
private static uint ExtractIPv4Address(ushort[] address) => (uint)(Reverse(address[7]) << 16) | Reverse(address[6]);
|
||||
|
||||
/// <summary>Reverses the two bytes in the ushort.</summary>
|
||||
private static ushort Reverse(ushort number) => (ushort)(((number >> 8) & 0xFF) | ((number << 8) & 0xFF00));
|
||||
}
|
||||
}
|
||||
|
||||
329
external/corefx/src/System.Net.Primitives/src/System/Net/IPv4AddressHelper.cs
vendored
Normal file
329
external/corefx/src/System.Net.Primitives/src/System/Net/IPv4AddressHelper.cs
vendored
Normal file
@@ -0,0 +1,329 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace System
|
||||
{
|
||||
internal static class IPv4AddressHelper
|
||||
{
|
||||
internal const long Invalid = -1;
|
||||
private const long MaxIPv4Value = uint.MaxValue; // the native parser cannot handle MaxIPv4Value, only MaxIPv4Value - 1
|
||||
private const int Octal = 8;
|
||||
private const int Decimal = 10;
|
||||
private const int Hex = 16;
|
||||
|
||||
private const int NumberOfLabels = 4;
|
||||
|
||||
// Only called from the IPv6Helper, only parse the canonical format
|
||||
internal static unsafe int ParseHostNumber(string str, int start, int end)
|
||||
{
|
||||
byte* numbers = stackalloc byte[NumberOfLabels];
|
||||
ParseCanonical(str, numbers, start, end);
|
||||
return (numbers[0] << 24) + (numbers[1] << 16) + (numbers[2] << 8) + numbers[3];
|
||||
}
|
||||
|
||||
//
|
||||
// IsValid
|
||||
//
|
||||
// Performs IsValid on a substring. Updates the index to where we
|
||||
// believe the IPv4 address ends
|
||||
//
|
||||
// Inputs:
|
||||
// <argument> name
|
||||
// string containing possible IPv4 address
|
||||
//
|
||||
// <argument> start
|
||||
// offset in <name> to start checking for IPv4 address
|
||||
//
|
||||
// <argument> end
|
||||
// offset in <name> of the last character we can touch in the check
|
||||
//
|
||||
// Outputs:
|
||||
// <argument> end
|
||||
// index of last character in <name> we checked
|
||||
//
|
||||
// <argument> allowIPv6
|
||||
// enables parsing IPv4 addresses embedded in IPv6 address literals
|
||||
//
|
||||
// <argument> notImplicitFile
|
||||
// do not consider this URI holding an implicit filename
|
||||
//
|
||||
// <argument> unknownScheme
|
||||
// the check is made on an unknown scheme (suppress IPv4 canonicalization)
|
||||
//
|
||||
// Assumes:
|
||||
// The address string is terminated by either
|
||||
// end of the string, characters ':' '/' '\' '?'
|
||||
//
|
||||
//
|
||||
// Returns:
|
||||
// bool
|
||||
//
|
||||
// Throws:
|
||||
// Nothing
|
||||
//
|
||||
|
||||
//Remark: MUST NOT be used unless all input indexes are are verified and trusted.
|
||||
internal static unsafe bool IsValid(char* name, int start, ref int end, bool allowIPv6, bool notImplicitFile, bool unknownScheme)
|
||||
{
|
||||
// IPv6 can only have canonical IPv4 embedded. Unknown schemes will not attempt parsing of non-canonical IPv4 addresses.
|
||||
if (allowIPv6 || unknownScheme)
|
||||
{
|
||||
return IsValidCanonical(name, start, ref end, allowIPv6, notImplicitFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ParseNonCanonical(name, start, ref end, notImplicitFile) != Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// IsValidCanonical
|
||||
//
|
||||
// Checks if the substring is a valid canonical IPv4 address or an IPv4 address embedded in an IPv6 literal
|
||||
// This is an attempt to parse ABNF productions from RFC3986, Section 3.2.2:
|
||||
// IP-literal = "[" ( IPv6address / IPvFuture ) "]"
|
||||
// IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
|
||||
// dec-octet = DIGIT ; 0-9
|
||||
// / %x31-39 DIGIT ; 10-99
|
||||
// / "1" 2DIGIT ; 100-199
|
||||
// / "2" %x30-34 DIGIT ; 200-249
|
||||
// / "25" %x30-35 ; 250-255
|
||||
//
|
||||
internal static unsafe bool IsValidCanonical(char* name, int start, ref int end, bool allowIPv6, bool notImplicitFile)
|
||||
{
|
||||
int dots = 0;
|
||||
int number = 0;
|
||||
bool haveNumber = false;
|
||||
bool firstCharIsZero = false;
|
||||
|
||||
while (start < end)
|
||||
{
|
||||
char ch = name[start];
|
||||
if (allowIPv6)
|
||||
{
|
||||
// for ipv4 inside ipv6 the terminator is either ScopeId, prefix or ipv6 terminator
|
||||
if (ch == ']' || ch == '/' || ch == '%')
|
||||
break;
|
||||
}
|
||||
else if (ch == '/' || ch == '\\' || (notImplicitFile && (ch == ':' || ch == '?' || ch == '#')))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch <= '9' && ch >= '0')
|
||||
{
|
||||
if (!haveNumber && (ch == '0'))
|
||||
{
|
||||
if ((start + 1 < end) && name[start + 1] == '0')
|
||||
{
|
||||
// 00 is not allowed as a prefix.
|
||||
return false;
|
||||
}
|
||||
|
||||
firstCharIsZero = true;
|
||||
}
|
||||
|
||||
haveNumber = true;
|
||||
number = number * 10 + (name[start] - '0');
|
||||
if (number > 255)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (ch == '.')
|
||||
{
|
||||
if (!haveNumber || (number > 0 && firstCharIsZero))
|
||||
{
|
||||
// 0 is not allowed to prefix a number.
|
||||
return false;
|
||||
}
|
||||
++dots;
|
||||
haveNumber = false;
|
||||
number = 0;
|
||||
firstCharIsZero = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
++start;
|
||||
}
|
||||
bool res = (dots == 3) && haveNumber;
|
||||
if (res)
|
||||
{
|
||||
end = start;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Parse any canonical or noncanonical IPv4 formats and return a long between 0 and MaxIPv4Value.
|
||||
// Return Invalid (-1) for failures.
|
||||
// If the address has less than three dots, only the rightmost section is assumed to contain the combined value for
|
||||
// the missing sections: 0xFF00FFFF == 0xFF.0x00.0xFF.0xFF == 0xFF.0xFFFF
|
||||
internal static unsafe long ParseNonCanonical(char* name, int start, ref int end, bool notImplicitFile)
|
||||
{
|
||||
int numberBase = Decimal;
|
||||
char ch;
|
||||
long* parts = stackalloc long[4];
|
||||
long currentValue = 0;
|
||||
bool atLeastOneChar = false;
|
||||
|
||||
// Parse one dotted section at a time
|
||||
int dotCount = 0; // Limit 3
|
||||
int current = start;
|
||||
for (; current < end; current++)
|
||||
{
|
||||
ch = name[current];
|
||||
currentValue = 0;
|
||||
|
||||
// Figure out what base this section is in
|
||||
numberBase = Decimal;
|
||||
if (ch == '0')
|
||||
{
|
||||
numberBase = Octal;
|
||||
current++;
|
||||
atLeastOneChar = true;
|
||||
if (current < end)
|
||||
{
|
||||
ch = name[current];
|
||||
if (ch == 'x' || ch == 'X')
|
||||
{
|
||||
numberBase = Hex;
|
||||
current++;
|
||||
atLeastOneChar = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse this section
|
||||
for (; current < end; current++)
|
||||
{
|
||||
ch = name[current];
|
||||
int digitValue;
|
||||
|
||||
if ((numberBase == Decimal || numberBase == Hex) && '0' <= ch && ch <= '9')
|
||||
{
|
||||
digitValue = ch - '0';
|
||||
}
|
||||
else if (numberBase == Octal && '0' <= ch && ch <= '7')
|
||||
{
|
||||
digitValue = ch - '0';
|
||||
}
|
||||
else if (numberBase == Hex && 'a' <= ch && ch <= 'f')
|
||||
{
|
||||
digitValue = ch + 10 - 'a';
|
||||
}
|
||||
else if (numberBase == Hex && 'A' <= ch && ch <= 'F')
|
||||
{
|
||||
digitValue = ch + 10 - 'A';
|
||||
}
|
||||
else
|
||||
{
|
||||
break; // Invalid/terminator
|
||||
}
|
||||
|
||||
currentValue = (currentValue * numberBase) + digitValue;
|
||||
|
||||
if (currentValue > MaxIPv4Value) // Overflow
|
||||
{
|
||||
return Invalid;
|
||||
}
|
||||
|
||||
atLeastOneChar = true;
|
||||
}
|
||||
|
||||
if (current < end && name[current] == '.')
|
||||
{
|
||||
if (dotCount >= 3 // Max of 3 dots and 4 segments
|
||||
|| !atLeastOneChar // No empty segmets: 1...1
|
||||
// Only the last segment can be more than 255 (if there are less than 3 dots)
|
||||
|| currentValue > 0xFF)
|
||||
{
|
||||
return Invalid;
|
||||
}
|
||||
parts[dotCount] = currentValue;
|
||||
dotCount++;
|
||||
atLeastOneChar = false;
|
||||
continue;
|
||||
}
|
||||
// We don't get here unless We find an invalid character or a terminator
|
||||
break;
|
||||
}
|
||||
|
||||
// Terminators
|
||||
if (!atLeastOneChar)
|
||||
{
|
||||
return Invalid; // Empty trailing segment: 1.1.1.
|
||||
}
|
||||
else if (current >= end)
|
||||
{
|
||||
// end of string, allowed
|
||||
}
|
||||
else if ((ch = name[current]) == '/' || ch == '\\' || (notImplicitFile && (ch == ':' || ch == '?' || ch == '#')))
|
||||
{
|
||||
end = current;
|
||||
}
|
||||
else
|
||||
{
|
||||
// not a valid terminating character
|
||||
return Invalid;
|
||||
}
|
||||
|
||||
parts[dotCount] = currentValue;
|
||||
|
||||
// Parsed, reassemble and check for overflows
|
||||
switch (dotCount)
|
||||
{
|
||||
case 0: // 0xFFFFFFFF
|
||||
if (parts[0] > MaxIPv4Value)
|
||||
{
|
||||
return Invalid;
|
||||
}
|
||||
return parts[0];
|
||||
case 1: // 0xFF.0xFFFFFF
|
||||
if (parts[1] > 0xffffff)
|
||||
{
|
||||
return Invalid;
|
||||
}
|
||||
return (parts[0] << 24) | (parts[1] & 0xffffff);
|
||||
case 2: // 0xFF.0xFF.0xFFFF
|
||||
if (parts[2] > 0xffff)
|
||||
{
|
||||
return Invalid;
|
||||
}
|
||||
return (parts[0] << 24) | ((parts[1] & 0xff) << 16) | (parts[2] & 0xffff);
|
||||
case 3: // 0xFF.0xFF.0xFF.0xFF
|
||||
if (parts[3] > 0xff)
|
||||
{
|
||||
return Invalid;
|
||||
}
|
||||
return (parts[0] << 24) | ((parts[1] & 0xff) << 16) | ((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
|
||||
default:
|
||||
return Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
// Assumes:
|
||||
// <Name> has been validated and contains only decimal digits in groups
|
||||
// of 8-bit numbers and the characters '.'
|
||||
// Address may terminate with ':' or with the end of the string
|
||||
//
|
||||
private static unsafe bool ParseCanonical(string name, byte* numbers, int start, int end)
|
||||
{
|
||||
for (int i = 0; i < NumberOfLabels; ++i)
|
||||
{
|
||||
|
||||
byte b = 0;
|
||||
char ch;
|
||||
for (; (start < end) && (ch = name[start]) != '.' && ch != ':'; ++start)
|
||||
{
|
||||
b = (byte)(b * 10 + (byte)(ch - '0'));
|
||||
}
|
||||
numbers[i] = b;
|
||||
++start;
|
||||
}
|
||||
return numbers[0] == 127;
|
||||
}
|
||||
}
|
||||
}
|
||||
417
external/corefx/src/System.Net.Primitives/src/System/Net/IPv6AddressHelper.cs
vendored
Normal file
417
external/corefx/src/System.Net.Primitives/src/System/Net/IPv6AddressHelper.cs
vendored
Normal file
@@ -0,0 +1,417 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System
|
||||
{
|
||||
internal static class IPv6AddressHelper
|
||||
{
|
||||
private const int NumberOfLabels = 8;
|
||||
|
||||
// RFC 5952 Section 4.2.3
|
||||
// Longest consecutive sequence of zero segments, minimum 2.
|
||||
// On equal, first sequence wins. <-1, -1> for no compression.
|
||||
internal unsafe static (int longestSequenceStart, int longestSequenceLength) FindCompressionRange(
|
||||
ushort[] numbers, int fromInclusive, int toExclusive)
|
||||
{
|
||||
Debug.Assert(fromInclusive >= 0);
|
||||
Debug.Assert(toExclusive <= NumberOfLabels);
|
||||
Debug.Assert(fromInclusive <= toExclusive);
|
||||
|
||||
int longestSequenceLength = 0, longestSequenceStart = -1, currentSequenceLength = 0;
|
||||
|
||||
for (int i = fromInclusive; i < toExclusive; i++)
|
||||
{
|
||||
if (numbers[i] == 0)
|
||||
{
|
||||
currentSequenceLength++;
|
||||
if (currentSequenceLength > longestSequenceLength)
|
||||
{
|
||||
longestSequenceLength = currentSequenceLength;
|
||||
longestSequenceStart = i - currentSequenceLength + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
currentSequenceLength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return longestSequenceLength > 1 ?
|
||||
(longestSequenceStart, longestSequenceStart + longestSequenceLength) :
|
||||
(-1, -1);
|
||||
}
|
||||
|
||||
// Returns true if the IPv6 address should be formatted with an embedded IPv4 address:
|
||||
// ::192.168.1.1
|
||||
internal unsafe static bool ShouldHaveIpv4Embedded(ushort[] numbers)
|
||||
{
|
||||
// 0:0 : 0:0 : x:x : x.x.x.x
|
||||
if (numbers[0] == 0 && numbers[1] == 0 && numbers[2] == 0 && numbers[3] == 0 && numbers[6] != 0)
|
||||
{
|
||||
// RFC 5952 Section 5 - 0:0 : 0:0 : 0:[0 | FFFF] : x.x.x.x
|
||||
if (numbers[4] == 0 && (numbers[5] == 0 || numbers[5] == 0xFFFF))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// SIIT - 0:0 : 0:0 : FFFF:0 : x.x.x.x
|
||||
else if (numbers[4] == 0xFFFF && numbers[5] == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// ISATAP
|
||||
return numbers[4] == 0 && numbers[5] == 0x5EFE;
|
||||
}
|
||||
|
||||
//
|
||||
// IsValidStrict
|
||||
//
|
||||
// Determine whether a name is a valid IPv6 address. Rules are:
|
||||
//
|
||||
// * 8 groups of 16-bit hex numbers, separated by ':'
|
||||
// * a *single* run of zeros can be compressed using the symbol '::'
|
||||
// * an optional string of a ScopeID delimited by '%'
|
||||
// * the last 32 bits in an address can be represented as an IPv4 address
|
||||
//
|
||||
// Difference between IsValid() and IsValidStrict() is that IsValid() expects part of the string to
|
||||
// be ipv6 address where as IsValidStrict() expects strict ipv6 address.
|
||||
//
|
||||
// Inputs:
|
||||
// <argument> name
|
||||
// IPv6 address in string format
|
||||
//
|
||||
// Outputs:
|
||||
// Nothing
|
||||
//
|
||||
// Assumes:
|
||||
// the correct name is terminated by ']' character
|
||||
//
|
||||
// Returns:
|
||||
// true if <name> is IPv6 address, else false
|
||||
//
|
||||
// Throws:
|
||||
// Nothing
|
||||
//
|
||||
|
||||
// Remarks: MUST NOT be used unless all input indexes are verified and trusted.
|
||||
// start must be next to '[' position, or error is reported
|
||||
internal unsafe static bool IsValidStrict(char* name, int start, ref int end)
|
||||
{
|
||||
int sequenceCount = 0;
|
||||
int sequenceLength = 0;
|
||||
bool haveCompressor = false;
|
||||
bool haveIPv4Address = false;
|
||||
bool expectingNumber = true;
|
||||
int lastSequence = 1;
|
||||
|
||||
bool needsClosingBracket = false;
|
||||
if (start < end && name[start] == '[')
|
||||
{
|
||||
start++;
|
||||
needsClosingBracket = true;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = start; i < end; ++i)
|
||||
{
|
||||
if (Uri.IsHexDigit(name[i]))
|
||||
{
|
||||
++sequenceLength;
|
||||
expectingNumber = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sequenceLength > 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (sequenceLength != 0)
|
||||
{
|
||||
++sequenceCount;
|
||||
lastSequence = i - sequenceLength;
|
||||
sequenceLength = 0;
|
||||
}
|
||||
switch (name[i])
|
||||
{
|
||||
case '%':
|
||||
while (i+1 < end)
|
||||
{
|
||||
i++;
|
||||
if (name[i] == ']')
|
||||
{
|
||||
goto case ']';
|
||||
}
|
||||
else if (name[i] == '/')
|
||||
{
|
||||
goto case '/';
|
||||
}
|
||||
else if (name[i] < '0' || name[i] > '9')
|
||||
{
|
||||
// scope ID must only contain digits
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ']':
|
||||
if (!needsClosingBracket)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
needsClosingBracket = false;
|
||||
|
||||
// If there's more after the closing bracket, it must be a port.
|
||||
// We don't use the port, but we still validate it.
|
||||
if (i + 1 < end && name[i + 1] != ':')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there is a port, it must either be a hexadecimal or decimal number.
|
||||
if (i + 3 < end && name[i + 2] == '0' && name[i + 3] == 'x')
|
||||
{
|
||||
i += 4;
|
||||
for (; i < end; i++)
|
||||
{
|
||||
if (!Uri.IsHexDigit(name[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i += 2;
|
||||
for (; i < end; i++)
|
||||
{
|
||||
if (name[i] < '0' || name[i] > '9')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
case ':':
|
||||
if ((i > 0) && (name[i - 1] == ':'))
|
||||
{
|
||||
if (haveCompressor)
|
||||
{
|
||||
// can only have one per IPv6 address
|
||||
return false;
|
||||
}
|
||||
haveCompressor = true;
|
||||
expectingNumber = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
expectingNumber = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case '/':
|
||||
return false;
|
||||
|
||||
case '.':
|
||||
if (haveIPv4Address)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
i = end;
|
||||
if (!IPv4AddressHelper.IsValid(name, lastSequence, ref i, true, false, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// ipv4 address takes 2 slots in ipv6 address, one was just counted meeting the '.'
|
||||
++sequenceCount;
|
||||
lastSequence = i - sequenceLength;
|
||||
sequenceLength = 0;
|
||||
haveIPv4Address = true;
|
||||
--i; // it will be incremented back on the next loop
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
sequenceLength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (sequenceLength != 0)
|
||||
{
|
||||
++sequenceCount;
|
||||
lastSequence = i - sequenceLength;
|
||||
sequenceLength = 0;
|
||||
}
|
||||
|
||||
// these sequence counts are -1 because it is implied in end-of-sequence
|
||||
|
||||
const int ExpectedSequenceCount = 8;
|
||||
return
|
||||
!expectingNumber &&
|
||||
(sequenceLength <= 4) &&
|
||||
(haveCompressor ? (sequenceCount < ExpectedSequenceCount) : (sequenceCount == ExpectedSequenceCount)) &&
|
||||
!needsClosingBracket;
|
||||
}
|
||||
|
||||
//
|
||||
// Parse
|
||||
//
|
||||
// Convert this IPv6 address into a sequence of 8 16-bit numbers
|
||||
//
|
||||
// Inputs:
|
||||
// <member> Name
|
||||
// The validated IPv6 address
|
||||
//
|
||||
// Outputs:
|
||||
// <member> numbers
|
||||
// Array filled in with the numbers in the IPv6 groups
|
||||
//
|
||||
// <member> PrefixLength
|
||||
// Set to the number after the prefix separator (/) if found
|
||||
//
|
||||
// Assumes:
|
||||
// <Name> has been validated and contains only hex digits in groups of
|
||||
// 16-bit numbers, the characters ':' and '/', and a possible IPv4
|
||||
// address
|
||||
//
|
||||
// Throws:
|
||||
// Nothing
|
||||
//
|
||||
|
||||
internal static unsafe void Parse(string address, ushort* numbers, int start, ref string scopeId)
|
||||
{
|
||||
int number = 0;
|
||||
int index = 0;
|
||||
int compressorIndex = -1;
|
||||
bool numberIsValid = true;
|
||||
|
||||
//This used to be a class instance member but have not been used so far
|
||||
int PrefixLength = 0;
|
||||
if (address[start] == '[')
|
||||
{
|
||||
++start;
|
||||
}
|
||||
|
||||
for (int i = start; i < address.Length && address[i] != ']';)
|
||||
{
|
||||
switch (address[i])
|
||||
{
|
||||
case '%':
|
||||
if (numberIsValid)
|
||||
{
|
||||
numbers[index++] = (ushort)number;
|
||||
numberIsValid = false;
|
||||
}
|
||||
|
||||
start = i;
|
||||
for (++i; i < address.Length && address[i] != ']' && address[i] != '/'; ++i)
|
||||
{
|
||||
}
|
||||
scopeId = address.Substring(start, i - start);
|
||||
// ignore prefix if any
|
||||
for (; i < address.Length && address[i] != ']'; ++i)
|
||||
{
|
||||
}
|
||||
break;
|
||||
|
||||
case ':':
|
||||
numbers[index++] = (ushort)number;
|
||||
number = 0;
|
||||
++i;
|
||||
if (address[i] == ':')
|
||||
{
|
||||
compressorIndex = index;
|
||||
++i;
|
||||
}
|
||||
else if ((compressorIndex < 0) && (index < 6))
|
||||
{
|
||||
// no point checking for IPv4 address if we don't
|
||||
// have a compressor or we haven't seen 6 16-bit
|
||||
// numbers yet
|
||||
break;
|
||||
}
|
||||
|
||||
// check to see if the upcoming number is really an IPv4
|
||||
// address. If it is, convert it to 2 ushort numbers
|
||||
for (int j = i; j < address.Length &&
|
||||
(address[j] != ']') &&
|
||||
(address[j] != ':') &&
|
||||
(address[j] != '%') &&
|
||||
(address[j] != '/') &&
|
||||
(j < i + 4); ++j)
|
||||
{
|
||||
|
||||
if (address[j] == '.')
|
||||
{
|
||||
// we have an IPv4 address. Find the end of it:
|
||||
// we know that since we have a valid IPv6
|
||||
// address, the only things that will terminate
|
||||
// the IPv4 address are the prefix delimiter '/'
|
||||
// or the end-of-string (which we conveniently
|
||||
// delimited with ']')
|
||||
while (j < address.Length && (address[j] != ']') && (address[j] != '/') && (address[j] != '%'))
|
||||
{
|
||||
++j;
|
||||
}
|
||||
number = IPv4AddressHelper.ParseHostNumber(address, i, j);
|
||||
numbers[index++] = (ushort)(number >> 16);
|
||||
numbers[index++] = (ushort)number;
|
||||
i = j;
|
||||
|
||||
// set this to avoid adding another number to
|
||||
// the array if there's a prefix
|
||||
number = 0;
|
||||
numberIsValid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case '/':
|
||||
if (numberIsValid)
|
||||
{
|
||||
numbers[index++] = (ushort)number;
|
||||
numberIsValid = false;
|
||||
}
|
||||
|
||||
// since we have a valid IPv6 address string, the prefix
|
||||
// length is the last token in the string
|
||||
for (++i; address[i] != ']'; ++i)
|
||||
{
|
||||
PrefixLength = PrefixLength * 10 + (address[i] - '0');
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
number = number * 16 + Uri.FromHex(address[i++]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// add number to the array if its not the prefix length or part of
|
||||
// an IPv4 address that's already been handled
|
||||
if (numberIsValid)
|
||||
{
|
||||
numbers[index++] = (ushort)number;
|
||||
}
|
||||
|
||||
// if we had a compressor sequence ("::") then we need to expand the
|
||||
// numbers array
|
||||
if (compressorIndex > 0)
|
||||
{
|
||||
int toIndex = NumberOfLabels - 1;
|
||||
int fromIndex = index - 1;
|
||||
|
||||
for (int i = index - compressorIndex; i > 0; --i)
|
||||
{
|
||||
numbers[toIndex--] = numbers[fromIndex];
|
||||
numbers[fromIndex--] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,9 +25,19 @@ namespace System.Net.Sockets
|
||||
|
||||
private static int GetNativeErrorForSocketError(SocketError error)
|
||||
{
|
||||
return error != SocketError.SocketError ?
|
||||
SocketErrorPal.GetNativeErrorForSocketError(error).Info().RawErrno :
|
||||
(int)error;
|
||||
int nativeErr = (int)error;
|
||||
if (error != SocketError.SocketError)
|
||||
{
|
||||
Interop.Error interopErr;
|
||||
|
||||
// If an interop error was not found, then don't invoke Info().RawErrno as that will fail with assert.
|
||||
if (SocketErrorPal.TryGetNativeErrorForSocketError(error, out interopErr))
|
||||
{
|
||||
nativeErr = interopErr.Info().RawErrno;
|
||||
}
|
||||
}
|
||||
|
||||
return nativeErr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace System.Net.Sockets
|
||||
{
|
||||
/// <summary>Provides socket exceptions to the application.</summary>
|
||||
[Serializable]
|
||||
public partial class SocketException : Win32Exception
|
||||
{
|
||||
/// <summary>The SocketError or Int32 specified when constructing the exception.</summary>
|
||||
@@ -38,5 +40,13 @@ namespace System.Net.Sockets
|
||||
public override string Message => base.Message;
|
||||
|
||||
public SocketError SocketErrorCode => _errorCode;
|
||||
|
||||
protected SocketException(SerializationInfo serializationInfo, StreamingContext streamingContext)
|
||||
: base(serializationInfo, streamingContext)
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
public override int ErrorCode => base.NativeErrorCode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace System.Net.Sockets
|
||||
{
|
||||
[Serializable]
|
||||
public partial class SocketException : Win32Exception
|
||||
{
|
||||
protected SocketException(SerializationInfo serializationInfo, StreamingContext streamingContext)
|
||||
: base(serializationInfo, streamingContext)
|
||||
{
|
||||
if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"{NativeErrorCode}:{Message}");
|
||||
}
|
||||
|
||||
public override int ErrorCode => base.NativeErrorCode;
|
||||
}
|
||||
}
|
||||
@@ -151,6 +151,7 @@ namespace System.Net.Primitives.Functional.Tests
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(SetCookiesInvalidData))]
|
||||
[ActiveIssue("https://github.com/dotnet/corefx/issues/20482", TargetFrameworkMonikers.UapAot)]
|
||||
public static void SetCookies_InvalidData_Throws(Uri uri, string cookieHeader)
|
||||
{
|
||||
CookieContainer cc = new CookieContainer();
|
||||
|
||||
@@ -241,7 +241,7 @@ namespace System.Net.Primitives.Functional.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[SkipOnTargetFramework(TargetFrameworkMonikers.Netcoreapp | TargetFrameworkMonikers.Uap)]
|
||||
[SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)] // Cookie.Value returns null on full framework, empty string on .NETCore
|
||||
public static void Value_PassNullToCtor_GetReturnsEmptyString_net46()
|
||||
{
|
||||
var cookie = new Cookie("SomeName", null);
|
||||
@@ -250,7 +250,7 @@ namespace System.Net.Primitives.Functional.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
|
||||
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] // Cookie.Value returns null on full framework, empty string on .NETCore
|
||||
public static void Value_PassNullToCtor_GetReturnsEmptyString()
|
||||
{
|
||||
var cookie = new Cookie("SomeName", null);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user