2010-09-15 16 views
9

Je travaille sur un projet qui implique une exploration de base du Web. J'ai utilisé HttpWebRequest et HttpWebResponse assez bien. Pour la gestion des cookies, j'ai juste un CookieContainer que j'affecte à HttpWebRequest.CookieContainer à chaque fois. Je reçois automatiquement les nouveaux cookies à chaque fois et ne nécessite aucun traitement supplémentaire de ma part. Tout cela a bien fonctionné jusqu'à tout récemment, lorsque l'un des sites Web qui fonctionnait soudainement a cessé de fonctionner. Je suis raisonnablement sûr que c'est un problème avec les cookies, mais je n'ai pas gardé un enregistrement des cookies de quand il a l'habitude de travailler, donc je ne suis pas sûr à 100%.CookieContainer gestion des chemins (Qui a mangé mon cookie?)

J'ai réussi à simuler le problème que je vois avec le code suivant:

CookieContainer cookieJar = new CookieContainer(); 

Uri uri1 = new Uri("http://www.somedomain.com/some/path/page1.html"); 
CookieCollection cookies1 = new CookieCollection(); 
cookies1.Add(new Cookie("NoPathCookie", "Page1Value")); 
cookies1.Add(new Cookie("CookieWithPath", "Page1Value", "/some/path/")); 

Uri uri2 = new Uri("http://www.somedomain.com/some/path/page2.html"); 
CookieCollection cookies2 = new CookieCollection(); 
cookies2.Add(new Cookie("NoPathCookie", "Page2Value")); 
cookies2.Add(new Cookie("CookieWithPath", "Page2Value", "/some/path/")); 

Uri uri3 = new Uri("http://www.somedomain.com/some/path/page3.html"); 

// Add the cookies from page1.html 
cookieJar.Add(uri1, cookies1); 

// Add the cookies from page2.html 
cookieJar.Add(uri2, cookies2); 

// We should now have 3 cookies 
Console.WriteLine(string.Format("CookieJar contains {0} cookies", cookieJar.Count)); 

Console.WriteLine(string.Format("Cookies to send to page1.html: {0}", cookieJar.GetCookieHeader(uri1))); 
Console.WriteLine(string.Format("Cookies to send to page2.html: {0}", cookieJar.GetCookieHeader(uri2))); 
Console.WriteLine(string.Format("Cookies to send to page3.html: {0}", cookieJar.GetCookieHeader(uri3))); 

Ceci simule la visite de deux pages, les deux qui définissent deux cookies. Il vérifie ensuite lequel de ces cookies sera défini sur chacune des trois pages.

Parmi les deux cookies, un est défini sans spécifier de chemin et l'autre a un chemin spécifié. Quand un chemin n'est pas spécifié, j'ai supposé que le cookie serait renvoyé vers n'importe quelle page de ce domaine, mais il semble que je ne sois renvoyé qu'à cette page spécifique. Je suppose maintenant que c'est correct car c'est cohérent.

Le principal problème pour moi est le traitement des cookies avec un chemin spécifié. Sûrement, si un chemin est spécifié alors le cookie devrait être envoyé à n'importe quelle page contenue dans ce chemin. Ainsi, dans le code ci-dessus, 'CookieWithPath' devrait être valide pour n'importe quelle page dans/some/path /, qui comprend page1.html, page2.html et page3.html. Certainement, si vous commentez les deux instances 'NoPathCookie', alors le 'CookieWithPath' est envoyé aux trois pages comme je l'aurais attendu. Cependant, avec l'inclusion de 'NoPathCookie' comme ci-dessus, alors 'CookieWithPath' n'est envoyé qu'aux pages2.html et page3.html, mais pas page1.html.

Pourquoi est-ce, et est-ce correct?

Recherche de ce problème J'ai rencontré une discussion sur un problème de gestion de domaine dans CookieContainer, mais je n'ai trouvé aucune discussion sur la gestion des chemins.

J'utilise Visual Studio 2005/2.0

.NET

Répondre

2

Lorsqu'un chemin n'est pas spécifié, je l'avais supposé que le cookie serait renvoyé à une page dans ce domaine, mais il semble que être renvoyé à cette page spécifique. Je suppose maintenant que c'est correct car c'est cohérent.

Oui, c'est correct. Chaque fois que le domaine ou le chemin n'est pas spécifié, il provient de l'URI en cours.

OK, jetons un coup d'œil à CookieContainer. La méthode en question est InternalGetCookies(Uri). Voici la partie intéressante:

while (enumerator2.MoveNext()) 
{ 
    DictionaryEntry dictionaryEntry = (DictionaryEntry)enumerator2.get_Current(); 
    string text2 = (string)dictionaryEntry.get_Key(); 
    if (!uri.AbsolutePath.StartsWith(CookieParser.CheckQuoted(text2))) 
    { 
     if (flag2) 
     { 
      break; 
     } 
     else 
     { 
      continue; 
     } 
    } 
    flag2 = true; 
    CookieCollection cookieCollection2 = (CookieCollection)dictionaryEntry.get_Value(); 
    cookieCollection2.TimeStamp(CookieCollection.Stamp.Set); 
    this.MergeUpdateCollections(cookieCollection, cookieCollection2, port, flag, i < 0); 
    if (!(text2 == "/")) 
    { 
     continue; 
    } 
    flag3 = true; 
    continue; 
} 

enumerator2 est ici une liste (triée) des chemins de cookies. Il est trié de telle manière, que les chemins plus spécifiques (comme /directory/subdirectory/) vont avant les moins spécifiques (comme /directory/), et autrement - dans l'ordre lexicographique (/directory/page1 va avant /directory/page2).

Le code fait effectivement ce qui suit: il itère sur cette liste de chemins de cookies jusqu'à ce qu'il trouve un premier chemin, c'est-à-dire un préfixe pour le chemin de l'URI demandé.Ensuite, il ajoute un cookie sous ce chemin à la sortie et définit flag2 à true, ce qui signifie "OK, j'ai finalement trouvé l'endroit dans la liste qui se rapporte réellement à l'URI demandé". Après cela, le premier chemin rencontré, qui n'est PAS un préfixe pour le chemin de l'URI demandé, est considéré comme étant la fin des chemins associés, de sorte que le code cesse de rechercher des cookies en faisant break.

De toute évidence, il s'agit d'une sorte d'optimisation pour empêcher l'analyse de toute la liste et cela fonctionne apparemment si aucun des chemins ne mène à une page concrète. Maintenant, pour votre cas, la liste des chemins ressemble que:

/some/path/page1.html 
/some/path/page2.html 
/some/path/ 

Vous pouvez vérifier que avec un débogueur, regardant ((System.Net.PathList)(cookieJar.m_domainTable["www.somedomain.com"])).m_list dans la fenêtre montre

Ainsi, pour URI de page1.html ', le code interrompt page2.html article, n'ayant pas la chance de traiter également /some/path/ article. En conclusion: c'est évidemment un autre bug dans CookieContainer. Je crois qu'il devrait être signalé sur connect. PS: Il y a trop de bogues par classe. J'espère seulement que le gars de MS qui a écrit des tests pour cette classe est déjà renvoyé.