2010-09-15 12 views
9

Estoy trabajando en un proyecto que implica un rastreo web básico. He estado utilizando HttpWebRequest y HttpWebResponse con bastante éxito. Para el manejo de cookies, solo tengo un CookieContainer que asigno a HttpWebRequest.CookieContainer cada vez. Me vuelvo a llenar automáticamente con las nuevas cookies cada vez y no requiere un manejo adicional de mi parte. Todo esto ha funcionado bien hasta hace poco cuando uno de los sitios web que solía funcionar de repente dejó de funcionar. Estoy razonablemente seguro de que es un problema con las cookies, pero no guardé un registro de las cookies de cuando solía funcionar, así que no estoy 100% seguro.CookieContainer manejo de rutas (¿Quién comió mi cookie?)

He conseguido simular el problema tal como la veo con el siguiente código:

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

Esto simula visitar dos páginas, los cuales establecen dos galletas. A continuación, comprueba cuál de esas cookies se establecería en cada una de las tres páginas.

De las dos cookies, una se establece sin especificar una ruta y la otra tiene una ruta especificada. Cuando no se especifica una ruta, asumí que la cookie se enviaría de vuelta a cualquier página de ese dominio, pero parece que solo se envía de vuelta a esa página específica. Ahora estoy asumiendo que es correcto ya que es consistente.

El principal problema para mí es el manejo de cookies con una ruta especificada. Seguramente, si se especifica una ruta, la cookie debe enviarse a cualquier página contenida dentro de esa ruta. Por lo tanto, en el código anterior, 'CookieWithPath' debe ser válido para cualquier página dentro de/some/path /, que incluye page1.html, page2.html y page3.html. Ciertamente, si comenta las dos instancias 'NoPathCookie', entonces 'CookieWithPath' se envía a las tres páginas como era de esperar. Sin embargo, con la inclusión de 'NoPathCookie' como se indica anteriormente, 'CookieWithPath' solo se envía a page2.html y page3.html, pero no a page1.html.

¿Por qué es esto, y es correcto?

Buscando este problema He encontrado una discusión sobre un problema con el manejo de dominio en CookieContainer, pero no he podido encontrar ninguna discusión sobre el manejo de rutas.

Estoy usando Visual Studio 2005/.NET 2,0

Respuesta

2

Cuando no se especifica una ruta, que había asumido que la cookie sería enviado de vuelta a cualquier página de ese dominio, pero parece que sólo se ser enviado de vuelta a esa página específica. Ahora estoy asumiendo que es correcto ya que es consistente.

Sí, eso es correcto. Siempre que no se especifique el dominio o la ruta, se tomará del URI actual.

Bien, echemos un vistazo a CookieContainer. El método en cuestión es InternalGetCookies(Uri). Aquí está la parte interesante:

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 aquí es una lista (ordenada) de caminos de galletas. Está ordenado de tal forma que las rutas más específicas (como /directory/subdirectory/) van antes que las menos específicas (como /directory/), y de lo contrario, en orden lexicográfico (/directory/page1 va antes de /directory/page2).

El código hace realmente lo siguiente: itera sobre esta lista de rutas de cookies hasta que encuentra una primera ruta, que es un prefijo para la ruta de URI solicitada.Luego agrega cookies bajo esa ruta a la salida y establece flag2 en true, lo que significa "OK, finalmente encontré el lugar en la lista que realmente se relaciona con el URI solicitado". Después de eso, la primera ruta encontrada, que NO es un prefijo para la ruta URI solicitada, se considera el final de las rutas relacionadas, por lo que el código deja de buscar cookies haciendo break.

Obviamente, este es un tipo de optimización para evitar el escaneo de toda la lista y aparentemente funciona si ninguna de las rutas conduce a una página concreta. Ahora, para su caso, la lista de rutas que se parece a:

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

Usted puede comprobar que con un depurador, mirando hacia arriba en la ventana de inspección ((System.Net.PathList)(cookieJar.m_domainTable["www.somedomain.com"])).m_list

Así, por 'page1.html' URI, el código se rompe en el artículo page2.html, sin posibilidad de procesar también el artículo /some/path/.

En conclusión: obviamente este es otro error en CookieContainer. Creo que debería informarse en connect.

PD: Eso es demasiados errores por clase. Solo espero que el tipo de MS que escribió las pruebas para esta clase ya haya sido despedido.

Cuestiones relacionadas