package proxy import ( "net/http" "net/url" "strings" ) // ExtractSessionHeaders сканирует историю в поисках самой свежей записи // под заданный host и вытаскивает из неё Cookie/Authorization — типичные // заголовки сессии. Используется Spider, чтобы обходить авторизованные // зоны сайта без ручного копирования куки: если ты уже походил по сайту // руками через браузер с настроенным прокси, краулер сам подхватит ту же // сессию. // // Идёт от конца истории к началу (самые новые записи первыми) — сессия // могла обновиться (перелогин, ротация токена), и должна использоваться // самая свежая версия, а не первая попавшаяся. func ExtractSessionHeaders(entries []Entry, host string) http.Header { h := http.Header{} for i := len(entries) - 1; i >= 0; i-- { e := entries[i] u, err := url.Parse(e.URL) if err != nil || u.Host != host { continue } cookie, auth := parseSessionHeadersFromRaw(e.Raw) if cookie != "" && h.Get("Cookie") == "" { h.Set("Cookie", cookie) } if auth != "" && h.Get("Authorization") == "" { h.Set("Authorization", auth) } if h.Get("Cookie") != "" && h.Get("Authorization") != "" { break // нашли оба — дальше по истории идти незачем } } return h } // parseSessionHeadersFromRaw вытаскивает значения заголовков Cookie и // Authorization из сырого текста HTTP-запроса (Entry.Raw). Останавливается // на первой пустой строке — конец заголовков, начало тела, там эти // заголовки заведомо не встретятся, а тело может быть сколь угодно большим. func parseSessionHeadersFromRaw(raw string) (cookie, auth string) { for _, line := range strings.Split(raw, "\n") { line = strings.TrimRight(line, "\r") if line == "" { break } lower := strings.ToLower(line) switch { case strings.HasPrefix(lower, "cookie:"): cookie = strings.TrimSpace(line[len("cookie:"):]) case strings.HasPrefix(lower, "authorization:"): auth = strings.TrimSpace(line[len("authorization:"):]) } } return cookie, auth }