From 1f195ce1ced4ccbfdc6ba818b7f9bffd6ee3343e Mon Sep 17 00:00:00 2001 From: darkweak Date: Thu, 8 Feb 2024 10:04:31 +0100 Subject: [PATCH] fix(plugins): traefik surrogate-keys --- .../traefik/override/storage/cacheProvider.go | 17 ++++++++--- .../override/surrogate/providers/common.go | 29 ++++++++++++------- .../github.com/darkweak/souin/api/souin.go | 1 + .../darkweak/souin/pkg/api/souin.go | 1 + .../souin/pkg/storage/cacheProvider.go | 17 ++++++++--- .../souin/pkg/surrogate/providers/common.go | 29 ++++++++++++------- 6 files changed, 64 insertions(+), 30 deletions(-) diff --git a/plugins/traefik/override/storage/cacheProvider.go b/plugins/traefik/override/storage/cacheProvider.go index 6cf442da9..ab5d9fb8a 100644 --- a/plugins/traefik/override/storage/cacheProvider.go +++ b/plugins/traefik/override/storage/cacheProvider.go @@ -20,10 +20,17 @@ type Cache struct { stale time.Duration } +var sharedCache *Cache + // CacheConnectionFactory function create new Cache instance func CacheConnectionFactory(c t.AbstractConfigurationInterface) (types.Storer, error) { provider := cache.New(1 * time.Second) - return &Cache{Cache: provider, stale: c.GetDefaultCache().GetStale()}, nil + + if sharedCache == nil { + sharedCache = &Cache{Cache: provider, stale: c.GetDefaultCache().GetStale()} + } + + return sharedCache, nil } // Name returns the storer name @@ -44,10 +51,12 @@ func (provider *Cache) ListKeys() []string { // MapKeys method returns the map of existing keys func (provider *Cache) MapKeys(prefix string) map[string]string { - var keys map[string]string + keys := map[string]string{} provider.Cache.Range(func(key, value interface{}) bool { - k, _ := strings.CutPrefix(key.(string), prefix) - keys[k] = value.(string) + if strings.HasPrefix(key.(string), prefix) { + k, _ := strings.CutPrefix(key.(string), prefix) + keys[k] = string(value.([]byte)) + } return true }) diff --git a/plugins/traefik/override/surrogate/providers/common.go b/plugins/traefik/override/surrogate/providers/common.go index ef6c1cda4..bfedad1b8 100644 --- a/plugins/traefik/override/surrogate/providers/common.go +++ b/plugins/traefik/override/surrogate/providers/common.go @@ -7,6 +7,7 @@ import ( "regexp" "strings" "sync" + "time" "github.com/darkweak/souin/configurationtypes" "github.com/darkweak/souin/pkg/storage" @@ -15,6 +16,7 @@ import ( const ( cdnCacheControl = "CDN-Cache-Control" + cacheGroupKey = "Cache-Groups" surrogateKey = "Surrogate-Key" surrogateControl = "Surrogate-Control" cacheControl = "Cache-Control" @@ -26,9 +28,14 @@ const ( cacheTags = "Cache-Tags" cacheTag = "Cache-Tag" - stalePrefix = "STALE_" + stalePrefix = "STALE_" + surrogatePrefix = "SURROGATE_" ) +var storageToInfiniteTTLMap = map[string]time.Duration{ + "CACHE": 365 * 24 * time.Hour, +} + func (s *baseStorage) ParseHeaders(value string) []string { return regexp.MustCompile(s.parent.getHeaderSeparator()+" *").Split(value, -1) } @@ -73,6 +80,7 @@ type baseStorage struct { dynamic bool keepStale bool mu *sync.Mutex + duration time.Duration } func (s *baseStorage) init(config configurationtypes.AbstractConfigurationInterface) { @@ -109,17 +117,16 @@ func (s *baseStorage) init(config configurationtypes.AbstractConfigurationInterf s.dynamic = config.GetDefaultCache().GetCDN().Dynamic s.keysRegexp = keysRegexp s.mu = &sync.Mutex{} + s.duration = storageToInfiniteTTLMap[s.Storage.Name()] } func (s *baseStorage) storeTag(tag string, cacheKey string, re *regexp.Regexp) { defer s.mu.Unlock() s.mu.Lock() - currentValue := string(s.Storage.Get(tag)) - if s.dynamic { - if !re.MatchString(currentValue) { - fmt.Printf("Store the tag %s", tag) - _ = s.Storage.Set("SURROGATE_"+tag, []byte(currentValue+souinStorageSeparator+cacheKey), configurationtypes.URL{}, -1) - } + currentValue := string(s.Storage.Get(surrogatePrefix + tag)) + if !re.MatchString(currentValue) { + fmt.Printf("Store the tag %s", tag) + _ = s.Storage.Set(surrogatePrefix+tag, []byte(currentValue+souinStorageSeparator+cacheKey), configurationtypes.URL{}, -1) } } @@ -172,11 +179,11 @@ func (s *baseStorage) getSurrogateKey(header http.Header) string { func (s *baseStorage) purgeTag(tag string) []string { toInvalidate := string(s.Storage.Get(tag)) fmt.Printf("Purge the tag %s", tag) - s.Storage.Delete("SURROGATE_" + tag) + s.Storage.Delete(surrogatePrefix + tag) if !s.keepStale { toInvalidate = toInvalidate + "," + string(s.Storage.Get(stalePrefix+tag)) fmt.Printf("Purge the tag %s", stalePrefix+tag) - s.Storage.Delete("SURROGATE_" + stalePrefix + tag) + s.Storage.Delete(surrogatePrefix + stalePrefix + tag) } return strings.Split(toInvalidate, souinStorageSeparator) } @@ -240,12 +247,12 @@ func (s *baseStorage) Invalidate(method string, headers http.Header) { // List returns the stored keys associated to resources func (s *baseStorage) List() map[string]string { - return s.Storage.MapKeys("SURROGATE_") + return s.Storage.MapKeys(surrogatePrefix) } // Destruct method will shutdown properly the provider func (s *baseStorage) Destruct() error { - s.Storage.DeleteMany("SURROGATE_.*") + s.Storage.DeleteMany(surrogatePrefix + ".*") return nil } diff --git a/plugins/traefik/vendor/github.com/darkweak/souin/api/souin.go b/plugins/traefik/vendor/github.com/darkweak/souin/api/souin.go index 8f5305cb9..cb6ae7f82 100644 --- a/plugins/traefik/vendor/github.com/darkweak/souin/api/souin.go +++ b/plugins/traefik/vendor/github.com/darkweak/souin/api/souin.go @@ -117,6 +117,7 @@ func (s *SouinAPI) HandleRequest(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: if regexp.MustCompile(s.GetBasePath()+"/surrogate_keys").FindString(r.RequestURI) != "" { + fmt.Printf("r.RequestURI => %#v\n", s.surrogateStorage.List()) res, _ = json.Marshal(s.surrogateStorage.List()) } else if compile { search := regexp.MustCompile(s.GetBasePath()+"/(.+)").FindAllStringSubmatch(r.RequestURI, -1)[0][1] diff --git a/plugins/traefik/vendor/github.com/darkweak/souin/pkg/api/souin.go b/plugins/traefik/vendor/github.com/darkweak/souin/pkg/api/souin.go index 8f5305cb9..cb6ae7f82 100644 --- a/plugins/traefik/vendor/github.com/darkweak/souin/pkg/api/souin.go +++ b/plugins/traefik/vendor/github.com/darkweak/souin/pkg/api/souin.go @@ -117,6 +117,7 @@ func (s *SouinAPI) HandleRequest(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: if regexp.MustCompile(s.GetBasePath()+"/surrogate_keys").FindString(r.RequestURI) != "" { + fmt.Printf("r.RequestURI => %#v\n", s.surrogateStorage.List()) res, _ = json.Marshal(s.surrogateStorage.List()) } else if compile { search := regexp.MustCompile(s.GetBasePath()+"/(.+)").FindAllStringSubmatch(r.RequestURI, -1)[0][1] diff --git a/plugins/traefik/vendor/github.com/darkweak/souin/pkg/storage/cacheProvider.go b/plugins/traefik/vendor/github.com/darkweak/souin/pkg/storage/cacheProvider.go index 6cf442da9..ab5d9fb8a 100644 --- a/plugins/traefik/vendor/github.com/darkweak/souin/pkg/storage/cacheProvider.go +++ b/plugins/traefik/vendor/github.com/darkweak/souin/pkg/storage/cacheProvider.go @@ -20,10 +20,17 @@ type Cache struct { stale time.Duration } +var sharedCache *Cache + // CacheConnectionFactory function create new Cache instance func CacheConnectionFactory(c t.AbstractConfigurationInterface) (types.Storer, error) { provider := cache.New(1 * time.Second) - return &Cache{Cache: provider, stale: c.GetDefaultCache().GetStale()}, nil + + if sharedCache == nil { + sharedCache = &Cache{Cache: provider, stale: c.GetDefaultCache().GetStale()} + } + + return sharedCache, nil } // Name returns the storer name @@ -44,10 +51,12 @@ func (provider *Cache) ListKeys() []string { // MapKeys method returns the map of existing keys func (provider *Cache) MapKeys(prefix string) map[string]string { - var keys map[string]string + keys := map[string]string{} provider.Cache.Range(func(key, value interface{}) bool { - k, _ := strings.CutPrefix(key.(string), prefix) - keys[k] = value.(string) + if strings.HasPrefix(key.(string), prefix) { + k, _ := strings.CutPrefix(key.(string), prefix) + keys[k] = string(value.([]byte)) + } return true }) diff --git a/plugins/traefik/vendor/github.com/darkweak/souin/pkg/surrogate/providers/common.go b/plugins/traefik/vendor/github.com/darkweak/souin/pkg/surrogate/providers/common.go index 2402c62b4..a01dfd0b5 100644 --- a/plugins/traefik/vendor/github.com/darkweak/souin/pkg/surrogate/providers/common.go +++ b/plugins/traefik/vendor/github.com/darkweak/souin/pkg/surrogate/providers/common.go @@ -7,6 +7,7 @@ import ( "regexp" "strings" "sync" + "time" "github.com/darkweak/souin/configurationtypes" "github.com/darkweak/souin/pkg/storage" @@ -15,6 +16,7 @@ import ( const ( cdnCacheControl = "CDN-Cache-Control" + cacheGroupKey = "Cache-Groups" surrogateKey = "Surrogate-Key" surrogateControl = "Surrogate-Control" cacheControl = "Cache-Control" @@ -26,9 +28,14 @@ const ( cacheTags = "Cache-Tags" cacheTag = "Cache-Tag" - stalePrefix = "STALE_" + stalePrefix = "STALE_" + surrogatePrefix = "SURROGATE_" ) +var storageToInfiniteTTLMap = map[string]time.Duration{ + "CACHE": 365 * 24 * time.Hour, +} + func (s *baseStorage) ParseHeaders(value string) []string { return regexp.MustCompile(s.parent.getHeaderSeparator()+" *").Split(value, -1) } @@ -73,6 +80,7 @@ type baseStorage struct { dynamic bool keepStale bool mu *sync.Mutex + duration time.Duration } func (s *baseStorage) init(config configurationtypes.AbstractConfigurationInterface) { @@ -109,17 +117,16 @@ func (s *baseStorage) init(config configurationtypes.AbstractConfigurationInterf s.dynamic = config.GetDefaultCache().GetCDN().Dynamic s.keysRegexp = keysRegexp s.mu = &sync.Mutex{} + s.duration = storageToInfiniteTTLMap[s.Storage.Name()] } func (s *baseStorage) storeTag(tag string, cacheKey string, re *regexp.Regexp) { defer s.mu.Unlock() s.mu.Lock() - currentValue := string(s.Storage.Get(tag)) - if s.dynamic { - if !re.MatchString(currentValue) { - fmt.Printf("Store the tag %s", tag) - _ = s.Storage.Set("SURROGATE_"+tag, []byte(currentValue+souinStorageSeparator+cacheKey), configurationtypes.URL{}, -1) - } + currentValue := string(s.Storage.Get(surrogatePrefix + tag)) + if !re.MatchString(currentValue) { + fmt.Printf("Store the tag %s", tag) + _ = s.Storage.Set(surrogatePrefix+tag, []byte(currentValue+souinStorageSeparator+cacheKey), configurationtypes.URL{}, -1) } } @@ -171,11 +178,11 @@ func (s *baseStorage) getSurrogateKey(header http.Header) string { func (s *baseStorage) purgeTag(tag string) []string { toInvalidate := string(s.Storage.Get(tag)) fmt.Printf("Purge the tag %s", tag) - s.Storage.Delete("SURROGATE_" + tag) + s.Storage.Delete(surrogatePrefix + tag) if !s.keepStale { toInvalidate = toInvalidate + "," + string(s.Storage.Get(stalePrefix+tag)) fmt.Printf("Purge the tag %s", stalePrefix+tag) - s.Storage.Delete("SURROGATE_" + stalePrefix + tag) + s.Storage.Delete(surrogatePrefix + stalePrefix + tag) } return strings.Split(toInvalidate, souinStorageSeparator) } @@ -239,12 +246,12 @@ func (s *baseStorage) Invalidate(method string, headers http.Header) { // List returns the stored keys associated to resources func (s *baseStorage) List() map[string]string { - return s.Storage.MapKeys("SURROGATE_") + return s.Storage.MapKeys(surrogatePrefix) } // Destruct method will shutdown properly the provider func (s *baseStorage) Destruct() error { - s.Storage.DeleteMany("SURROGATE_.*") + s.Storage.DeleteMany(surrogatePrefix + ".*") return nil }