diff --git a/README.md b/README.md index 599eb01..36ab02e 100644 --- a/README.md +++ b/README.md @@ -38,21 +38,23 @@ PRs more than welcome. package main import ( + "context" "fmt" "github.com/browserutils/kooky" _ "github.com/browserutils/kooky/browser/all" // register cookie store finders! + "github.com/browserutils/kooky/filter" ) func main() { // uses registered finders to find cookie store files in default locations // applies the passed filters "Valid", "DomainHasSuffix()" and "Name()" in order to the cookies - cookiesSeq := kooky.TraverseCookies(context.TODO(), kooky.Valid, kooky.DomainHasSuffix(`google.com`), kooky.Name(`NID`)).OnlyCookies() + cookiesSeq := kooky.TraverseCookies(context.TODO(), filter.Valid, filter.DomainHasSuffix(`google.com`), filter.Name(`NID`)).OnlyCookies() for cookie := range cookiesSeq { fmt.Println(cookie.Domain, cookie.Name, cookie.Value) } - } +} ``` ### Chrome on macOS diff --git a/browser/chrome/chrome_test.go b/browser/chrome/chrome_test.go index c7cb48f..1cd3b4e 100644 --- a/browser/chrome/chrome_test.go +++ b/browser/chrome/chrome_test.go @@ -6,6 +6,7 @@ import ( "time" "github.com/browserutils/kooky" + "github.com/browserutils/kooky/filter" "github.com/browserutils/kooky/internal/chrome" "github.com/browserutils/kooky/internal/testutils" ) @@ -33,7 +34,7 @@ func TestReadCookies(t *testing.T) { name := "user" ctx := context.Background() - cookies = kooky.FilterCookies(ctx, cookies, kooky.Domain(domain), kooky.Name(name)).Collect(ctx) + cookies = kooky.FilterCookies(ctx, cookies, filter.Domain(domain), filter.Name(name)).Collect(ctx) if len(cookies) == 0 { t.Fatalf("Found no cookies with domain=%q, name=%q", domain, name) } diff --git a/browser/safari/safari_test.go b/browser/safari/safari_test.go index 8127b63..ae6174e 100644 --- a/browser/safari/safari_test.go +++ b/browser/safari/safari_test.go @@ -6,6 +6,7 @@ import ( "time" "github.com/browserutils/kooky" + "github.com/browserutils/kooky/filter" "github.com/browserutils/kooky/internal/testutils" ) @@ -24,7 +25,7 @@ func TestReadCookies(t *testing.T) { domain := "news.ycombinator.com" name := "user" - cookies = kooky.FilterCookies(ctx, cookies, kooky.Domain(domain), kooky.Name(name)).Collect(ctx) + cookies = kooky.FilterCookies(ctx, cookies, filter.Domain(domain), filter.Name(name)).Collect(ctx) if len(cookies) == 0 { t.Fatalf("Found no cookies with domain=%q, name=%q", domain, name) } diff --git a/cmd/kooky/kooky.go b/cmd/kooky/kooky.go index 56d24b7..bb13caa 100644 --- a/cmd/kooky/kooky.go +++ b/cmd/kooky/kooky.go @@ -13,6 +13,7 @@ import ( "github.com/browserutils/kooky" _ "github.com/browserutils/kooky/browser/all" + "github.com/browserutils/kooky/filter" "github.com/spf13/pflag" ) @@ -31,13 +32,13 @@ func main() { // cookie filters filters := []kooky.Filter{storeFilter(browser, profile, defaultProfile)} if showExpired == nil || !*showExpired { - filters = append(filters, kooky.Valid) + filters = append(filters, filter.Valid) } if domain != nil && len(*domain) > 0 { - filters = append(filters, kooky.DomainContains(*domain)) + filters = append(filters, filter.DomainContains(*domain)) } if name != nil && len(*name) > 0 { - filters = append(filters, kooky.Name(*name)) + filters = append(filters, filter.Name(*name)) } ctx, cancel := context.WithCancel(context.Background()) @@ -126,7 +127,7 @@ func prFilePath(c *kooky.Cookie) string { } func storeFilter(browser, profile *string, defaultProfile *bool) kooky.Filter { - return kooky.FilterFunc(func(cookie *kooky.Cookie) bool { + return filter.FilterFunc(func(cookie *kooky.Cookie) bool { if cookie == nil || cookie.Browser == nil { return false } diff --git a/cookiejar_example_test.go b/cookiejar_example_test.go index c233e75..975b066 100644 --- a/cookiejar_example_test.go +++ b/cookiejar_example_test.go @@ -11,6 +11,7 @@ import ( "github.com/browserutils/kooky" _ "github.com/browserutils/kooky/browser/firefox" + "github.com/browserutils/kooky/filter" ) func Example_cookieJar() { @@ -26,13 +27,13 @@ func Example_cookieJar() { } // jar := s // only store cookies relevant for the target website in the cookie jar - jar, _ := s.SubJar(ctx, kooky.FilterFunc(func(c *kooky.Cookie) bool { - return kooky.Domain(`github.com`).Filter(c) || kooky.Domain(`.github.com`).Filter(c) + jar, _ := s.SubJar(ctx, filter.FilterFunc(func(c *kooky.Cookie) bool { + return filter.Domain(`github.com`).Filter(c) || filter.Domain(`.github.com`).Filter(c) })) u, _ := url.Parse(`https://github.com/settings/profile`) - cookies := kooky.FilterCookies(ctx, jar.Cookies(u), kooky.Name(`logged_in`)).Collect(ctx) + cookies := kooky.FilterCookies(ctx, jar.Cookies(u), filter.Name(`logged_in`)).Collect(ctx) if len(cookies) == 0 { log.Fatal(`not logged in`) } diff --git a/cookiestores_example_test.go b/cookiestores_example_test.go index 3776b3e..5309dc7 100644 --- a/cookiestores_example_test.go +++ b/cookiestores_example_test.go @@ -6,6 +6,7 @@ import ( "github.com/browserutils/kooky" _ "github.com/browserutils/kooky/browser/all" // register cookiestore finders + "github.com/browserutils/kooky/filter" ) func ExampleFindAllCookieStores() { @@ -18,7 +19,7 @@ func ExampleFindAllCookieStores() { defer store.Close() var filters = []kooky.Filter{ - kooky.Valid, // remove expired cookies + filter.Valid, // remove expired cookies } for cookie := range store.TraverseCookies(filters...).OnlyCookies() { diff --git a/filter.go b/filter.go index ddddf2b..1121984 100644 --- a/filter.go +++ b/filter.go @@ -3,11 +3,8 @@ package kooky import ( "context" "errors" - "fmt" "net/http" "reflect" - "strings" - "time" ) // Filter is used for filtering cookies in ReadCookies() functions. @@ -17,24 +14,6 @@ import ( // A cookie passes the Filter if Filter.Filter returns true. type Filter interface{ Filter(*Cookie) bool } -type FilterFunc func(*Cookie) bool - -func (f FilterFunc) Filter(c *Cookie) bool { - if f == nil { - return false - } - return f(c) -} - -type ValueFilterFunc func(*Cookie) bool - -func (f ValueFilterFunc) Filter(c *Cookie) bool { - if f == nil { - return false - } - return f(c) -} - func FilterCookies[S CookieSeq | ~[]*Cookie | ~[]*http.Cookie](ctx context.Context, cookies S, filters ...Filter) CookieSeq { var ret CookieSeq // https://github.com/golang/go/issues/45380#issuecomment-1014950980 @@ -64,6 +43,26 @@ func FilterCookies[S CookieSeq | ~[]*Cookie | ~[]*http.Cookie](ctx context.Conte return ret } +func matchCookie(ctx context.Context, cookie *Cookie, filters ...Filter) bool { + if cookie == nil { + return false + } + for _, filter := range filters { + if filter == nil { + continue + } + select { + case <-ctx.Done(): + return false + default: + } + if !filter.Filter(cookie) { + return false + } + } + return true +} + func filterCookieSeq(ctx context.Context, cookies CookieSeq, filters ...Filter) CookieSeq { return func(yield func(*Cookie, error) bool) { if cookies == nil { @@ -85,7 +84,7 @@ func filterCookieSeq(ctx context.Context, cookies CookieSeq, filters ...Filter) return default: } - if !FilterCookie(ctx, cookie, filters...) { + if !matchCookie(ctx, cookie, filters...) { continue } if !yield(cookie, nil) { @@ -114,7 +113,7 @@ func filterCookieSlice[S ~[]*T, T Cookie | http.Cookie](ctx context.Context, coo default: } kooky := &Cookie{Cookie: *cookie} - if !FilterCookie(ctx, kooky, filters...) { + if !matchCookie(ctx, kooky, filters...) { continue } if !yield(kooky, nil) { @@ -132,7 +131,7 @@ func filterCookieSlice[S ~[]*T, T Cookie | http.Cookie](ctx context.Context, coo break cookieLoopKooky default: } - if !FilterCookie(ctx, cookie, filters...) { + if !matchCookie(ctx, cookie, filters...) { continue } if !yield(cookie, nil) { @@ -142,216 +141,3 @@ func filterCookieSlice[S ~[]*T, T Cookie | http.Cookie](ctx context.Context, coo } } } - -// FilterCookie() tells if a "cookie" passes all "filters". -func FilterCookie[T Cookie | http.Cookie](ctx context.Context, cookie *T, filters ...Filter) bool { - if cookie == nil { - return false - } - - var c *Cookie - // https://github.com/golang/go/issues/45380#issuecomment-1014950980 - switch cookieTyp := any(cookie).(type) { - case *http.Cookie: - c = &Cookie{Cookie: *cookieTyp} - case *Cookie: - c = cookieTyp - } - - for _, filter := range filters { - if filter == nil { - continue - } - select { - case <-ctx.Done(): - return false - default: - } - if !filter.Filter(c) { - return false - } - } - return true -} - -// debug filter - -// Debug prints the cookie. -// -// Position Debug after the filter you want to test. -var Debug Filter = FilterFunc(func(cookie *Cookie) bool { - // TODO(srlehn): where should the Debug filter be positioned when the filter rearrangement happens? - fmt.Printf("%+#v\n", cookie) - return true -}) - -// domain filters - -type domainFilter struct { - filterFunc FilterFunc - typ string - domain string -} - -func (d *domainFilter) Type() string { - if d == nil { - return `` - } - return d.typ -} -func (d *domainFilter) Domain() string { - if d == nil { - return `` - } - return d.domain -} -func (d *domainFilter) Filter(c *Cookie) bool { - return d != nil && d.filterFunc != nil && d.filterFunc(c) -} - -func Domain(domain string) Filter { - f := func(cookie *Cookie) bool { - return cookie != nil && cookie.Domain == domain - } - return &domainFilter{filterFunc: f, typ: `domain`, domain: domain} -} -func DomainContains(substr string) Filter { - return FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && strings.Contains(cookie.Domain, substr) - }) -} -func DomainHasPrefix(prefix string) Filter { - return FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && strings.HasPrefix(cookie.Domain, prefix) - }) -} -func DomainHasSuffix(suffix string) Filter { - return FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && strings.HasSuffix(cookie.Domain, suffix) - }) -} - -// name filters - -func Name(name string) Filter { - return FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && cookie.Name == name - }) -} -func NameContains(substr string) Filter { - return FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && strings.Contains(cookie.Name, substr) - }) -} -func NameHasPrefix(prefix string) Filter { - return FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && strings.HasPrefix(cookie.Name, prefix) - }) -} -func NameHasSuffix(suffix string) Filter { - return FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && strings.HasSuffix(cookie.Name, suffix) - }) -} - -// path filters - -func Path(path string) Filter { - return FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && cookie.Path == path - }) -} -func PathContains(substr string) Filter { - return FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && strings.Contains(cookie.Path, substr) - }) -} -func PathHasPrefix(prefix string) Filter { - return FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && strings.HasPrefix(cookie.Path, prefix) - }) -} -func PathHasSuffix(suffix string) Filter { - return FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && strings.HasSuffix(cookie.Path, suffix) - }) -} -func PathDepth(depth int) Filter { - return FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && strings.Count(strings.TrimRight(cookie.Path, `/`), `/`) == depth - }) -} - -// value filters - -func Value(value string) Filter { - return ValueFilterFunc(func(cookie *Cookie) bool { - return cookie != nil && cookie.Value == value - }) -} -func ValueContains(substr string) Filter { - return ValueFilterFunc(func(cookie *Cookie) bool { - return cookie != nil && strings.Contains(cookie.Value, substr) - }) -} -func ValueHasPrefix(prefix string) Filter { - return ValueFilterFunc(func(cookie *Cookie) bool { - return cookie != nil && strings.HasPrefix(cookie.Value, prefix) - }) -} -func ValueHasSuffix(suffix string) Filter { - return ValueFilterFunc(func(cookie *Cookie) bool { - return cookie != nil && strings.HasSuffix(cookie.Value, suffix) - }) -} -func ValueLen(length int) Filter { - return ValueFilterFunc(func(cookie *Cookie) bool { - return cookie != nil && len(cookie.Value) == length - }) -} - -// secure filter - -var Secure Filter = FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && cookie.Secure -}) - -// httpOnly filter - -var HTTPOnly Filter = FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && cookie.HttpOnly -}) - -// expires filters - -var Valid Filter = ValueFilterFunc(func(cookie *Cookie) bool { - return cookie != nil && cookie.Expires.After(time.Now()) && cookie.Cookie.Valid() == nil -}) - -var Expired Filter = FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && cookie.Expires.Before(time.Now()) -}) - -func ExpiresAfter(u time.Time) Filter { - return FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && cookie.Expires.After(u) - }) -} -func ExpiresBefore(u time.Time) Filter { - return FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && cookie.Expires.Before(u) - }) -} - -// creation filters - -func CreationAfter(u time.Time) Filter { - return FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && cookie.Creation.After(u) - }) -} -func CreationBefore(u time.Time) Filter { - return FilterFunc(func(cookie *Cookie) bool { - return cookie != nil && cookie.Creation.Before(u) - }) -} diff --git a/filter/filter.go b/filter/filter.go new file mode 100644 index 0000000..1d83d86 --- /dev/null +++ b/filter/filter.go @@ -0,0 +1,213 @@ +package filter + +import ( + "fmt" + "strings" + "time" + + "github.com/browserutils/kooky" +) + +// FilterFunc is the simplest way to implement a [kooky.Filter]. +type FilterFunc func(*kooky.Cookie) bool + +func (f FilterFunc) Filter(c *kooky.Cookie) bool { + if f == nil { + return false + } + return f(c) +} + +// ValueFilterFunc marks a [kooky.Filter] as depending on the cookie value. +// This allows filter-aware cookie stores to defer expensive operations like +// decryption until non-value filters have passed. +type ValueFilterFunc func(*kooky.Cookie) bool + +func (f ValueFilterFunc) Filter(c *kooky.Cookie) bool { + if f == nil { + return false + } + return f(c) +} + +// debug filter + +// Debug prints the cookie. +// +// Position Debug after the filter you want to test. +var Debug kooky.Filter = FilterFunc(func(cookie *kooky.Cookie) bool { + // TODO(srlehn): where should the Debug filter be positioned when the filter rearrangement happens? + fmt.Printf("%+#v\n", cookie) + return true +}) + +// domain filters + +type domainFilter struct { + filterFunc FilterFunc + typ string + domain string +} + +func (d *domainFilter) Type() string { + if d == nil { + return `` + } + return d.typ +} +func (d *domainFilter) Domain() string { + if d == nil { + return `` + } + return d.domain +} +func (d *domainFilter) Filter(c *kooky.Cookie) bool { + return d != nil && d.filterFunc != nil && d.filterFunc(c) +} + +func Domain(domain string) kooky.Filter { + f := func(cookie *kooky.Cookie) bool { + return cookie != nil && cookie.Domain == domain + } + return &domainFilter{filterFunc: f, typ: `domain`, domain: domain} +} +func DomainContains(substr string) kooky.Filter { + return FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && strings.Contains(cookie.Domain, substr) + }) +} +func DomainHasPrefix(prefix string) kooky.Filter { + return FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && strings.HasPrefix(cookie.Domain, prefix) + }) +} +func DomainHasSuffix(suffix string) kooky.Filter { + return FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && strings.HasSuffix(cookie.Domain, suffix) + }) +} + +// name filters + +func Name(name string) kooky.Filter { + return FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && cookie.Name == name + }) +} +func NameContains(substr string) kooky.Filter { + return FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && strings.Contains(cookie.Name, substr) + }) +} +func NameHasPrefix(prefix string) kooky.Filter { + return FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && strings.HasPrefix(cookie.Name, prefix) + }) +} +func NameHasSuffix(suffix string) kooky.Filter { + return FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && strings.HasSuffix(cookie.Name, suffix) + }) +} + +// path filters + +func Path(path string) kooky.Filter { + return FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && cookie.Path == path + }) +} +func PathContains(substr string) kooky.Filter { + return FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && strings.Contains(cookie.Path, substr) + }) +} +func PathHasPrefix(prefix string) kooky.Filter { + return FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && strings.HasPrefix(cookie.Path, prefix) + }) +} +func PathHasSuffix(suffix string) kooky.Filter { + return FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && strings.HasSuffix(cookie.Path, suffix) + }) +} +func PathDepth(depth int) kooky.Filter { + return FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && strings.Count(strings.TrimRight(cookie.Path, `/`), `/`) == depth + }) +} + +// value filters + +func Value(value string) kooky.Filter { + return ValueFilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && cookie.Value == value + }) +} +func ValueContains(substr string) kooky.Filter { + return ValueFilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && strings.Contains(cookie.Value, substr) + }) +} +func ValueHasPrefix(prefix string) kooky.Filter { + return ValueFilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && strings.HasPrefix(cookie.Value, prefix) + }) +} +func ValueHasSuffix(suffix string) kooky.Filter { + return ValueFilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && strings.HasSuffix(cookie.Value, suffix) + }) +} +func ValueLen(length int) kooky.Filter { + return ValueFilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && len(cookie.Value) == length + }) +} + +// secure filter + +var Secure kooky.Filter = FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && cookie.Secure +}) + +// httpOnly filter + +var HTTPOnly kooky.Filter = FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && cookie.HttpOnly +}) + +// expires filters + +var Valid kooky.Filter = ValueFilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && cookie.Expires.After(time.Now()) && cookie.Cookie.Valid() == nil +}) + +var Expired kooky.Filter = FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && cookie.Expires.Before(time.Now()) +}) + +func ExpiresAfter(u time.Time) kooky.Filter { + return FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && cookie.Expires.After(u) + }) +} +func ExpiresBefore(u time.Time) kooky.Filter { + return FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && cookie.Expires.Before(u) + }) +} + +// creation filters + +func CreationAfter(u time.Time) kooky.Filter { + return FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && cookie.Creation.After(u) + }) +} +func CreationBefore(u time.Time) kooky.Filter { + return FilterFunc(func(cookie *kooky.Cookie) bool { + return cookie != nil && cookie.Creation.Before(u) + }) +} diff --git a/filter_example_test.go b/filter_example_test.go index 4078830..210b007 100644 --- a/filter_example_test.go +++ b/filter_example_test.go @@ -7,6 +7,7 @@ import ( "regexp" "github.com/browserutils/kooky" + "github.com/browserutils/kooky/filter" ) // example regex matching base64 strings @@ -20,7 +21,7 @@ func ExampleFilter_regex() { ctx, cookies, ValueRegexMatch(reBase64), // filter cookies with the regex filter - // kooky.Debug, // print cookies after applying the regex filter + // filter.Debug, // print cookies after applying the regex filter ).Collect(ctx) for _, cookie := range cookies { @@ -32,7 +33,7 @@ func ExampleFilter_regex() { } func ValueRegexMatch(re *regexp.Regexp) kooky.Filter { - return kooky.FilterFunc(func(cookie *kooky.Cookie) bool { + return filter.FilterFunc(func(cookie *kooky.Cookie) bool { return cookie != nil && re != nil && re.Match([]byte(cookie.Value)) }) } diff --git a/filtercookies_example_test.go b/filtercookies_example_test.go index a056076..5703eb2 100644 --- a/filtercookies_example_test.go +++ b/filtercookies_example_test.go @@ -5,6 +5,7 @@ import ( "github.com/browserutils/kooky" _ "github.com/browserutils/kooky/browser/all" // register cookiestore finders + "github.com/browserutils/kooky/filter" ) var cookieName = `NID` @@ -16,10 +17,10 @@ func ExampleFilterCookies() { Seq(). Filter( ctx, - kooky.Valid, // remove expired cookies - kooky.DomainContains(`google`), // cookie domain has to contain "google" - kooky.Name(cookieName), // cookie name is "NID" - kooky.Debug, // print cookies after applying previous filter + filter.Valid, // remove expired cookies + filter.DomainContains(`google`), // cookie domain has to contain "google" + filter.Name(cookieName), // cookie name is "NID" + filter.Debug, // print cookies after applying previous filter ). Collect(ctx) // iterate and collect in a slice diff --git a/firstmatch_nid_test.go b/firstmatch_nid_test.go index 6512ede..0f37253 100644 --- a/firstmatch_nid_test.go +++ b/firstmatch_nid_test.go @@ -1,19 +1,22 @@ -package kooky +package kooky_test import ( "context" "testing" + + "github.com/browserutils/kooky" + "github.com/browserutils/kooky/filter" ) -var nidFilters = []Filter{ - Domain(`.google.com`), - Name(`NID`), +var nidFilters = []kooky.Filter{ + filter.Domain(`.google.com`), + filter.Name(`NID`), } func BenchmarkFirstMatch(b *testing.B) { ctx := context.Background() for i := 0; i < b.N; i++ { - cookie := TraverseCookies(ctx).FirstMatch(ctx, nidFilters...) + cookie := kooky.TraverseCookies(ctx).FirstMatch(ctx, nidFilters...) _ = cookie } } @@ -21,7 +24,7 @@ func BenchmarkFirstMatch(b *testing.B) { func BenchmarkFirstMatchSlice(b *testing.B) { for i := 0; i < b.N; i++ { // cookies := ReadCookies(nidFilters...) // old name - cookies := AllCookies(nidFilters...) + cookies := kooky.AllCookies(nidFilters...) _ = cookies } } diff --git a/internal/iterx/iter.go b/internal/iterx/iter.go index b5dd502..dbb51a9 100644 --- a/internal/iterx/iter.go +++ b/internal/iterx/iter.go @@ -5,8 +5,29 @@ import ( "errors" "github.com/browserutils/kooky" + "github.com/browserutils/kooky/filter" ) +func matchCookie(ctx context.Context, cookie *kooky.Cookie, filters ...kooky.Filter) bool { + if cookie == nil { + return false + } + for _, f := range filters { + if f == nil { + continue + } + select { + case <-ctx.Done(): + return false + default: + } + if !f.Filter(cookie) { + return false + } + } + return true +} + func CookieFilterYield(ctx context.Context, cookie *kooky.Cookie, errCookie error, yield func(*kooky.Cookie, error) bool, filters ...kooky.Filter) bool { if errCookie != nil { if errors.Is(errCookie, ErrYieldEnd) { @@ -14,7 +35,7 @@ func CookieFilterYield(ctx context.Context, cookie *kooky.Cookie, errCookie erro } return yield(nil, errCookie) } - if kooky.FilterCookie(ctx, cookie, filters...) { + if matchCookie(ctx, cookie, filters...) { return yield(cookie, nil) } return true @@ -27,12 +48,12 @@ func CookieFilterYield(ctx context.Context, cookie *kooky.Cookie, errCookie erro func NewLazyCookieFilterYielder(splitFilters bool, filters ...kooky.Filter) func(_ context.Context, yield func(*kooky.Cookie, error) bool, _ *kooky.Cookie, errCookie error, valRetriever func(*kooky.Cookie) error) bool { var valueFilters, nonValueFilters []kooky.Filter if splitFilters { - for _, filter := range filters { - if _, ok := filter.(kooky.ValueFilterFunc); ok { - valueFilters = append(valueFilters, filter) + for _, f := range filters { + if _, ok := f.(filter.ValueFilterFunc); ok { + valueFilters = append(valueFilters, f) } else { // these non-value filters can be used for prefiltering before value decryption - nonValueFilters = append(nonValueFilters, filter) + nonValueFilters = append(nonValueFilters, f) } } } @@ -51,13 +72,13 @@ func NewLazyCookieFilterYielder(splitFilters bool, filters ...kooky.Filter) func return err == nil || (yield(nil, err) && false) } if valRetriever != nil { - if kooky.FilterCookie(ctx, cookie, nonValueFilters...) && + if matchCookie(ctx, cookie, nonValueFilters...) && retr(cookie) && - kooky.FilterCookie(ctx, cookie, valueFilters...) { + matchCookie(ctx, cookie, valueFilters...) { return yield(cookie, nil) } } else { - if kooky.FilterCookie(ctx, cookie, filters...) { + if matchCookie(ctx, cookie, filters...) { return yield(cookie, nil) } } diff --git a/kooky.go b/kooky.go index 388f3b0..c5c1b8e 100644 --- a/kooky.go +++ b/kooky.go @@ -188,7 +188,7 @@ func (s CookieSeq) Filter(ctx context.Context, filters ...Filter) CookieSeq { return default: } - if !FilterCookie(ctx, cookie, filters...) { + if !matchCookie(ctx, cookie, filters...) { continue } if !yield(cookie, nil) { @@ -208,7 +208,7 @@ func (s CookieSeq) FirstMatch(ctx context.Context, filters ...Filter) *Cookie { return nil default: } - if FilterCookie(ctx, cookie, filters...) { + if matchCookie(ctx, cookie, filters...) { return cookie } }