diff --git a/.github/workflows/plugins.yml b/.github/workflows/plugins.yml index 78e64b887..f00e24e9b 100644 --- a/.github/workflows/plugins.yml +++ b/.github/workflows/plugins.yml @@ -36,7 +36,7 @@ jobs: name: Install Go uses: actions/setup-go@v3 with: - go-version: '1.20' + go-version: '1.21' - name: Checkout code uses: actions/checkout@v3 @@ -81,7 +81,7 @@ jobs: with: CAPITALIZED_NAME: Beego LOWER_NAME: beego - GO_VERSION: '1.20' + GO_VERSION: '1.21' build-chi-validator: name: Check that Souin build as middleware uses: ./.github/workflows/plugin_template.yml @@ -89,7 +89,7 @@ jobs: with: CAPITALIZED_NAME: Chi LOWER_NAME: chi - GO_VERSION: '1.20' + GO_VERSION: '1.21' build-dotweb-validator: name: Check that Souin build as middleware uses: ./.github/workflows/plugin_template.yml @@ -97,7 +97,7 @@ jobs: with: CAPITALIZED_NAME: Dotweb LOWER_NAME: dotweb - GO_VERSION: '1.20' + GO_VERSION: '1.21' build-echo-validator: name: Check that Souin build as middleware uses: ./.github/workflows/plugin_template.yml @@ -105,7 +105,7 @@ jobs: with: CAPITALIZED_NAME: Echo LOWER_NAME: echo - GO_VERSION: '1.20' + GO_VERSION: '1.21' build-fiber-validator: name: Check that Souin build as middleware uses: ./.github/workflows/plugin_template.yml @@ -113,7 +113,7 @@ jobs: with: CAPITALIZED_NAME: Fiber LOWER_NAME: fiber - GO_VERSION: '1.20' + GO_VERSION: '1.21' build-gin-validator: name: Check that Souin build as middleware uses: ./.github/workflows/plugin_template.yml @@ -121,7 +121,7 @@ jobs: with: CAPITALIZED_NAME: Gin LOWER_NAME: gin - GO_VERSION: '1.20' + GO_VERSION: '1.21' build-goa-validator: name: Check that Souin build as middleware uses: ./.github/workflows/plugin_template.yml @@ -129,7 +129,7 @@ jobs: with: CAPITALIZED_NAME: Goa LOWER_NAME: goa - GO_VERSION: '1.20' + GO_VERSION: '1.21' build-go-zero-validator: name: Check that Souin build as middleware uses: ./.github/workflows/plugin_template.yml @@ -137,7 +137,7 @@ jobs: with: CAPITALIZED_NAME: Go-zero LOWER_NAME: go-zero - GO_VERSION: '1.20' + GO_VERSION: '1.21' build-hertz-validator: name: Check that Souin build as middleware uses: ./.github/workflows/plugin_template.yml @@ -145,7 +145,7 @@ jobs: with: CAPITALIZED_NAME: Hertz LOWER_NAME: hertz - GO_VERSION: '1.20' + GO_VERSION: '1.21' build-kratos-validator: name: Check that Souin build as middleware uses: ./.github/workflows/plugin_template.yml @@ -153,7 +153,7 @@ jobs: with: CAPITALIZED_NAME: Kratos LOWER_NAME: kratos - GO_VERSION: '1.20' + GO_VERSION: '1.21' build-roadrunner-validator: name: Check that Souin build as middleware uses: ./.github/workflows/plugin_template.yml @@ -161,7 +161,7 @@ jobs: with: CAPITALIZED_NAME: Roadrunner LOWER_NAME: roadrunner - GO_VERSION: '1.20' + GO_VERSION: '1.21' build-skipper-validator: name: Check that Souin build as middleware uses: ./.github/workflows/plugin_template.yml @@ -169,7 +169,7 @@ jobs: with: CAPITALIZED_NAME: Skipper LOWER_NAME: skipper - GO_VERSION: '1.20' + GO_VERSION: '1.21' build-souin-validator: name: Check that Souin build as middleware uses: ./.github/workflows/plugin_template.yml @@ -177,7 +177,7 @@ jobs: with: CAPITALIZED_NAME: Souin LOWER_NAME: souin - GO_VERSION: '1.20' + GO_VERSION: '1.21' build-traefik-validator: name: Check that Souin build as middleware uses: ./.github/workflows/plugin_template.yml @@ -185,7 +185,7 @@ jobs: with: CAPITALIZED_NAME: Traefik LOWER_NAME: traefik - GO_VERSION: '1.20' + GO_VERSION: '1.21' build-tyk-validator: name: Check that Souin build as middleware uses: ./.github/workflows/plugin_template.yml @@ -193,7 +193,7 @@ jobs: with: CAPITALIZED_NAME: Tyk LOWER_NAME: tyk - GO_VERSION: '1.20' + GO_VERSION: '1.21' build-webgo-validator: name: Check that Souin build as middleware uses: ./.github/workflows/plugin_template.yml @@ -201,4 +201,4 @@ jobs: with: CAPITALIZED_NAME: Webgo LOWER_NAME: webgo - GO_VERSION: '1.20' + GO_VERSION: '1.21' diff --git a/.github/workflows/workflow_plugins_generator.sh b/.github/workflows/workflow_plugins_generator.sh index 21f3ee836..2536ac9be 100644 --- a/.github/workflows/workflow_plugins_generator.sh +++ b/.github/workflows/workflow_plugins_generator.sh @@ -1,7 +1,7 @@ #!/bin/bash plugins=("beego" "chi" "dotweb" "echo" "fiber" "gin" "goa" "go-zero" "hertz" "kratos" "roadrunner" "skipper" "souin" "traefik" "tyk" "webgo") -go_version=1.20 +go_version=1.21 IFS= read -r -d '' tpl < 0 { + status += strings.Join(fails, "") + } + + // if s.Storer.Set(cachedKey, response, currentMatchedURL, ma) == nil { + // s.Configuration.GetLogger().Sugar().Debugf("Store the cache key %s into the surrogate keys from the following headers %v", cachedKey, res) + // go func(rs http.Response, key string) { + // _ = s.SurrogateKeyStorer.Store(&rs, key) + // }(res, cachedKey) + // status += "; stored" + // } else { + // status += "; detail=STORAGE-INSERTION-ERROR" + // } } } else { status += "; detail=NO-STORE-DIRECTIVE" @@ -394,7 +427,14 @@ func (s *SouinBaseHandler) ServeHTTP(rw http.ResponseWriter, rq *http.Request, n s.Configuration.GetLogger().Sugar().Debugf("Request cache-control %+v", requestCc) if modeContext.Bypass_request || !requestCc.NoCache { validator := rfc.ParseRequest(rq) - response := s.Storer.Prefix(cachedKey, rq, validator) + var response *http.Response + for _, currentStorer := range s.Storers { + response = currentStorer.Prefix(cachedKey, rq, validator) + if response != nil { + s.Configuration.GetLogger().Sugar().Debugf("Found response in the %s storage", currentStorer.Name()) + break + } + } if response != nil && (!modeContext.Strict || rfc.ValidateCacheControl(response, requestCc)) { if validator.ResponseETag != "" && validator.Matched { @@ -425,7 +465,12 @@ func (s *SouinBaseHandler) ServeHTTP(rw http.ResponseWriter, rq *http.Request, n return err } } else if response == nil && !requestCc.OnlyIfCached && (requestCc.MaxStaleSet || requestCc.MaxStale > -1) { - response = s.Storer.Prefix(storage.StalePrefix+cachedKey, rq, validator) + for _, currentStorer := range s.Storers { + response := currentStorer.Prefix(storage.StalePrefix+cachedKey, rq, validator) + if response != nil { + break + } + } if nil != response && (!modeContext.Strict || rfc.ValidateCacheControl(response, requestCc)) { addTime, _ := time.ParseDuration(response.Header.Get(rfc.StoredTTLHeader)) rfc.SetCacheStatusHeader(response) diff --git a/pkg/storage/badgerProvider.go b/pkg/storage/badgerProvider.go index e1812de4b..077fb8b00 100644 --- a/pkg/storage/badgerProvider.go +++ b/pkg/storage/badgerProvider.go @@ -86,6 +86,11 @@ func BadgerConnectionFactory(c t.AbstractConfigurationInterface) (Storer, error) return i, nil } +// Name returns the storer name +func (provider *Badger) Name() string { + return "BADGER" +} + // ListKeys method returns the list of existing keys func (provider *Badger) ListKeys() []string { keys := []string{} diff --git a/pkg/storage/embeddedOlricProvider.go b/pkg/storage/embeddedOlricProvider.go index aae5831af..aa430f891 100644 --- a/pkg/storage/embeddedOlricProvider.go +++ b/pkg/storage/embeddedOlricProvider.go @@ -108,6 +108,11 @@ func EmbeddedOlricConnectionFactory(configuration t.AbstractConfigurationInterfa }, e } +// Name returns the storer name +func (provider *EmbeddedOlric) Name() string { + return "EMBEDDED_OLRIC" +} + // ListKeys method returns the list of existing keys func (provider *EmbeddedOlric) ListKeys() []string { diff --git a/pkg/storage/etcdProvider.go b/pkg/storage/etcdProvider.go index 6e09d5cf6..d08dfebfa 100644 --- a/pkg/storage/etcdProvider.go +++ b/pkg/storage/etcdProvider.go @@ -61,6 +61,11 @@ func EtcdConnectionFactory(c t.AbstractConfigurationInterface) (Storer, error) { }, nil } +// Name returns the storer name +func (provider *Etcd) Name() string { + return "ETCD" +} + // ListKeys method returns the list of existing keys func (provider *Etcd) ListKeys() []string { if provider.reconnecting { diff --git a/pkg/storage/nutsProvider.go b/pkg/storage/nutsProvider.go index 31349fc17..522adc053 100644 --- a/pkg/storage/nutsProvider.go +++ b/pkg/storage/nutsProvider.go @@ -106,6 +106,11 @@ func NutsConnectionFactory(c t.AbstractConfigurationInterface) (Storer, error) { }, nil } +// Name returns the storer name +func (provider *Nuts) Name() string { + return "NUTS" +} + // ListKeys method returns the list of existing keys func (provider *Nuts) ListKeys() []string { keys := []string{} diff --git a/pkg/storage/olricProvider.go b/pkg/storage/olricProvider.go index 14d313a8b..c9840417e 100644 --- a/pkg/storage/olricProvider.go +++ b/pkg/storage/olricProvider.go @@ -45,6 +45,11 @@ func OlricConnectionFactory(configuration t.AbstractConfigurationInterface) (Sto }, nil } +// Name returns the storer name +func (provider *Olric) Name() string { + return "OLRIC" +} + // ListKeys method returns the list of existing keys func (provider *Olric) ListKeys() []string { if provider.reconnecting { diff --git a/pkg/storage/redisProvider.go b/pkg/storage/redisProvider.go index 57863d66a..48891d9d0 100644 --- a/pkg/storage/redisProvider.go +++ b/pkg/storage/redisProvider.go @@ -57,6 +57,11 @@ func RedisConnectionFactory(c t.AbstractConfigurationInterface) (Storer, error) }, nil } +// Name returns the storer name +func (provider *Redis) Name() string { + return "REDIS" +} + // ListKeys method returns the list of existing keys func (provider *Redis) ListKeys() []string { if provider.reconnecting { diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index 484def9bd..13e696e0a 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -25,6 +25,7 @@ type Storer interface { Delete(key string) DeleteMany(key string) Init() error + Name() string Reset() error } @@ -67,6 +68,55 @@ func NewStorage(configuration configurationtypes.AbstractConfigurationInterface) return nil, errors.New("Storer with name" + storerName + " not found") } +func uniqueStorers(storers []string) []string { + storerPresent := make(map[string]bool) + s := []string{} + + for _, current := range storers { + if _, found := storerPresent[current]; !found { + storerPresent[current] = true + s = append(s, current) + } + } + + return s +} + +func NewStorages(configuration configurationtypes.AbstractConfigurationInterface) ([]Storer, error) { + storers := []Storer{} + for _, storerName := range uniqueStorers(configuration.GetDefaultCache().GetStorers()) { + if newStorage, found := storageMap[storerName]; found { + instance, err := newStorage(configuration) + if err != nil { + configuration.GetLogger().Sugar().Debugf("Cannot load configuration for the chianed provider %s: %+v", storerName, err) + continue + } + + configuration.GetLogger().Sugar().Debugf("Append storer %s to the chain", storerName) + storers = append(storers, instance) + } else { + configuration.GetLogger().Sugar().Debugf("Storer with name %s not found", storerName) + } + } + + if len(storers) == 0 { + configuration.GetLogger().Debug("Not able to create storers chain from the storers slice, fallback to the default storer creation") + instance, err := NewStorage(configuration) + if err != nil || instance == nil { + return nil, err + } + + storers = append(storers, instance) + } + + names := []string{} + for _, s := range storers { + names = append(names, s.Name()) + } + configuration.GetLogger().Sugar().Debugf("Run with %d chained providers with the given order %s", len(storers), strings.Join(names, ", ")) + return storers, nil +} + func varyVoter(baseKey string, req *http.Request, currentKey string) bool { if currentKey == baseKey { return true diff --git a/plugins/beego/souin_test.go b/plugins/beego/souin_test.go index 5c6bdac89..31429961f 100644 --- a/plugins/beego/souin_test.go +++ b/plugins/beego/souin_test.go @@ -17,7 +17,7 @@ import ( func Test_NewHTTPCache(t *testing.T) { s := NewHTTPCache(DevDefaultConfiguration) - if s.SouinBaseHandler.Storer == nil { + if s.SouinBaseHandler.Storers == nil || len(s.SouinBaseHandler.Storers) != 1 { t.Error("The storer must be set.") } c := middleware.BaseConfiguration{} diff --git a/plugins/caddy/configuration.go b/plugins/caddy/configuration.go index 93c0f066f..92371ee39 100644 --- a/plugins/caddy/configuration.go +++ b/plugins/caddy/configuration.go @@ -40,6 +40,8 @@ type DefaultCache struct { Nuts configurationtypes.CacheProvider `json:"nuts"` // Regex to exclude cache. Regex configurationtypes.Regex `json:"regex"` + // Storage providers chaining and order. + Storers []string `json:"storers"` // Time before cache or backend access timeout. Timeout configurationtypes.Timeout `json:"timeout"` // Time to live. @@ -113,6 +115,11 @@ func (d *DefaultCache) GetRegex() configurationtypes.Regex { return d.Regex } +// GetStorers returns the chianed storers +func (d *DefaultCache) GetStorers() []string { + return d.Storers +} + // GetTimeout returns the backend and cache timeouts func (d *DefaultCache) GetTimeout() configurationtypes.Timeout { return d.Timeout @@ -513,6 +520,9 @@ func parseConfiguration(cfg *Configuration, h *caddyfile.Dispenser, isBlocking b if err == nil { cfg.DefaultCache.Stale.Duration = stale } + case "storers": + args := h.RemainingArgs() + cfg.DefaultCache.Storers = args case "timeout": timeout := configurationtypes.Timeout{} for nesting := h.Nesting(); h.NextBlock(nesting); { diff --git a/plugins/caddy/httpcache.go b/plugins/caddy/httpcache.go index c5db767d7..80d59e8b0 100644 --- a/plugins/caddy/httpcache.go +++ b/plugins/caddy/httpcache.go @@ -63,6 +63,8 @@ type SouinCaddyMiddleware struct { TTL configurationtypes.Duration `json:"ttl,omitempty"` // Time to live for a stale key, using time.duration. Stale configurationtypes.Duration `json:"stale,omitempty"` + // Storage providers chaining and order. + Storers []string `json:"storers,omitempty"` // The default Cache-Control header value if none set by the upstream server. DefaultCacheControl string `json:"default_cache_control,omitempty"` // The cache name to use in the Cache-Status response header. @@ -102,6 +104,7 @@ func (s *SouinCaddyMiddleware) configurationPropertyMapper() error { Timeout: s.Timeout, TTL: s.TTL, Stale: s.Stale, + Storers: s.Storers, } if s.Configuration == nil { s.Configuration = &Configuration{ @@ -173,6 +176,9 @@ func (s *SouinCaddyMiddleware) FromApp(app *SouinApp) error { if dc.Stale.Duration == 0 { s.Configuration.DefaultCache.Stale = appDc.Stale } + if len(dc.Storers) == 0 { + s.Configuration.DefaultCache.Storers = appDc.Storers + } if dc.Timeout.Backend.Duration == 0 { s.Configuration.DefaultCache.Timeout.Backend = appDc.Timeout.Backend } diff --git a/plugins/chi/souin_test.go b/plugins/chi/souin_test.go index 30caebb01..ec5f11ddc 100644 --- a/plugins/chi/souin_test.go +++ b/plugins/chi/souin_test.go @@ -14,7 +14,7 @@ import ( func Test_NewHTTPCache(t *testing.T) { s := NewHTTPCache(DevDefaultConfiguration) - if s.SouinBaseHandler.Storer == nil { + if s.SouinBaseHandler.Storers == nil || len(s.SouinBaseHandler.Storers) != 1 { t.Error("The storer must be set.") } c := middleware.BaseConfiguration{} diff --git a/plugins/dotweb/souin_test.go b/plugins/dotweb/souin_test.go index 0bb20c327..1fc07a724 100644 --- a/plugins/dotweb/souin_test.go +++ b/plugins/dotweb/souin_test.go @@ -14,7 +14,7 @@ import ( func Test_NewHTTPCache(t *testing.T) { s := NewHTTPCache(DevDefaultConfiguration) - if s.SouinBaseHandler.Storer == nil { + if s.SouinBaseHandler.Storers == nil || len(s.SouinBaseHandler.Storers) != 1 { t.Error("The storer must be set.") } c := middleware.BaseConfiguration{} diff --git a/plugins/echo/souin_test.go b/plugins/echo/souin_test.go index 6df253ede..8506489ac 100644 --- a/plugins/echo/souin_test.go +++ b/plugins/echo/souin_test.go @@ -15,7 +15,7 @@ import ( func Test_New(t *testing.T) { s := NewMiddleware(DevDefaultConfiguration) - if s.SouinBaseHandler.Storer == nil { + if s.SouinBaseHandler.Storers == nil || len(s.SouinBaseHandler.Storers) != 1 { t.Error("The storer must be set.") } c := middleware.BaseConfiguration{} diff --git a/plugins/fiber/souin_test.go b/plugins/fiber/souin_test.go index 894b774df..cbf0bacf6 100644 --- a/plugins/fiber/souin_test.go +++ b/plugins/fiber/souin_test.go @@ -14,7 +14,7 @@ import ( func Test_NewHTTPCache(t *testing.T) { s := NewHTTPCache(DevDefaultConfiguration) - if s.SouinBaseHandler.Storer == nil { + if s.SouinBaseHandler.Storers == nil || len(s.SouinBaseHandler.Storers) != 1 { t.Error("The storer must be set.") } c := middleware.BaseConfiguration{} diff --git a/plugins/gin/souin_test.go b/plugins/gin/souin_test.go index a293a1758..6343f3457 100644 --- a/plugins/gin/souin_test.go +++ b/plugins/gin/souin_test.go @@ -11,7 +11,7 @@ import ( func Test_New(t *testing.T) { s := New(DevDefaultConfiguration) - if s.SouinBaseHandler.Storer == nil { + if s.SouinBaseHandler.Storers == nil || len(s.SouinBaseHandler.Storers) != 1 { t.Error("The storer must be set.") } c := middleware.BaseConfiguration{} diff --git a/plugins/go-zero/souin_test.go b/plugins/go-zero/souin_test.go index f50a6cf06..7e28e4ae6 100644 --- a/plugins/go-zero/souin_test.go +++ b/plugins/go-zero/souin_test.go @@ -13,7 +13,7 @@ import ( func Test_NewHTTPCache(t *testing.T) { s := NewHTTPCache(DevDefaultConfiguration) - if s.SouinBaseHandler.Storer == nil { + if s.SouinBaseHandler.Storers == nil || len(s.SouinBaseHandler.Storers) != 1 { t.Error("The storer must be set.") } c := middleware.BaseConfiguration{} diff --git a/plugins/goa/souin_test.go b/plugins/goa/souin_test.go index d1eefbd08..9100f26ea 100644 --- a/plugins/goa/souin_test.go +++ b/plugins/goa/souin_test.go @@ -16,7 +16,7 @@ func Test_NewHTTPCache(t *testing.T) { s := &SouinGoaMiddleware{ SouinBaseHandler: middleware.NewHTTPCacheHandler(&DevDefaultConfiguration), } - if s.SouinBaseHandler.Storer == nil { + if s.SouinBaseHandler.Storers == nil || len(s.SouinBaseHandler.Storers) != 1 { t.Error("The storer must be set.") } defer func() { diff --git a/plugins/goyave/souin_test.go b/plugins/goyave/souin_test.go index 5f57ba4cc..3787f364c 100644 --- a/plugins/goyave/souin_test.go +++ b/plugins/goyave/souin_test.go @@ -15,7 +15,7 @@ import ( func Test_NewHTTPCache(t *testing.T) { s := NewHTTPCache(DevDefaultConfiguration) - if s.SouinBaseHandler.Storer == nil { + if s.SouinBaseHandler.Storers == nil || len(s.SouinBaseHandler.Storers) != 1 { t.Error("The storer must be set.") } c := middleware.BaseConfiguration{} diff --git a/plugins/kratos/configuration.go b/plugins/kratos/configuration.go index bc6f40aec..ea46eca6e 100644 --- a/plugins/kratos/configuration.go +++ b/plugins/kratos/configuration.go @@ -302,6 +302,13 @@ func parseDefaultCache(dcConfiguration map[string]config.Value) *configurationty if err == nil { dc.Stale = configurationtypes.Duration{Duration: stale} } + case "storers": + storers, _ := defaultCacheV.Slice() + dc.Storers = make([]string, 0) + for _, storer := range storers { + h, _ := storer.String() + dc.Storers = append(dc.Storers, h) + } case "default_cache_control": dc.DefaultCacheControl, _ = defaultCacheV.String() } diff --git a/plugins/roadrunner/go.mod b/plugins/roadrunner/go.mod index e79b07f5a..5c28d3b89 100644 --- a/plugins/roadrunner/go.mod +++ b/plugins/roadrunner/go.mod @@ -1,6 +1,6 @@ module github.com/darkweak/souin/plugins/roadrunner -go 1.20 +go 1.21 require ( github.com/darkweak/souin v1.6.40 diff --git a/plugins/roadrunner/go.sum b/plugins/roadrunner/go.sum index ec667d1ed..5c32ad61c 100644 --- a/plugins/roadrunner/go.sum +++ b/plugins/roadrunner/go.sum @@ -541,6 +541,7 @@ github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -554,8 +555,10 @@ github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bsm/ginkgo/v2 v2.5.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w= github.com/bsm/ginkgo/v2 v2.9.5 h1:rtVBYPs3+TC5iLUVOis1B9tjLTup7Cj5IfzosKtvTJ0= +github.com/bsm/ginkgo/v2 v2.9.5/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.20.0/go.mod h1:JifAceMQ4crZIWYUKrlGcmbN3bqHogVTADMD2ATsbwk= github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= +github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/buraksezer/consistent v0.10.0 h1:hqBgz1PvNLC5rkWcEBVAL9dFMBWz6I0VgUCW25rrZlU= github.com/buraksezer/consistent v0.10.0/go.mod h1:6BrVajWq7wbKZlTOUPs/XVfR8c0maujuPowduSpZqmw= github.com/buraksezer/olric v0.5.4 h1:LDgLIfVoyol4qzdNirrrDUKqzFw0yDsa7ukvLrpP4cU= @@ -851,6 +854,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -969,6 +973,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= @@ -1057,6 +1062,7 @@ go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= diff --git a/plugins/souin/agnostic/configuration_parser.go b/plugins/souin/agnostic/configuration_parser.go index 454699898..149967cec 100644 --- a/plugins/souin/agnostic/configuration_parser.go +++ b/plugins/souin/agnostic/configuration_parser.go @@ -256,6 +256,18 @@ func parseDefaultCache(dcConfiguration map[string]interface{}) *configurationtyp if err == nil { dc.Stale = configurationtypes.Duration{Duration: ttl} } + case "storers": + if storers, ok := defaultCacheV.([]string); ok { + dc.Storers = storers + } else { + if storers, ok := defaultCacheV.([]string); ok { + dc.Storers = storers + } else { + for _, sv := range defaultCacheV.([]interface{}) { + dc.Storers = append(dc.Storers, sv.(string)) + } + } + } case "default_cache_control": dc.DefaultCacheControl, _ = defaultCacheV.(string) } diff --git a/plugins/traefik/main.go b/plugins/traefik/main.go index 8381fbbb2..d4aba10cb 100644 --- a/plugins/traefik/main.go +++ b/plugins/traefik/main.go @@ -198,6 +198,8 @@ func parseConfiguration(c map[string]interface{}) Configuration { if err == nil { dc.Stale = configurationtypes.Duration{Duration: stale} } + case "storers": + dc.Storers = parseStringSlice(defaultCacheV) case "default_cache_control": dc.DefaultCacheControl = defaultCacheV.(string) } diff --git a/plugins/traefik/vendor/github.com/darkweak/souin/configurationtypes/types.go b/plugins/traefik/vendor/github.com/darkweak/souin/configurationtypes/types.go index 53aac6bfe..609f14103 100644 --- a/plugins/traefik/vendor/github.com/darkweak/souin/configurationtypes/types.go +++ b/plugins/traefik/vendor/github.com/darkweak/souin/configurationtypes/types.go @@ -229,6 +229,7 @@ type DefaultCache struct { Port Port `json:"port" yaml:"port"` Regex Regex `json:"regex" yaml:"regex"` Stale Duration `json:"stale" yaml:"stale"` + Storers []string `json:"storers" yaml:"storers"` Timeout Timeout `json:"timeout" yaml:"timeout"` TTL Duration `json:"ttl" yaml:"ttl"` DefaultCacheControl string `json:"default_cache_control" yaml:"default_cache_control"` @@ -314,6 +315,11 @@ func (d *DefaultCache) GetStale() time.Duration { return d.Stale.Duration } +// GetStale returns the stale duration +func (d *DefaultCache) GetStorers() []string { + return d.Storers +} + // GetDefaultCacheControl returns the default Cache-Control response header value when empty func (d *DefaultCache) GetDefaultCacheControl() string { return d.DefaultCacheControl @@ -335,6 +341,7 @@ type DefaultCacheInterface interface { GetKey() Key GetRegex() Regex GetStale() time.Duration + GetStorers() []string GetTimeout() Timeout GetTTL() time.Duration GetDefaultCacheControl() string diff --git a/plugins/webgo/souin_test.go b/plugins/webgo/souin_test.go index 1120324df..db9164166 100644 --- a/plugins/webgo/souin_test.go +++ b/plugins/webgo/souin_test.go @@ -15,7 +15,7 @@ import ( func Test_NewHTTPCache(t *testing.T) { s := NewHTTPCache(DevDefaultConfiguration) - if s.SouinBaseHandler.Storer == nil { + if s.SouinBaseHandler.Storers == nil || len(s.SouinBaseHandler.Storers) != 1 { t.Error("The storer must be set.") } c := middleware.BaseConfiguration{}