diff --git a/src/Common/src/System/Net/CookieParser.cs b/src/Common/src/System/Net/CookieParser.cs index f63ba9384f34..dfa67b2fb76a 100644 --- a/src/Common/src/System/Net/CookieParser.cs +++ b/src/Common/src/System/Net/CookieParser.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Globalization; +using System.Reflection; namespace System.Net { @@ -543,18 +544,60 @@ internal string GetString() return _tokenizer.GetCookieString(); } - private static void SetCookieName(Cookie cookie, string name) + private static MethodInfo s_internalSetNameMethod; + private static MethodInfo InternalSetNameMethod { - try + get { - cookie.Name = name; + if (s_internalSetNameMethod == null) + { + // We need to use Cookie.InternalSetName instead of the Cookie.set_Name wrapped in a try catch block, as + // Cookie.set_Name keeps the original name if the string is empty or null. + // Unfortunately this API is internal so we use reflection to access it. The method is cached for performance reasons. + MethodInfo method = typeof(Cookie).GetMethod("InternalSetName", BindingFlags.NonPublic | BindingFlags.Instance); + Debug.Assert(method != null, "We need to use an internal method named InternalSetName that is declared on Cookie."); + s_internalSetNameMethod = method; + } + + return s_internalSetNameMethod; } - catch (CookieException) + } + + private static FieldInfo s_isQuotedDomainField = null; + private static FieldInfo IsQuotedDomainField + { + get { - Debug.Assert(cookie.Name == string.Empty); + if (s_isQuotedDomainField == null) + { + FieldInfo field = typeof(Cookie).GetField("IsQuotedDomain", BindingFlags.NonPublic | BindingFlags.Instance); + Debug.Assert(field != null, "We need to use an internal property named IsQuotedDomain that is declared on Cookie."); + s_isQuotedDomainField = field; + } + + return s_isQuotedDomainField; } } + private static FieldInfo s_isQuotedVersionField = null; + private static FieldInfo IsQuotedVersionField + { + get + { + if (s_isQuotedVersionField == null) + { + FieldInfo field = typeof(Cookie).GetField("IsQuotedVersion", BindingFlags.NonPublic | BindingFlags.Instance); + Debug.Assert(field != null, "We need to use an internal property named IsQuotedVersion that is declared on Cookie."); + s_isQuotedVersionField = field; + } + + return s_isQuotedVersionField; + } + } + + private static object[] s_emptyStringArray = null; + private static object[] EmptyStringArray => s_emptyStringArray ?? (s_emptyStringArray = new object[] { string.Empty }); + // Get // // Gets the next cookie or null if there are no more cookies. @@ -579,7 +622,7 @@ internal Cookie Get() if (cookie == null && (token == CookieToken.NameValuePair || token == CookieToken.Attribute)) { cookie = new Cookie(); - SetCookieName(cookie, _tokenizer.Name); + InternalSetNameMethod.Invoke(cookie, new object[] { _tokenizer.Name }); cookie.Value = _tokenizer.Value; } else @@ -614,8 +657,7 @@ internal Cookie Get() { domainSet = true; cookie.Domain = CheckQuoted(_tokenizer.Value); - // TODO: this is internal. - // cookie.IsQuotedDomain = _tokenizer.Quoted; + IsQuotedDomainField.SetValue(cookie, _tokenizer.Quoted); } break; @@ -633,7 +675,7 @@ internal Cookie Get() else { // This cookie will be rejected - SetCookieName(cookie, string.Empty); + InternalSetNameMethod.Invoke(cookie, EmptyStringArray); } } break; @@ -650,7 +692,7 @@ internal Cookie Get() else { // This cookie will be rejected - SetCookieName(cookie, string.Empty); + InternalSetNameMethod.Invoke(cookie, EmptyStringArray); } } break; @@ -674,7 +716,7 @@ internal Cookie Get() catch { // This cookie will be rejected - SetCookieName(cookie, string.Empty); + InternalSetNameMethod.Invoke(cookie, EmptyStringArray); } } break; @@ -687,13 +729,12 @@ internal Cookie Get() if (int.TryParse(CheckQuoted(_tokenizer.Value), out parsed)) { cookie.Version = parsed; - // TODO: this is internal. - // cookie.IsQuotedVersion = _tokenizer.Quoted; + IsQuotedVersionField.SetValue(cookie, _tokenizer.Quoted); } else { // This cookie will be rejected - SetCookieName(cookie, string.Empty); + InternalSetNameMethod.Invoke(cookie, EmptyStringArray); } } break; @@ -760,7 +801,7 @@ internal Cookie GetServer() { cookie = new Cookie(); } - SetCookieName(cookie, _tokenizer.Name); + InternalSetNameMethod.Invoke(cookie, new object[] { _tokenizer.Name }); cookie.Value = _tokenizer.Value; } else @@ -775,8 +816,7 @@ internal Cookie GetServer() { domainSet = true; cookie.Domain = CheckQuoted(_tokenizer.Value); - // TODO: this is internal. - // cookie.IsQuotedDomain = _tokenizer.Quoted; + IsQuotedDomainField.SetValue(cookie, _tokenizer.Quoted); } break; @@ -799,7 +839,7 @@ internal Cookie GetServer() catch (CookieException) { // This cookie will be rejected - SetCookieName(cookie, string.Empty); + InternalSetNameMethod.Invoke(cookie, EmptyStringArray); } } break; @@ -817,7 +857,7 @@ internal Cookie GetServer() case CookieToken.Unknown: // this is a new cookie, the token is for the next cookie. _savedCookie = new Cookie(); - SetCookieName(_savedCookie, _tokenizer.Name); + InternalSetNameMethod.Invoke(_savedCookie, new object[] { _tokenizer.Name }); _savedCookie.Value = _tokenizer.Value; return cookie; }