Imported Upstream version 5.4.0.167

Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2017-08-21 15:34:15 +00:00
parent e49d6f06c0
commit 536cd135cc
12856 changed files with 563812 additions and 223249 deletions

View File

@@ -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>

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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)

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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));
}
}

View 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;
}
}
}

View 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;
}
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();

View File

@@ -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