2010-09-15 40 views
9

我正在研究一個涉及一些基本網絡爬行的項目。我一直在很成功地使用HttpWebRequest和HttpWebResponse。對於cookie處理,我只有一個CookieContainer,每次都分配給HttpWebRequest.CookieContainer。我每次都會自動獲得新的cookie,不需要額外的處理。直到很久以前,當一個曾經工作的網站突然停止工作時,這一切都運行良好。我相當肯定這是一個與Cookie有關的問題,但是我沒有記錄它從來沒有使用過的cookies,所以我不能100%確定。CookieContainer處理路徑(誰吃了我的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應該被髮送到該路徑中包含的任何頁面。因此,在上面的代碼中,'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

回答

2

如果未指定路徑,我曾以爲,該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這裏是餅乾路徑(排序)名單。它以這種方式排序,更具體的路徑(如/directory/subdirectory/)在較不具體的路徑之前(如/directory/),否則 - 以字典順序(/directory/page1/directory/page2之前)。

該代碼實際上執行以下操作:它遍歷cookie的路徑列表,直到找到第一個路徑,即所請求的URI路徑的前綴。然後它將該路徑下的cookie添加到輸出中,並將flag2設置爲true,這意味着「確定,我最終在列表中找到了與請求的URI實際相關的位置」。之後,第一個會見路徑(不是所請求的URI路徑的前綴)將被視爲相關路徑的結尾,因此代碼將停止搜索cookie,方法是執行break

顯然,這是一種優化,以防止掃描整個列表,它顯然工作,如果沒有路徑導致具體頁面。現在,你的情況下,路徑列表看起來像這樣:

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

您可以檢查與調試,尋找在監視窗口中最多((System.Net.PathList)(cookieJar.m_domainTable["www.somedomain.com"])).m_list

所以,對於「page1.html」 URI,代碼打破page2.html項目,沒有機會處理也/some/path/項目。

總之:這顯然是CookieContainer中的另一個bug。我相信它應該在連接上報告。

PS:這是太多的錯誤每一個類。我只希望MS爲這個班級編寫測試的人已經被解僱了。