CookieContainer обработка путей (Кто съел мой cookie?) - PullRequest
9 голосов
/ 15 сентября 2010

Я работаю над проектом, который включает в себя базовое сканирование. Я использую HttpWebRequest и HttpWebResponse довольно успешно. Для обработки куки у меня есть только один CookieContainer, который я каждый раз назначаю HttpWebRequest.CookieContainer. Я автоматически попадаю на новые куки каждый раз и не требую от меня дополнительной обработки. Все это работало нормально, пока некоторое время назад один из сайтов, которые раньше работали, внезапно перестал работать. Я вполне уверен, что это проблема с файлами cookie, но я не вел учет файлов cookie с того времени, когда они работали, поэтому я не уверен на 100%.

Мне удалось смоделировать проблему с помощью следующего кода:

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

1 Ответ

2 голосов
/ 20 февраля 2013

Когда путь не указан, я предполагал, что файл 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, считается концом связанных путей, поэтому код прекращает поиск файлов 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.Я полагаю, что об этом следует сообщать при подключении.

PS: Слишком много ошибок в одном классе.Я только надеюсь, что парень из MS, который написал тесты для этого класса, уже уволен.

...