Bug di CookieContainer?

Sono confuso su come CookieContainer gestisce il dominio, quindi creo questo test. Questo test mostra che cookieContainer non restituisce alcun cookie per “esempio.com” ma secondo RFC dovrebbe restituire almeno 2 cookie.

Non è un bug?

Come farlo funzionare?

Ecco una discussione su questo bug:

http://social.msdn.microsoft.com/Forums/en-US/ncl/thread/c4edc965-2dc2-4724-8f08-68815cf1dce6

        CookieContainer getContainer() { CookieContainer result = new CookieContainer(); Uri uri = new Uri("http://sub.example.com"); string cookieH = @"Test1=val; domain=sub.example.com; path=/"; result.SetCookies(uri, cookieH); cookieH = @"Test2=val; domain=.example.com; path=/"; result.SetCookies(uri, cookieH); cookieH = @"Test3=val; domain=example.com; path=/"; result.SetCookies(uri, cookieH); return result; } void Test() { CookieContainer cookie = getContainer(); lblResult.Text += "
    Total cookies count: " + cookie.Count + "    expected: 3"; Uri uri = new Uri("http://sub.example.com"); CookieCollection coll = cookie.GetCookies(uri); lblResult.Text += "
    For " + uri + " Cookie count: " + coll.Count + "    expected: 2"; uri = new Uri("http://other.example.com"); coll = cookie.GetCookies(uri); lblResult.Text += "
    For " + uri + " Cookie count: " + coll.Count + "    expected: 2"; uri = new Uri("http://example.com"); coll = cookie.GetCookies(uri); lblResult.Text += "
    For " + uri + " Cookie count: " + coll.Count + "    expected: 2"; } protected void Page_Load(object sender, EventArgs e) { Test(); } CookieContainer Test Page

    Ho appena trovato la correzione per questo bug e discusso qui: http://dot-net-expertise.blogspot.com/2009/10/cookiecontainer-domain-handling-bug-fix.html

    Ecco la soluzione:

    1. Non utilizzare .Add (Cookie), utilizzare solo il metodo .Add (Uri, Cookie).
    2. Chiama BugFix_CookieDomain ogni volta che aggiungi un cookie al contenitore o prima di utilizzare .GetCookie o prima che il sistema utilizzi il contenitore.

       private void BugFix_CookieDomain(CookieContainer cookieContainer) { System.Type _ContainerType = typeof(CookieContainer); Hashtable table = (Hashtable)_ContainerType.InvokeMember("m_domainTable", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance, null, cookieContainer, new object[] { }); ArrayList keys = new ArrayList(table.Keys); foreach (string keyObj in keys) { string key = (keyObj as string); if (key[0] == '.') { string newKey = key.Remove(0, 1); table[newKey] = table[keyObj]; } } } 
     //bug fix, exists only in 3.5 FW, please wrap it with defines //http://dot-net-expertise.blogspot.com/2009/10/cookiecontainer-domain-handling-bug-fix.html if(!value.Contains("://www.")) //we are going to hit the bug { string urlWWW = value.Replace("://", "://www."); Uri uriWWW = new Uri(urlWWW); foreach (Cookie c in _cookieContainer.GetCookies(uriWWW)) if (c.Domain.StartsWith(".")) request.Headers["Cookies"] += c.Name + "=" + c.Value + ";"; //manually add the cookies } //~bug fix 

    Ho perso la giornata con questo problema. La risposta di CallMeLaNN non mi ha aiutato (sto usando .Net 4.5). Nel mio caso il problema era nell’ordine di impostazione del corpo dei cookie di richiesta e impostazioni.

    In questo caso i cookie non verranno inviati al server:

      var response = (HttpWebRequest)WebRequest.Create("http://localhost:4433/"); using (var requestStream = response.GetRequestStream()) { using (var streamWriter = new StreamWriter(requestStream)) { requestStream.Write(RequestContent); } } response.CookieContainer.Add(new Cookie("Name", "Value")); await response.GetResponseAsync(); 

    Per farlo funzionare cambia l’ordine richiesto:

      var response = (HttpWebRequest)WebRequest.Create("http://localhost:4433/"); response.CookieContainer.Add(new Cookie("Name", "Value")); await response.GetResponseAsync(); using (var requestStream = response.GetRequestStream()) { using (var streamWriter = new StreamWriter(requestStream)) { requestStream.Write(RequestContent); } } 

    Ho creato una soluzione per questo problema che funziona su app Windows 10 / UWP / .NET Core. Il problema è che i componenti interni di CookieContainer sono diversi, ma altrettanto schifosi, come nel .NET Framework corretto. Quindi la soluzione accettata non funziona più.

    Ma invece di “aggiustare” il CookieContainer , ho appena scritto una versione di GetCookies() che ottiene tutti i cookie per un determinato dominio con una stringa, indipendentemente dal loro stato “sicuro” o se sono preceduti da un punto. Sentiti libero di modificarlo come ritieni adatto alle tue esigenze, e vedrò di averne implementato una versione in una futura versione di .NET Core.

     using System.Collections.Generic; using System.Reflection; namespace System.Net { ///  /// Contains extensions for the  class. ///  public static class CookieContainerExtensions { ///  /// Uses Reflection to get ALL of the Cookies where  /// contains part of the specified string. Will return cookies for any subdomain, as well as dotted-prefix cookies. ///  /// The  to extract the Cookies from. /// The string that contains part of the domain you want to extract cookies for. ///  public static IEnumerable GetCookies(this CookieContainer cookieContainer, string domain) { var domainTable = GetFieldValue(cookieContainer, "_domainTable"); foreach (var entry in domainTable) { string key = GetPropertyValue(entry, "Key"); if (key.Contains(domain)) { var value = GetPropertyValue(entry, "Value"); var internalList = GetFieldValue>(value, "_list"); foreach (var li in internalList) { foreach (Cookie cookie in li.Value) { yield return cookie; } } } } } ///  /// Gets the value of a Field for a given object instance. ///  /// The  you want the value to be converted to when returned. /// The Type instance to extract the Field's data from. /// The name of the Field to extract the data from. ///  internal static T GetFieldValue(object instance, string fieldName) { BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static; FieldInfo fi = instance.GetType().GetField(fieldName, bindFlags); return (T)fi.GetValue(instance); } ///  /// Gets the value of a Property for a given object instance. ///  /// The  you want the value to be converted to when returned. /// The Type instance to extract the Property's data from. /// The name of the Property to extract the data from. ///  internal static T GetPropertyValue(object instance, string propertyName) { var pi = instance.GetType().GetProperty(propertyName); return (T)pi.GetValue(instance, null); } } }