diff --git a/src/System.Net.Http/src/netcore50/System/Net/cookie.cs b/src/System.Net.Http/src/netcore50/System/Net/cookie.cs index c9b928250150..c1b51f0d7ce9 100644 --- a/src/System.Net.Http/src/netcore50/System/Net/cookie.cs +++ b/src/System.Net.Http/src/netcore50/System/Net/cookie.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Collections.Generic; using System.Globalization; +using System.Text; using System.Threading; // The NETNative_SystemNetHttp #define is used in some source files to indicate we are compiling classes @@ -221,20 +222,6 @@ public string Domain } } - private string _Domain - { - get - { - return (Plain || m_domain_implicit || (m_domain.Length == 0)) - ? string.Empty - : (SpecialAttributeLiteral - + DomainAttributeName - + EqualsLiteral + (IsQuotedDomain ? "\"" : string.Empty) - + m_domain + (IsQuotedDomain ? "\"" : string.Empty) - ); - } - } - internal bool DomainImplicit { get @@ -325,20 +312,6 @@ public string Path } } - private string _Path - { - get - { - return (Plain || m_path_implicit || (m_path.Length == 0)) - ? string.Empty - : (SpecialAttributeLiteral - + PathAttributeName - + EqualsLiteral - + m_path - ); - } - } - internal bool Plain { get @@ -729,18 +702,6 @@ internal int[] PortList } } - private string _Port - { - get - { - return m_port_implicit ? string.Empty : - (SpecialAttributeLiteral - + PortAttributeName - + ((m_port.Length == 0) ? string.Empty : (EqualsLiteral + m_port)) - ); - } - } - /// /// [To be supplied.] /// @@ -834,18 +795,6 @@ public int Version } } - private string _Version - { - get - { - return (Version == 0) ? string.Empty : - (SpecialAttributeLiteral - + VersionAttributeName - + EqualsLiteral + (IsQuotedVersion ? "\"" : string.Empty) - + m_version.ToString(NumberFormatInfo.InvariantInfo) + (IsQuotedVersion ? "\"" : string.Empty)); - } - } - // methods @@ -897,23 +846,65 @@ public override int GetHashCode() /// public override string ToString() { - string domain = _Domain; - string path = _Path; - string port = _Port; - string version = _Version; - - string result = - ((version.Length == 0) ? string.Empty : (version + SeparatorLiteral)) - + Name + EqualsLiteral + Value - + ((path.Length == 0) ? string.Empty : (SeparatorLiteral + path)) - + ((domain.Length == 0) ? string.Empty : (SeparatorLiteral + domain)) - + ((port.Length == 0) ? string.Empty : (SeparatorLiteral + port)) - ; - if (result == "=") + var sb = new StringBuilder(); + ToString(sb); + return sb.ToString(); + } + + internal void ToString(StringBuilder sb) + { + int beforeLength = sb.Length; + + // Add the Cookie version if necessary. + if (Version != 0) + { + sb.Append(SpecialAttributeLiteral + VersionAttributeName + EqualsLiteral); // const strings + if (IsQuotedVersion) sb.Append('"'); + sb.Append(m_version.ToString(NumberFormatInfo.InvariantInfo)); + if (IsQuotedVersion) sb.Append('"'); + sb.Append(SeparatorLiteral); + } + + // Add the Cookie Name=Value pair. + sb.Append(Name).Append(EqualsLiteral).Append(Value); + + if (!Plain) + { + // Add the Path if necessary. + if (!m_path_implicit && m_path.Length > 0) + { + sb.Append(SeparatorLiteral + SpecialAttributeLiteral + PathAttributeName + EqualsLiteral); // const strings + sb.Append(m_path); + } + + // Add the Domain if necessary. + if (!m_domain_implicit && m_domain.Length > 0) + { + sb.Append(SeparatorLiteral + SpecialAttributeLiteral + DomainAttributeName + EqualsLiteral); // const strings + if (IsQuotedDomain) sb.Append('"'); + sb.Append(m_domain); + if (IsQuotedDomain) sb.Append('"'); + } + } + + // Add the Port if necessary. + if (!m_port_implicit) + { + sb.Append(SeparatorLiteral + SpecialAttributeLiteral + PortAttributeName); // const strings + if (m_port.Length > 0) + { + sb.Append(EqualsLiteral); + sb.Append(m_port); + } + } + + // Check to see whether the only thing we added was "=", and if so, + // remove it so that we leave the StringBuilder unchanged in contents. + int afterLength = sb.Length; + if (afterLength == (1 + beforeLength) && sb[beforeLength] == '=') { - return string.Empty; + sb.Length = beforeLength; } - return result; } internal string ToServerString() diff --git a/src/System.Net.Primitives/src/System.Net.Primitives.csproj b/src/System.Net.Primitives/src/System.Net.Primitives.csproj index d440dc656a23..849cd46b5d78 100644 --- a/src/System.Net.Primitives/src/System.Net.Primitives.csproj +++ b/src/System.Net.Primitives/src/System.Net.Primitives.csproj @@ -91,6 +91,9 @@ Common\System\Net\NetworkInformation\HostInformation.cs + + Common\System\IO\StringBuilderCache.cs + Common\System\Net\Shims\TraceSource.cs diff --git a/src/System.Net.Primitives/src/System/Net/Cookie.cs b/src/System.Net.Primitives/src/System/Net/Cookie.cs index 685216233216..d5f2eca4c752 100644 --- a/src/System.Net.Primitives/src/System/Net/Cookie.cs +++ b/src/System.Net.Primitives/src/System/Net/Cookie.cs @@ -2,10 +2,11 @@ // 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.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; +using System.IO; +using System.Text; using System.Threading; // The NETNative_SystemNetHttp #define is used in some source files to indicate we are compiling classes @@ -181,19 +182,6 @@ public string Domain } } - private string _Domain - { - get - { - return (Plain || _domainImplicit || (_domain.Length == 0)) - ? string.Empty - : (SpecialAttributeLiteral - + DomainAttributeName - + EqualsLiteral + (IsQuotedDomain ? "\"" : string.Empty) - + _domain + (IsQuotedDomain ? "\"" : string.Empty)); - } - } - internal bool DomainImplicit { get @@ -272,19 +260,6 @@ public string Path } } - private string _Path - { - get - { - return (Plain || _pathImplicit || (_path.Length == 0)) - ? string.Empty - : (SpecialAttributeLiteral - + PathAttributeName - + EqualsLiteral - + _path); - } - } - internal bool Plain { get @@ -666,17 +641,6 @@ internal int[] PortList } } - private string _Port - { - get - { - return _portImplicit ? string.Empty : - (SpecialAttributeLiteral - + PortAttributeName - + ((_port.Length == 0) ? string.Empty : (EqualsLiteral + _port))); - } - } - public bool Secure { get @@ -763,18 +727,6 @@ public int Version } } - private string _Version - { - get - { - return (Version == 0) ? string.Empty : - (SpecialAttributeLiteral - + VersionAttributeName - + EqualsLiteral + (IsQuotedVersion ? "\"" : string.Empty) - + _version.ToString(NumberFormatInfo.InvariantInfo) + (IsQuotedVersion ? "\"" : string.Empty)); - } - } - public override bool Equals(object comparand) { Cookie other = comparand as Cookie; @@ -794,22 +746,65 @@ public override int GetHashCode() public override string ToString() { - string domain = _Domain; - string path = _Path; - string port = _Port; - string version = _Version; - - string result = - ((version.Length == 0) ? string.Empty : (version + SeparatorLiteral)) - + Name + EqualsLiteral + Value - + ((path.Length == 0) ? string.Empty : (SeparatorLiteral + path)) - + ((domain.Length == 0) ? string.Empty : (SeparatorLiteral + domain)) - + ((port.Length == 0) ? string.Empty : (SeparatorLiteral + port)); - if (result == "=") - { - return string.Empty; - } - return result; + StringBuilder sb = StringBuilderCache.Acquire(); + ToString(sb); + return StringBuilderCache.GetStringAndRelease(sb); + } + + internal void ToString(StringBuilder sb) + { + int beforeLength = sb.Length; + + // Add the Cookie version if necessary. + if (Version != 0) + { + sb.Append(SpecialAttributeLiteral + VersionAttributeName + EqualsLiteral); // const strings + if (IsQuotedVersion) sb.Append('"'); + sb.Append(_version.ToString(NumberFormatInfo.InvariantInfo)); + if (IsQuotedVersion) sb.Append('"'); + sb.Append(SeparatorLiteral); + } + + // Add the Cookie Name=Value pair. + sb.Append(Name).Append(EqualsLiteral).Append(Value); + + if (!Plain) + { + // Add the Path if necessary. + if (!_pathImplicit && _path.Length > 0) + { + sb.Append(SeparatorLiteral + SpecialAttributeLiteral + PathAttributeName + EqualsLiteral); // const strings + sb.Append(_path); + } + + // Add the Domain if necessary. + if (!_domainImplicit && _domain.Length > 0) + { + sb.Append(SeparatorLiteral + SpecialAttributeLiteral + DomainAttributeName + EqualsLiteral); // const strings + if (IsQuotedDomain) sb.Append('"'); + sb.Append(_domain); + if (IsQuotedDomain) sb.Append('"'); + } + } + + // Add the Port if necessary. + if (!_portImplicit) + { + sb.Append(SeparatorLiteral + SpecialAttributeLiteral + PortAttributeName); // const strings + if (_port.Length > 0) + { + sb.Append(EqualsLiteral); + sb.Append(_port); + } + } + + // Check to see whether the only thing we added was "=", and if so, + // remove it so that we leave the StringBuilder unchanged in contents. + int afterLength = sb.Length; + if (afterLength == (1 + beforeLength) && sb[beforeLength] == '=') + { + sb.Length = beforeLength; + } } internal string ToServerString() diff --git a/src/System.Net.Primitives/src/System/Net/CookieContainer.cs b/src/System.Net.Primitives/src/System/Net/CookieContainer.cs index 168158c78aa9..87d38238cdde 100644 --- a/src/System.Net.Primitives/src/System/Net/CookieContainer.cs +++ b/src/System.Net.Primitives/src/System/Net/CookieContainer.cs @@ -2,9 +2,9 @@ // 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.Collections; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Net.NetworkInformation; using System.Text; @@ -728,17 +728,17 @@ public CookieCollection GetCookies(Uri uri) { throw new ArgumentNullException(nameof(uri)); } - return InternalGetCookies(uri); + return InternalGetCookies(uri) ?? new CookieCollection(); } internal CookieCollection InternalGetCookies(Uri uri) { bool isSecure = (uri.Scheme == UriScheme.Https); int port = uri.Port; - CookieCollection cookies = new CookieCollection(); + CookieCollection cookies = null; List domainAttributeMatchAnyCookieVariant = new List(); - List domainAttributeMatchOnlyCookieVariantPlain = new List(); + List domainAttributeMatchOnlyCookieVariantPlain = null; string fqdnRemote = uri.Host; @@ -780,6 +780,11 @@ internal CookieCollection InternalGetCookies(Uri uri) { while ((dot < last) && (dot = fqdnRemote.IndexOf('.', dot + 1)) != -1) { + if (domainAttributeMatchOnlyCookieVariantPlain == null) + { + domainAttributeMatchOnlyCookieVariantPlain = new List(); + } + // These candidates can only match CookieVariant.Plain cookies. domainAttributeMatchOnlyCookieVariantPlain.Add(fqdnRemote.Substring(dot)); } @@ -787,13 +792,16 @@ internal CookieCollection InternalGetCookies(Uri uri) } } - BuildCookieCollectionFromDomainMatches(uri, isSecure, port, cookies, domainAttributeMatchAnyCookieVariant, false); - BuildCookieCollectionFromDomainMatches(uri, isSecure, port, cookies, domainAttributeMatchOnlyCookieVariantPlain, true); + BuildCookieCollectionFromDomainMatches(uri, isSecure, port, ref cookies, domainAttributeMatchAnyCookieVariant, false); + if (domainAttributeMatchOnlyCookieVariantPlain != null) + { + BuildCookieCollectionFromDomainMatches(uri, isSecure, port, ref cookies, domainAttributeMatchOnlyCookieVariantPlain, true); + } return cookies; } - private void BuildCookieCollectionFromDomainMatches(Uri uri, bool isSecure, int port, CookieCollection cookies, List domainAttribute, bool matchOnlyPlainCookie) + private void BuildCookieCollectionFromDomainMatches(Uri uri, bool isSecure, int port, ref CookieCollection cookies, List domainAttribute, bool matchOnlyPlainCookie) { for (int i = 0; i < domainAttribute.Count; i++) { @@ -819,7 +827,7 @@ private void BuildCookieCollectionFromDomainMatches(Uri uri, bool isSecure, int CookieCollection cc = pair.Value; cc.TimeStamp(CookieCollection.Stamp.Set); - MergeUpdateCollections(cookies, cc, port, isSecure, matchOnlyPlainCookie); + MergeUpdateCollections(ref cookies, cc, port, isSecure, matchOnlyPlainCookie); if (path == "/") { @@ -840,7 +848,7 @@ private void BuildCookieCollectionFromDomainMatches(Uri uri, bool isSecure, int if (cc != null) { cc.TimeStamp(CookieCollection.Stamp.Set); - MergeUpdateCollections(cookies, cc, port, isSecure, matchOnlyPlainCookie); + MergeUpdateCollections(ref cookies, cc, port, isSecure, matchOnlyPlainCookie); } } @@ -856,11 +864,11 @@ private void BuildCookieCollectionFromDomainMatches(Uri uri, bool isSecure, int } } - private void MergeUpdateCollections(CookieCollection destination, CookieCollection source, int port, bool isSecure, bool isPlainOnly) + private void MergeUpdateCollections(ref CookieCollection destination, CookieCollection source, int port, bool isSecure, bool isPlainOnly) { lock (source) { - // Cannot use foreach as we going update 'source' + // Cannot use foreach as we are going to update 'source' for (int idx = 0; idx < source.Count; ++idx) { bool to_add = false; @@ -910,6 +918,10 @@ private void MergeUpdateCollections(CookieCollection destination, CookieCollecti // In 'source' are already ordered. // If two same cookies come from different 'source' then they // will follow (not replace) each other. + if (destination == null) + { + destination = new CookieCollection(); + } destination.InternalAdd(cookie, false); } } @@ -930,21 +942,30 @@ public string GetCookieHeader(Uri uri) internal string GetCookieHeader(Uri uri, out string optCookie2) { CookieCollection cookies = InternalGetCookies(uri); + if (cookies == null) + { + optCookie2 = string.Empty; + return string.Empty; + } + string delimiter = string.Empty; - var builder = new StringBuilder(); - foreach (Cookie cookie in cookies) + var builder = StringBuilderCache.Acquire(); + for (int i = 0; i < cookies.Count; i++) { - builder.Append(delimiter).Append(cookie.ToString()); + builder.Append(delimiter); + cookies[i].ToString(builder); + delimiter = "; "; } + optCookie2 = cookies.IsOtherVersionSeen ? (Cookie.SpecialAttributeLiteral + Cookie.VersionAttributeName + Cookie.EqualsLiteral + Cookie.MaxSupportedVersionString) : string.Empty; - return builder.ToString(); + return StringBuilderCache.GetStringAndRelease(builder); } public void SetCookies(Uri uri, string cookieHeader) diff --git a/src/System.Net.Primitives/tests/UnitTests/System.Net.Primitives.UnitTests.Tests.csproj b/src/System.Net.Primitives/tests/UnitTests/System.Net.Primitives.UnitTests.Tests.csproj index 5c21fb3a05c8..2a9094bedf89 100644 --- a/src/System.Net.Primitives/tests/UnitTests/System.Net.Primitives.UnitTests.Tests.csproj +++ b/src/System.Net.Primitives/tests/UnitTests/System.Net.Primitives.UnitTests.Tests.csproj @@ -88,6 +88,9 @@ ProductionCode\Common\System\Net\UriScheme.cs + + Common\System\IO\StringBuilderCache.cs + ProductionCode\Common\System\Net\Shims\TraceSource.cs