CookieContainer处理路径(谁吃了我的cookie?)

我正在开发一个涉及一些基本网络爬行的项目。 我一直在成功使用HttpWebRequest和HttpWebResponse。 对于cookie处理,我只有一个CookieContainer,我每次都分配给HttpWebRequest.CookieContainer。 每次我自动填充新的cookie,不需要我的额外处理。 直到不久之前,当其中一个曾经工作的网站突然停止工作时,这一切都很好。 我有理由相信这是一个有问题的cookie,但是我没有记录过以前的cookie,所以我不是百分百肯定的。

我用以下代码设法模拟了这个问题:

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

这模拟访问两个页面,两个页面都设置了两个cookie。 然后,它会检查哪些cookie将设置为三个页面中的每一个。

在两个cookie中,一个是在没有指定路径的情况下设置的,另一个是指定的路径。 当未指定路径时,我假设cookie将被发送回该域中的任何页面,但它似乎只会被发送回该特定页面。 我现在假设这是正确的,因为它是一致的。

对我来说,主要的问题是处理带有指定路径的cookie。 当然,如果指定了路径,则应将cookie发送到该路径中包含的任何页面。 因此,在上面的代码中,’CookieWithPath’应该对/ some / path /中的任何页面有效,其中包括page1.html,page2.html和page3.html。 当然,如果你注释掉两个’NoPathCookie’实例,那么’CookieWithPath’会像我期望的那样被发送到所有三个页面。 但是,如上所述包含’NoPathCookie’,那么’CookieWithPath’只会被发送到page2.html和page3.html,但不会发送到page1.html。

为什么这样,是否正确?

搜索此问题我在CookieContainer中遇到了有关域处理问题的讨论,但未能找到有关路径处理的任何讨论。

我正在使用Visual Studio 2005 / .NET 2.0

当未指定路径时,我假设cookie将被发送回该域中的任何页面,但它似乎只会被发送回该特定页面。 我现在假设这是正确的,因为它是一致的。

是的,这是正确的。 每当未指定域或路径时,它都取自当前URI。

好的,我们来看看CookieContainer。 有问题的方法是InternalGetCookies(Uri) 。 这是有趣的部分:

 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是一个(排序的)cookie路径列表。 它以这样的方式排序,更具体的路径(如/directory/subdirectory/ )在不太具体的路径之前(如/directory/ ),否则 - 以字典顺序排列( /directory/page1/directory/page2之前) 。

该代码实际上执行以下操作:它遍历此cookie的路径列表,直到找到第一个路径,即所请求的URI路径的前缀。 然后它在该路径下添加一个cookie到输出并将flag2设置为true ,这意味着“好的,我终于在列表中找到了与请求的URI实际相关的位置”。 之后,第一个遇到的路径,即不是请求的URI路径的前缀,被认为是相关路径的结束,因此代码停止通过break搜索cookie。

显然,这是一种优化,以防止扫描整个列表,如果没有路径导致具体页面,它显然有效。 现在,对于您的情况,路径列表如下所示:

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

您可以使用调试器进行检查,查看((System.Net.PathList)(cookieJar.m_domainTable["www.somedomain.com"])).m_list监视窗口中的((System.Net.PathList)(cookieJar.m_domainTable["www.somedomain.com"])).m_list

因此,对于'page1.html'URI,代码在page2.html项目中断,没有机会处理/some/path/ item。

总之:这显然是CookieContainer中的另一个错误。 我相信它应该在连接上报告。

PS:每个class级的错误太多了。 我只希望那个为这门课写过考试的MS的家伙已经被解雇了。