Files
go-extractor/cookies_txt.go
Steve Dudenhoeffer 963696cd62
All checks were successful
CI / vet (pull_request) Successful in 40s
CI / build (pull_request) Successful in 1m22s
CI / test (pull_request) Successful in 1m28s
enhance: thread-safe CookieJar, SameSite cookie attr, dynamic Google countries
- Wrap staticCookieJar in struct with sync.RWMutex for thread safety
- Add SameSite field to Cookie struct with Strict/Lax/None constants
- Update Playwright cookie conversion functions for SameSite
- Replace hardcoded 4-country switch with dynamic country code generation

Closes #20, #22, #23
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 16:34:54 +00:00

124 lines
2.4 KiB
Go

package extractor
import (
"bufio"
"io"
"os"
"strconv"
"strings"
"sync"
"time"
)
type staticCookieJar struct {
mu sync.RWMutex
cookies []Cookie
}
// GetAll will return all cookies in the jar.
func (s *staticCookieJar) GetAll() ([]Cookie, error) {
s.mu.RLock()
defer s.mu.RUnlock()
out := make([]Cookie, len(s.cookies))
copy(out, s.cookies)
return out, nil
}
// Get will, given a URL, return all cookies that are valid for that URL.
func (s *staticCookieJar) Get(target string) ([]Cookie, error) {
s.mu.RLock()
defer s.mu.RUnlock()
var validCookies []Cookie
for _, cookie := range s.cookies {
if match, err := cookie.IsTargetMatch(target); err != nil {
return nil, err
} else if match {
validCookies = append(validCookies, cookie)
}
}
return validCookies, nil
}
func (s *staticCookieJar) Set(cookie Cookie) error {
s.mu.Lock()
defer s.mu.Unlock()
// see if the cookie already exists
for i, c := range s.cookies {
if c.Name == cookie.Name && c.Host == cookie.Host && c.Path == cookie.Path {
s.cookies[i] = cookie
return nil
}
}
s.cookies = append(s.cookies, cookie)
return nil
}
func (s *staticCookieJar) Delete(cookie Cookie) error {
s.mu.Lock()
defer s.mu.Unlock()
for i, c := range s.cookies {
if c.Name == cookie.Name && c.Host == cookie.Host && c.Path == cookie.Path {
s.cookies = append(s.cookies[:i], s.cookies[i+1:]...)
return nil
}
}
return nil
}
// LoadCookiesFile loads cookies from a file, in the format of cookies.txt.
func LoadCookiesFile(path string) (CookieJar, error) {
fp, err := os.Open(path)
if err != nil {
return nil, err
}
defer func(cl io.Closer) {
_ = cl.Close()
}(fp)
var cookies []Cookie
scanner := bufio.NewScanner(fp)
for scanner.Scan() {
line := scanner.Text()
if line == "" {
continue
}
if line[0] == '#' {
continue
}
parts := strings.Split(line, "\t")
if len(parts) < 7 {
continue
}
expiry, err := strconv.ParseInt(parts[4], 10, 64)
if err != nil {
expiry = time.Now().Add(180 * 24 * time.Hour).Unix() // Default expiry
}
cookies = append(cookies, Cookie{
Host: parts[0],
HttpOnly: strings.ToLower(parts[1]) == "true",
Path: parts[2],
Secure: strings.ToLower(parts[3]) == "true",
Name: parts[5],
Expires: time.Unix(expiry, 0),
Value: parts[6],
})
}
return &staticCookieJar{cookies: cookies}, nil
}