diff --git a/README.md b/README.md index d28e45d66..73c5c8c1d 100644 --- a/README.md +++ b/README.md @@ -918,7 +918,7 @@ experimental: plugins: souin: moduleName: github.com/darkweak/souin - version: v1.6.21 + version: v1.6.22 ``` After that you can declare either the whole configuration at once in the middleware block or by service. See the examples below. ```yaml diff --git a/cache/providers/badgerProvider.go b/cache/providers/badgerProvider.go index 9d136edee..4064bee23 100644 --- a/cache/providers/badgerProvider.go +++ b/cache/providers/badgerProvider.go @@ -2,7 +2,6 @@ package providers import ( "encoding/json" - "fmt" "net/http" "regexp" "time" @@ -150,7 +149,7 @@ func (provider *Badger) Set(key string, value []byte, url t.URL, duration time.D }) if err != nil { - panic(fmt.Sprintf("Impossible to set value into Badger, %s", err)) + provider.logger.Sugar().Errorf("Impossible to set value into Badger, %v", err) } err = provider.DB.Update(func(txn *badger.Txn) error { @@ -158,7 +157,7 @@ func (provider *Badger) Set(key string, value []byte, url t.URL, duration time.D }) if err != nil { - panic(fmt.Sprintf("Impossible to set value into Badger, %s", err)) + provider.logger.Sugar().Errorf("Impossible to set value into Badger, %v", err) } } diff --git a/cache/providers/embeddedOlricProvider.go b/cache/providers/embeddedOlricProvider.go index b2683f4ac..cfb19a942 100644 --- a/cache/providers/embeddedOlricProvider.go +++ b/cache/providers/embeddedOlricProvider.go @@ -181,11 +181,11 @@ func (provider *EmbeddedOlric) Set(key string, value []byte, url t.URL, duration } if err := provider.dm.PutEx(key, value, duration); err != nil { - panic(err) + provider.logger.Sugar().Errorf("Impossible to set value into EmbeddedOlric, %v", err) } if err := provider.dm.PutEx(stalePrefix+key, value, provider.stale+duration); err != nil { - panic(err) + provider.logger.Sugar().Errorf("Impossible to set value into EmbeddedOlric, %v", err) } } @@ -194,7 +194,7 @@ func (provider *EmbeddedOlric) Delete(key string) { go func() { err := provider.dm.Delete(key) if err != nil { - panic(err) + provider.logger.Sugar().Errorf("Impossible to delete a value into EmbeddedOlric, %v", err) } }() } @@ -223,7 +223,7 @@ func (provider *EmbeddedOlric) DeleteMany(key string) { }) if err != nil { - panic(err) + provider.logger.Sugar().Errorf("Impossible to delete values into EmbeddedOlric, %v", err) } }() } diff --git a/cache/providers/etcdProvider.go b/cache/providers/etcdProvider.go index 308830f37..8f218a357 100644 --- a/cache/providers/etcdProvider.go +++ b/cache/providers/etcdProvider.go @@ -3,7 +3,6 @@ package providers import ( "context" "encoding/json" - "fmt" "net/http" "regexp" "time" @@ -136,7 +135,7 @@ func (provider *Etcd) Set(key string, value []byte, url t.URL, duration time.Dur go provider.Reconnect() return } - panic(fmt.Sprintf("Impossible to set value into Etcd, %s", err)) + provider.logger.Sugar().Errorf("Impossible to set value into Etcd, %v", err) } _, err = provider.Client.Put(provider.ctx, stalePrefix+key, string(value), clientv3.WithLease(rs.ID)) @@ -146,7 +145,7 @@ func (provider *Etcd) Set(key string, value []byte, url t.URL, duration time.Dur go provider.Reconnect() return } - panic(fmt.Sprintf("Impossible to set value into Etcd, %s", err)) + provider.logger.Sugar().Errorf("Impossible to set value into Etcd, %v", err) } } diff --git a/cache/providers/nutsProvider.go b/cache/providers/nutsProvider.go index 8cb76c7d6..e80b677f0 100644 --- a/cache/providers/nutsProvider.go +++ b/cache/providers/nutsProvider.go @@ -2,7 +2,6 @@ package providers import ( "encoding/json" - "fmt" "net/http" "strconv" "time" @@ -11,12 +10,14 @@ import ( t "github.com/darkweak/souin/configurationtypes" "github.com/imdario/mergo" "github.com/xujiajun/nutsdb" + "go.uber.org/zap" ) // Nuts provider type type Nuts struct { *nutsdb.DB - stale time.Duration + stale time.Duration + logger *zap.Logger } const ( @@ -96,7 +97,11 @@ func NutsConnectionFactory(c t.AbstractConfigurationInterface) (types.AbstractPr c.GetLogger().Sugar().Error("Impossible to open the Nuts DB.", e) } - return &Nuts{DB: db, stale: dc.GetStale()}, nil + return &Nuts{ + DB: db, + stale: dc.GetStale(), + logger: c.GetLogger(), + }, nil } // ListKeys method returns the list of existing keys @@ -165,7 +170,7 @@ func (provider *Nuts) Set(key string, value []byte, url t.URL, duration time.Dur }) if err != nil { - panic(fmt.Sprintf("Impossible to set value into Nuts, %s", err)) + provider.logger.Sugar().Errorf("Impossible to set value into Nuts, %v", err) } err = provider.DB.Update(func(tx *nutsdb.Tx) error { @@ -173,7 +178,7 @@ func (provider *Nuts) Set(key string, value []byte, url t.URL, duration time.Dur }) if err != nil { - panic(fmt.Sprintf("Impossible to set value into Nuts, %s", err)) + provider.logger.Sugar().Errorf("Impossible to set value into Nuts, %v", err) } } diff --git a/cache/providers/olricProvider.go b/cache/providers/olricProvider.go index 9e1d975f1..84dc0700f 100644 --- a/cache/providers/olricProvider.go +++ b/cache/providers/olricProvider.go @@ -36,7 +36,7 @@ func OlricConnectionFactory(configuration t.AbstractConfigurationInterface) (typ } c, err := client.New(&config) if err != nil { - panic(err) + configuration.GetLogger().Sugar().Errorf("Impossible to connect to Olric, %v", err) } return &Olric{ @@ -152,7 +152,7 @@ func (provider *Olric) Set(key string, value []byte, url t.URL, duration time.Du go provider.Reconnect() return } - panic(err) + provider.logger.Sugar().Errorf("Impossible to set value into Olric, %v", err) } if err := provider.dm.PutEx(stalePrefix+key, value, provider.stale+duration); err != nil { @@ -160,7 +160,7 @@ func (provider *Olric) Set(key string, value []byte, url t.URL, duration time.Du go provider.Reconnect() return } - panic(err) + provider.logger.Sugar().Errorf("Impossible to set value into Olric, %v", err) } } @@ -173,7 +173,7 @@ func (provider *Olric) Delete(key string) { go func() { err := provider.dm.Delete(key) if err != nil { - panic(err) + provider.logger.Sugar().Errorf("Impossible to delete value into Olric, %v", err) } }() } @@ -206,7 +206,7 @@ func (provider *Olric) DeleteMany(key string) { }) if err != nil { - panic(err) + provider.logger.Sugar().Errorf("Impossible to delete values into Olric, %v", err) } }() } diff --git a/cache/providers/redisProvider.go b/cache/providers/redisProvider.go index 081629896..9eeaa187f 100644 --- a/cache/providers/redisProvider.go +++ b/cache/providers/redisProvider.go @@ -3,7 +3,6 @@ package providers import ( "context" "encoding/json" - "fmt" "net/http" "regexp" "time" @@ -149,7 +148,7 @@ func (provider *Redis) Set(key string, value []byte, url t.URL, duration time.Du go provider.Reconnect() return } - panic(fmt.Sprintf("Impossible to set value into Redis, %s", err)) + provider.logger.Sugar().Errorf("Impossible to set value into Redis, %v", err) } if err := provider.Client.Set(provider.ctx, stalePrefix+key, value, duration+provider.stale).Err(); err != nil { @@ -157,7 +156,7 @@ func (provider *Redis) Set(key string, value []byte, url t.URL, duration time.Du go provider.Reconnect() return } - panic(fmt.Sprintf("Impossible to set value into Redis, %s", err)) + provider.logger.Sugar().Errorf("Impossible to set value into Redis, %v", err) } } diff --git a/context/types.go b/context/types.go index 241896ff5..7135b985a 100644 --- a/context/types.go +++ b/context/types.go @@ -23,6 +23,8 @@ type ( } ) +const CacheControlCtx ctxKey = "CACHE-CONTROL-CTX" + func GetContext() *Context { return &Context{ CacheName: &cacheContext{}, diff --git a/plugins/base.go b/plugins/base.go index 426c63a86..60ef22850 100644 --- a/plugins/base.go +++ b/plugins/base.go @@ -39,15 +39,19 @@ type souinWriterInterface interface { // CustomWriter handles the response and provide the way to cache the value type CustomWriter struct { - Response *http.Response - Buf *bytes.Buffer - Rw http.ResponseWriter - Req *http.Request - size int + Response *http.Response + Buf *bytes.Buffer + Rw http.ResponseWriter + Req *http.Request + size int + headersSent bool } // Header will write the response headers func (r *CustomWriter) Header() http.Header { + if r.headersSent { + return http.Header{} + } return r.Rw.Header() } @@ -59,6 +63,7 @@ func (r *CustomWriter) WriteHeader(code int) { if code != 0 { r.Response.StatusCode = code } + r.headersSent = true } // Write will write the response body diff --git a/plugins/beego/go.mod b/plugins/beego/go.mod index 6d098d7eb..5d8686662 100644 --- a/plugins/beego/go.mod +++ b/plugins/beego/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/beego/beego/v2 v2.0.4 - github.com/darkweak/souin v1.6.21 + github.com/darkweak/souin v1.6.22 ) require ( @@ -79,4 +79,4 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace github.com/darkweak/souin v1.6.21 => ../.. +replace github.com/darkweak/souin v1.6.22 => ../.. diff --git a/plugins/caddy/Caddyfile b/plugins/caddy/Caddyfile index ad22199db..84c84e7fb 100644 --- a/plugins/caddy/Caddyfile +++ b/plugins/caddy/Caddyfile @@ -104,6 +104,45 @@ route /nuts-configuration { respond "Hello nuts" } +route /redis-configuration { + cache { + ttl 15s + redis { + configuration { + Network my-network + Addr 127.0.0.1:6789 + Username user + Password password + DB 1 + MaxRetries 1 + MinRetryBackoff 5s + MaxRetryBackoff 5s + DialTimeout 5s + ReadTimeout 5s + WriteTimeout 5s + PoolFIFO true + PoolSize 99999 + PoolTimeout 10s + MinIdleConns 100 + MaxIdleConns 100 + ConnMaxIdleTime 5s + ConnMaxLifetime 5s + } + } + } + respond "Hello redis" +} + +route /redis-url { + cache { + ttl 15s + redis { + url 127.0.0.1:6789 + } + } + respond "Hello redis url" +} + route /vary { cache { ttl 15s diff --git a/plugins/caddy/README.md b/plugins/caddy/README.md index 179c90245..0bf304c50 100644 --- a/plugins/caddy/README.md +++ b/plugins/caddy/README.md @@ -20,12 +20,14 @@ Using the minimal configuration the responses will be cached for `120s` cache } -cache * { +example.com { + cache + reverse_proxy your-app:8080 } ``` -## Example Configurations -There is the fully configuration below +## Global Option Syntax +Here are all the available options for the global options ```caddy { order cache before rewrite @@ -96,116 +98,119 @@ There is the fully configuration below :4443 respond "Hello World!" +``` -@match path /test1* -@match2 path /test2* -@matchdefault path /default -@souin-api path /souin-api* - -cache @match { - ttl 5s - badger { - path /tmp/badger/first-match - configuration { - # Required value - ValueDir +## Cache directive Syntax +Here are all the available options for the directive options - # Optional - SyncWrites - NumVersionsToKeep - ReadOnly - Compression - InMemory - MetricsEnabled - MemTableSize - BaseTableSize - BaseLevelSize - LevelSizeMultiplier - TableSizeMultiplier - MaxLevels - VLogPercentile - ValueThreshold - NumMemtables - BlockSize - BloomFalsePositive - BlockCacheSize - IndexCacheSize - NumLevelZeroTables - NumLevelZeroTablesStall - ValueLogFileSize - ValueLogMaxEntries - NumCompactors - CompactL0OnClose - LmaxCompaction - ZSTDCompressionLevel - VerifyValueChecksum - EncryptionKey - EncryptionKey - BypassLockGuard - ChecksumVerificationMode - DetectConflicts - NamespaceOffset - } - } -} +``` +@match path /path -cache @match2 { - ttl 50s - badger { - path /tmp/badger/second-match - configuration { - ValueDir match2 - ValueLogFileSize 16777216 - MemTableSize 4194304 - ValueThreshold 524288 - BypassLockGuard true +@match { + cache { + cache_name ChangeName + cache_keys { + (host1|host2).*\.css { + disable_body + disable_host + disable_method + } } - } - headers Authorization - default_cache_control "public, max-age=86400" -} - -cache @matchdefault { - ttl 5s - badger { - path /tmp/badger/default-match - configuration { - ValueDir default - ValueLogFileSize 16777216 - MemTableSize 4194304 - ValueThreshold 524288 - BypassLockGuard true + cdn { + api_key XXXX + dynamic + email darkweak@protonmail.com + hostname domain.com + network your_network + provider fastly + strategy soft + service_id 123456_id + zone_id anywhere_zone } - } - cache_name ChangeName - cache_keys { - (host1|host2).*\.css { + key { disable_body disable_host disable_method } + headers Content-Type Authorization + log_level debug + regex { + exclude /test2.* + } + stale 200s + ttl 1000s + default_cache_control no-store } } +``` + +## Provider Syntax -route /badger-configuration { +### Badger +The badger provider must have either the path or the configuration directive. +``` +badger-path.com { + cache { + badger { + path /tmp/badger/first-match + } + } +} +``` +``` +badger-configuration.com { cache { - ttl 15s badger { configuration { - Dir /tmp/badger-configuration - ValueDir match2 - ValueLogFileSize 16777216 - MemTableSize 4194304 - ValueThreshold 524288 + # Required value + ValueDir + + # Optional + SyncWrites + NumVersionsToKeep + ReadOnly + Compression + InMemory + MetricsEnabled + MemTableSize + BaseTableSize + BaseLevelSize + LevelSizeMultiplier + TableSizeMultiplier + MaxLevels + VLogPercentile + ValueThreshold + NumMemtables + BlockSize + BloomFalsePositive + BlockCacheSize + IndexCacheSize + NumLevelZeroTables + NumLevelZeroTablesStall + ValueLogFileSize + ValueLogMaxEntries + NumCompactors + CompactL0OnClose + LmaxCompaction + ZSTDCompressionLevel + VerifyValueChecksum + EncryptionKey + EncryptionKey + BypassLockGuard + ChecksumVerificationMode + DetectConflicts + NamespaceOffset } } } - respond "Hello badger" } +``` -route /etcd-configuration { +### Etcd +The etcd provider must have the configuration directive. +``` +etcd-configuration.com { cache { - ttl 15s etcd { configuration { Endpoints etcd1:2379 etcd2:2379 etcd3:2379 @@ -222,12 +227,63 @@ route /etcd-configuration { } } } - respond "Hello etcd" } +``` + +### NutsDB +The nutsdb provider must have either the path or the configuration directive. +``` +nuts-path.com { + cache { + nuts { + path /tmp/nuts-path + } + } +} +``` +``` +nuts-configuration.com { + cache { + nuts { + configuration { + Dir /tmp/nuts-configuration + EntryIdxMode 1 + RWMode 0 + SegmentSize 1024 + NodeNum 42 + SyncEnable true + StartFileLoadingMode 1 + } + } + } +} +``` + +### Olric +The olric provider must have either the url directive to work as client mode. +``` +olric-url.com { + cache { + olric { + url olric:3320 + } + } +} +``` -route /nuts-configuration { +The olric provider must have either the path or the configuration directive to work as embedded mode. +``` +olric-path.com { + cache { + olric { + path /path/to/olricd.yml + } + } +} +``` +``` +olric-configuration.com { cache { - ttl 15s nuts { configuration { Dir /tmp/nuts-configuration @@ -240,11 +296,50 @@ route /nuts-configuration { } } } - respond "Hello nuts" } +``` + +### Redis +The redis provider must have either the URL or the configuration directive. -cache @souin-api {} ``` +redis-url.com { + cache { + redis { + url 127.0.0.1:6789 + } + } +} +``` +``` +redis-configuration.com { + cache { + redis { + configuration { + Network my-network + Addr 127.0.0.1:6789 + Username user + Password password + DB 1 + MaxRetries 1 + MinRetryBackoff 5s + MaxRetryBackoff 5s + DialTimeout 5s + ReadTimeout 5s + WriteTimeout 5s + PoolFIFO true + PoolSize 99999 + PoolTimeout 10s + MinIdleConns 100 + MaxIdleConns 100 + ConnMaxIdleTime 5s + ConnMaxLifetime 5s + } + } + } +} +``` + What does these directives mean? | Key | Description | Value example | |:-----------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------| @@ -286,11 +381,14 @@ What does these directives mean? | `olric` | Configure the Olric cache storage | | | `olric.path` | Configure Olric with a file | `/anywhere/olric_configuration.json` | | `olric.configuration` | Configure Olric directly in the Caddyfile or your JSON caddy configuration | [See the Olric configuration for the options](https://github.com/buraksezer/olric/blob/master/cmd/olricd/olricd.yaml/) | +| `redis` | Configure the Redis cache storage | | +| `redis.url` | Set the Redis url storage | `localhost:6379` | +| `redis.configuration` | Configure Redis directly in the Caddyfile or your JSON caddy configuration | [See the Nuts configuration for the options](https://github.com/nutsdb/nutsdb#default-options) | | `regex.exclude` | The regex used to prevent paths being cached | `^[A-z]+.*$` | | `stale` | The stale duration | `25m` | -| `timeout` | The timeout configuration | | -| `timeout.backend` | The timeout duration to consider the backend as unreachable | `10s` | -| `timeout.cache` | The timeout duration to consider the cache provider as unreachable | `10ms` | +| `timeout` | The timeout configuration | | +| `timeout.backend` | The timeout duration to consider the backend as unreachable | `10s` | +| `timeout.cache` | The timeout duration to consider the cache provider as unreachable | `10ms` | | `ttl` | The TTL duration | `120s` | | `log_level` | The log level | `One of DEBUG, INFO, WARN, ERROR, DPANIC, PANIC, FATAL it's case insensitive` | @@ -298,7 +396,3 @@ Other resources --------------- You can find an example for the [Caddyfile](Caddyfile) or the [JSON file](configuration.json). See the [Souin](https://github.com/darkweak/souin) configuration for the full configuration, and its associated [Caddyfile](https://github.com/darkweak/souin/blob/master/plugins/caddy/Caddyfile) - -## TODO - -* [ ] Improve the API and add relevant endpoints diff --git a/plugins/caddy/app.go b/plugins/caddy/app.go index f161e9770..32288b13a 100644 --- a/plugins/caddy/app.go +++ b/plugins/caddy/app.go @@ -12,11 +12,16 @@ import ( // SouinApp contains the whole Souin necessary items type SouinApp struct { *DefaultCache - Provider types.AbstractProviderInterface + // The provider to use. + Provider types.AbstractProviderInterface + // Surrogate storage to support th econfiguration reload without surrogate-key data loss. SurrogateStorage providers.SurrogateInterface - CacheKeys map[string]configurationtypes.Key `json:"cache_keys,omitempty"` - API configurationtypes.API `json:"api,omitempty"` - LogLevel string `json:"log_level,omitempty"` + // Cache-key tweaking. + CacheKeys map[string]configurationtypes.Key `json:"cache_keys,omitempty"` + // API endpoints enablers. + API configurationtypes.API `json:"api,omitempty"` + // Logger level, fallback on caddy's one when not redefined. + LogLevel string `json:"log_level,omitempty"` } func init() { @@ -30,8 +35,8 @@ func (s *SouinApp) Provision(_ caddy.Context) error { // Start will start the App func (s SouinApp) Start() error { - up.Delete(stored_providers_key) - up.LoadOrStore(stored_providers_key, newStorageProvider()) + _, _ = up.Delete(stored_providers_key) + _, _ = up.LoadOrStore(stored_providers_key, newStorageProvider()) if s.DefaultCache != nil && s.DefaultCache.GetTTL() == 0 { return errors.New("Invalid/Incomplete default cache declaration") } diff --git a/plugins/caddy/configuration.go b/plugins/caddy/configuration.go index 12fbb5b29..5e84fe275 100644 --- a/plugins/caddy/configuration.go +++ b/plugins/caddy/configuration.go @@ -9,22 +9,37 @@ import ( // DefaultCache the struct type DefaultCache struct { - AllowedHTTPVerbs []string `json:"allowed_http_verbs"` - Badger configurationtypes.CacheProvider `json:"badger"` - CacheName string `json:"cache_name"` - CDN configurationtypes.CDN `json:"cdn"` - DefaultCacheControl string `json:"default_cache_control"` - Distributed bool `json:"distributed"` - Headers []string `json:"headers"` - Key configurationtypes.Key `json:"key"` - Olric configurationtypes.CacheProvider `json:"olric"` - Redis configurationtypes.CacheProvider `json:"redis"` - Etcd configurationtypes.CacheProvider `json:"etcd"` - Nuts configurationtypes.CacheProvider `json:"nuts"` - Regex configurationtypes.Regex `json:"regex"` - Timeout configurationtypes.Timeout `json:"timeout"` - TTL configurationtypes.Duration `json:"ttl"` - Stale configurationtypes.Duration `json:"stale"` + // Allowed HTTP verbs to be cached by the system. + AllowedHTTPVerbs []string `json:"allowed_http_verbs"` + // Badger provider configuration. + Badger configurationtypes.CacheProvider `json:"badger"` + // The cache name to use in the Cache-Status response header. + CacheName string `json:"cache_name"` + CDN configurationtypes.CDN `json:"cdn"` + // The default Cache-Control header value if none set by the upstream server. + DefaultCacheControl string `json:"default_cache_control"` + // Redis provider configuration. + Distributed bool `json:"distributed"` + // Headers to add to the cache key if they are present. + Headers []string `json:"headers"` + // Configure the global key generation. + Key configurationtypes.Key `json:"key"` + // Olric provider configuration. + Olric configurationtypes.CacheProvider `json:"olric"` + // Redis provider configuration. + Redis configurationtypes.CacheProvider `json:"redis"` + // Etcd provider configuration. + Etcd configurationtypes.CacheProvider `json:"etcd"` + // NutsDB provider configuration. + Nuts configurationtypes.CacheProvider `json:"nuts"` + // Regex to exclude cache. + Regex configurationtypes.Regex `json:"regex"` + // Time before cache or backend access timeout. + Timeout configurationtypes.Timeout `json:"timeout"` + // Time to live. + TTL configurationtypes.Duration `json:"ttl"` + // Stale time to live. + Stale configurationtypes.Duration `json:"stale"` } // GetAllowedHTTPVerbs returns the allowed verbs to cache @@ -109,13 +124,18 @@ func (d *DefaultCache) GetDefaultCacheControl() string { //Configuration holder type Configuration struct { + // Default cache to fallback on when none are redefined. DefaultCache *DefaultCache - API configurationtypes.API + // API endpoints enablers. + API configurationtypes.API + // Cache keys configuration. CfgCacheKeys map[string]configurationtypes.Key - URLs map[string]configurationtypes.URL - LogLevel string - cacheKeys map[configurationtypes.RegValue]configurationtypes.Key - logger *zap.Logger + // Override the ttl depending the cases. + URLs map[string]configurationtypes.URL + // Logger level, fallback on caddy's one when not redefined. + LogLevel string + cacheKeys map[configurationtypes.RegValue]configurationtypes.Key + logger *zap.Logger } // GetUrls get the urls list in the configuration diff --git a/plugins/caddy/go.mod b/plugins/caddy/go.mod index a5d6b4e42..4f7023642 100644 --- a/plugins/caddy/go.mod +++ b/plugins/caddy/go.mod @@ -4,8 +4,8 @@ go 1.18 require ( github.com/buraksezer/olric v0.4.7 - github.com/caddyserver/caddy/v2 v2.6.0 - github.com/darkweak/souin v1.6.21 + github.com/caddyserver/caddy/v2 v2.6.1 + github.com/darkweak/souin v1.6.22 go.uber.org/zap v1.21.0 ) @@ -174,4 +174,4 @@ require ( howett.net/plist v1.0.0 // indirect ) -replace github.com/darkweak/souin v1.6.21 => ../.. +replace github.com/darkweak/souin v1.6.22 => ../.. diff --git a/plugins/caddy/go.sum b/plugins/caddy/go.sum index f27ec85bc..d44f9c63e 100644 --- a/plugins/caddy/go.sum +++ b/plugins/caddy/go.sum @@ -140,8 +140,8 @@ github.com/buraksezer/olric v0.4.7 h1:z6UiY6KS/Zpx3BP8MU9HdwFoJ1M2pUMVk+E7zGBjTE github.com/buraksezer/olric v0.4.7/go.mod h1:i5HJXtbgjCFXn8VTOtt4kr5H6f6qXHmBs0wdH5meJRA= github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= -github.com/caddyserver/caddy/v2 v2.6.0 h1:lHDynvM+sTOi9Aq4Y15b4FtkqzPB36WbUrZvVdwzTCA= -github.com/caddyserver/caddy/v2 v2.6.0/go.mod h1:YFaWZkg/wx3xW8mCF1Ydazk8dWbBBu/tx7IagU+E9io= +github.com/caddyserver/caddy/v2 v2.6.1 h1:EDqo59TyYWhXQnfde93Mmv4FJfYe00dO60zMiEt+pzo= +github.com/caddyserver/caddy/v2 v2.6.1/go.mod h1:YFaWZkg/wx3xW8mCF1Ydazk8dWbBBu/tx7IagU+E9io= github.com/caddyserver/certmagic v0.17.1 h1:VrWANhQAj3brK7jAUKyN6XBHg56WsyorI/84Ilq1tCQ= github.com/caddyserver/certmagic v0.17.1/go.mod h1:pSS2aZcdKlrTZrb2DKuRafckx20o5Fz1EdDKEB8KOQM= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= diff --git a/plugins/caddy/httpcache.go b/plugins/caddy/httpcache.go index a8b328dce..4789dd6b0 100644 --- a/plugins/caddy/httpcache.go +++ b/plugins/caddy/httpcache.go @@ -50,7 +50,7 @@ type SouinCaddyPlugin struct { Configuration *Configuration logger *zap.Logger cacheKeys map[configurationtypes.RegValue]configurationtypes.Key - // Log level. + // Logger level, fallback on caddy's one when not redefined. LogLevel string `json:"log_level,omitempty"` bufPool *sync.Pool // Allowed HTTP verbs to be cached by the system. @@ -330,7 +330,7 @@ func (s *SouinCaddyPlugin) Provision(ctx caddy.Context) error { if l { s.logger.Sugar().Debug("Loaded coalescing layer from cache.") - s.Retriever.GetTransport().GetCoalescingLayerStorage().Destruct() + _ = s.Retriever.GetTransport().GetCoalescingLayerStorage().Destruct() s.Retriever.GetTransport().(*rfc.VaryTransport).CoalescingLayerStorage = v.(*types.CoalescingLayerStorage) } diff --git a/plugins/caddy/httpcache_test.go b/plugins/caddy/httpcache_test.go index 290795e6e..b57d3fd17 100644 --- a/plugins/caddy/httpcache_test.go +++ b/plugins/caddy/httpcache_test.go @@ -8,6 +8,39 @@ import ( "github.com/caddyserver/caddy/v2/caddytest" ) +func TestMinimal(t *testing.T) { + tester := caddytest.NewTester(t) + tester.InitServer(` + { + order cache before rewrite + http_port 9080 + https_port 9443 + cache + } + localhost:9080 { + route /cache-default { + cache + respond "Hello, default!" + } + }`, "caddyfile") + + resp1, _ := tester.AssertGetResponse(`http://localhost:9080/cache-default`, 200, "Hello, default!") + if resp1.Header.Get("Cache-Status") != "Souin; fwd=uri-miss; stored" { + t.Errorf("unexpected Cache-Status header %v", resp1.Header) + } + + resp2, _ := tester.AssertGetResponse(`http://localhost:9080/cache-default`, 200, "Hello, default!") + if resp2.Header.Get("Cache-Status") != "Souin; hit; ttl=59" { + t.Errorf("unexpected Cache-Status header %v", resp2.Header.Get("Cache-Status")) + } + + time.Sleep(2 * time.Second) + resp3, _ := tester.AssertGetResponse(`http://localhost:9080/cache-default`, 200, "Hello, default!") + if resp3.Header.Get("Cache-Status") != "Souin; hit; ttl=57" { + t.Errorf("unexpected Cache-Status header %v", resp3.Header.Get("Cache-Status")) + } +} + func TestMaxAge(t *testing.T) { tester := caddytest.NewTester(t) tester.InitServer(` diff --git a/plugins/chi/go.mod b/plugins/chi/go.mod index 1a389fe1a..0bea8e579 100644 --- a/plugins/chi/go.mod +++ b/plugins/chi/go.mod @@ -3,7 +3,7 @@ module github.com/darkweak/souin/plugins/chi go 1.18 require ( - github.com/darkweak/souin v1.6.21 + github.com/darkweak/souin v1.6.22 github.com/go-chi/chi/v5 v5.0.7 ) @@ -77,4 +77,4 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace github.com/darkweak/souin v1.6.21 => ../.. +replace github.com/darkweak/souin v1.6.22 => ../.. diff --git a/plugins/dotweb/go.mod b/plugins/dotweb/go.mod index 57cba3f6e..1195f43f8 100644 --- a/plugins/dotweb/go.mod +++ b/plugins/dotweb/go.mod @@ -3,7 +3,7 @@ module github.com/darkweak/souin/plugins/dotweb go 1.18 require ( - github.com/darkweak/souin v1.6.21 + github.com/darkweak/souin v1.6.22 github.com/devfeel/dotweb v1.7.19 ) @@ -78,4 +78,4 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace github.com/darkweak/souin v1.6.21 => ../.. +replace github.com/darkweak/souin v1.6.22 => ../.. diff --git a/plugins/echo/go.mod b/plugins/echo/go.mod index f8405075a..795c75109 100644 --- a/plugins/echo/go.mod +++ b/plugins/echo/go.mod @@ -3,8 +3,8 @@ module github.com/darkweak/souin/plugins/echo go 1.18 require ( - github.com/darkweak/souin v1.6.21 - github.com/labstack/echo/v4 v4.7.2 + github.com/darkweak/souin v1.6.22 + github.com/labstack/echo/v4 v4.9.0 ) require ( @@ -44,9 +44,9 @@ require ( github.com/hashicorp/memberlist v0.1.5 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/klauspost/compress v1.12.3 // indirect - github.com/labstack/gommon v0.3.1 // indirect - github.com/mattn/go-colorable v0.1.11 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect + github.com/labstack/gommon v0.4.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/miekg/dns v1.1.31 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -69,11 +69,11 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.21.0 // indirect - golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect - golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect + golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2 // indirect + golang.org/x/net v0.0.0-20221004154528-8021a29435af // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect - golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664 // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/sys v0.0.0-20221010170243-090e33056c14 // indirect + golang.org/x/text v0.3.8 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect google.golang.org/grpc v1.38.0 // indirect @@ -82,4 +82,4 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace github.com/darkweak/souin v1.6.21 => ../.. +replace github.com/darkweak/souin v1.6.22 => ../.. diff --git a/plugins/echo/go.sum b/plugins/echo/go.sum index 0e37077be..4d5d87950 100644 --- a/plugins/echo/go.sum +++ b/plugins/echo/go.sum @@ -247,17 +247,19 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI= -github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= -github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o= -github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= +github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY= +github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= +github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= +github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= @@ -405,8 +407,9 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201001193750-eb9a90e9f9cb/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2 h1:x8vtB3zMecnlqZIwJNUUpwYKYSqCz5jXbiyv0ZJJZeI= +golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -480,8 +483,9 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20221004154528-8021a29435af h1:wv66FM3rLZGPdxpYL+ApnDe2HzHcTFta3z5nsc13wI4= +golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -561,8 +565,10 @@ golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220405210540-1e041c57c461/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664 h1:wEZYwx+kK+KlZ0hpvP2Ls1Xr4+RWnlzGFwPP0aiDjIU= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14 h1:k5II8e6QD8mITdi+okbbmR/cIyEbeXLBhy5Ha4nevyc= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -572,8 +578,9 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/plugins/fiber/go.mod b/plugins/fiber/go.mod index 5a5bd8699..98f25e346 100644 --- a/plugins/fiber/go.mod +++ b/plugins/fiber/go.mod @@ -3,7 +3,7 @@ module github.com/darkweak/souin/plugins/fiber go 1.18 require ( - github.com/darkweak/souin v1.6.21 + github.com/darkweak/souin v1.6.22 github.com/gofiber/fiber/v2 v2.34.1 github.com/valyala/fasthttp v1.38.0 ) @@ -81,4 +81,4 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace github.com/darkweak/souin v1.6.21 => ../.. +replace github.com/darkweak/souin v1.6.22 => ../.. diff --git a/plugins/gin/go.mod b/plugins/gin/go.mod index 46a6a60ed..a6b72138e 100644 --- a/plugins/gin/go.mod +++ b/plugins/gin/go.mod @@ -3,7 +3,7 @@ module github.com/darkweak/souin/plugins/gin go 1.18 require ( - github.com/darkweak/souin v1.6.21 + github.com/darkweak/souin v1.6.22 github.com/gin-gonic/gin v1.8.1 ) @@ -89,4 +89,4 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace github.com/darkweak/souin v1.6.21 => ../.. +replace github.com/darkweak/souin v1.6.22 => ../.. diff --git a/plugins/go-zero/go.mod b/plugins/go-zero/go.mod index 07ce4824a..7ee727f43 100644 --- a/plugins/go-zero/go.mod +++ b/plugins/go-zero/go.mod @@ -3,7 +3,7 @@ module github.com/darkweak/souin/plugins/go-zero go 1.18 require ( - github.com/darkweak/souin v1.6.21 + github.com/darkweak/souin v1.6.22 github.com/zeromicro/go-zero v1.3.0 ) @@ -89,4 +89,4 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace github.com/darkweak/souin v1.6.21 => ../.. +replace github.com/darkweak/souin v1.6.22 => ../.. diff --git a/plugins/goyave/go.mod b/plugins/goyave/go.mod index 8f6fd9903..107506de3 100644 --- a/plugins/goyave/go.mod +++ b/plugins/goyave/go.mod @@ -3,7 +3,7 @@ module github.com/darkweak/souin/plugins/goyave go 1.18 require ( - github.com/darkweak/souin v1.6.21 + github.com/darkweak/souin v1.6.22 github.com/pquerna/cachecontrol v0.1.0 goyave.dev/goyave/v4 v4.4.2 ) @@ -84,4 +84,4 @@ require ( gorm.io/gorm v1.23.5 // indirect ) -replace github.com/darkweak/souin v1.6.21 => ../.. +replace github.com/darkweak/souin v1.6.22 => ../.. diff --git a/plugins/kratos/go.mod b/plugins/kratos/go.mod index caae02747..689c50a30 100644 --- a/plugins/kratos/go.mod +++ b/plugins/kratos/go.mod @@ -3,7 +3,7 @@ module github.com/darkweak/souin/plugins/kratos go 1.18 require ( - github.com/darkweak/souin v1.6.21 + github.com/darkweak/souin v1.6.22 github.com/go-kratos/kratos/v2 v2.5.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -80,4 +80,4 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect ) -replace github.com/darkweak/souin v1.6.21 => ../.. +replace github.com/darkweak/souin v1.6.22 => ../.. diff --git a/plugins/roadrunner/Makefile b/plugins/roadrunner/Makefile index 827a950c1..c5437a11b 100644 --- a/plugins/roadrunner/Makefile +++ b/plugins/roadrunner/Makefile @@ -4,7 +4,7 @@ load-checker: ## Ensure Souin is running cd examples && echo "MIDDLEWARE_RESULT=$$(docker-compose logs roadrunner | grep 'Souin configuration' | tail -n 1)" prepare: vendor ## Prepare roadrunner plugin - cd examples && cp docker-compose.yml.test docker-compose.yml && docker-compose up -d + cd examples && cp docker-compose.yml.test docker-compose.yml && docker-compose up -d --build vendor: ## Update the go mods for the plugin go mod tidy diff --git a/plugins/roadrunner/configuration.go b/plugins/roadrunner/configuration.go index ad3d1be50..83b2d85cf 100644 --- a/plugins/roadrunner/configuration.go +++ b/plugins/roadrunner/configuration.go @@ -86,8 +86,12 @@ func parseDefaultCache(dcConfiguration map[string]interface{}) *configurationtyp switch defaultCacheK { case "allowed_http_verbs": dc.AllowedHTTPVerbs = make([]string, 0) - for _, v := range defaultCacheV.([]interface{}) { - dc.AllowedHTTPVerbs = append(dc.AllowedHTTPVerbs, v.(string)) + if values, ok := defaultCacheV.([]string); ok { + dc.AllowedHTTPVerbs = values + } else if values, ok := defaultCacheV.([]interface{}); ok { + for _, v := range values { + dc.AllowedHTTPVerbs = append(dc.AllowedHTTPVerbs, v.(string)) + } } case "badger": provider := configurationtypes.CacheProvider{} @@ -139,8 +143,12 @@ func parseDefaultCache(dcConfiguration map[string]interface{}) *configurationtyp dc.Etcd = provider case "headers": dc.Headers = make([]string, 0) - for _, v := range defaultCacheV.([]interface{}) { - dc.Headers = append(dc.Headers, v.(string)) + if values, ok := defaultCacheV.([]string); ok { + dc.Headers = values + } else if values, ok := defaultCacheV.([]interface{}); ok { + for _, v := range values { + dc.Headers = append(dc.Headers, v.(string)) + } } case "nuts": provider := configurationtypes.CacheProvider{} @@ -242,8 +250,12 @@ func parseURLs(urls map[string]interface{}) map[string]configurationtypes.URL { switch k { case "headers": currentURL.Headers = make([]string, 0) - for _, urlV := range v.([]interface{}) { - currentURL.Headers = append(currentURL.Headers, urlV.(string)) + if values, ok := urlV.([]string); ok { + currentURL.Headers = values + } else if values, ok := urlV.([]interface{}); ok { + for _, value := range values { + currentURL.Headers = append(currentURL.Headers, value.(string)) + } } case "ttl": if ttl, err := time.ParseDuration(v.(string)); err == nil { diff --git a/plugins/roadrunner/examples/configuration.toml b/plugins/roadrunner/examples/configuration.toml index f40be4e8c..f6c72bf30 100644 --- a/plugins/roadrunner/examples/configuration.toml +++ b/plugins/roadrunner/examples/configuration.toml @@ -10,7 +10,7 @@ ref = "master" [github.plugins] logger = { ref = "master", owner = "roadrunner-server", repository = "logger" } - cache = { ref = "master", owner = "darkweak", repository = "souin", folder = "/plugins/roadrunner" } + cache = { ref = "master", owner = "darkweak", repository = "souin", folder = "/plugins/roadrunner", replace = "/opt/plugins/roadrunner" } server = { ref = "master", owner = "roadrunner-server", repository = "server" } gzip = { ref = "master", owner = "roadrunner-server", repository = "gzip" } http = { ref = "master", owner = "roadrunner-server", repository = "http" } diff --git a/plugins/roadrunner/go.mod b/plugins/roadrunner/go.mod index d020fff2c..f0ba532ee 100644 --- a/plugins/roadrunner/go.mod +++ b/plugins/roadrunner/go.mod @@ -3,7 +3,7 @@ module github.com/darkweak/souin/plugins/roadrunner go 1.18 require ( - github.com/darkweak/souin v1.6.21 + github.com/darkweak/souin v1.6.22 github.com/roadrunner-server/api/v2 v2.23.0 github.com/roadrunner-server/errors v1.2.0 go.uber.org/zap v1.23.0 @@ -78,4 +78,4 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect ) -replace github.com/darkweak/souin v1.6.21 => ../.. +replace github.com/darkweak/souin v1.6.22 => ../.. diff --git a/plugins/skipper/go.mod b/plugins/skipper/go.mod index f8b6c9630..c160c2667 100644 --- a/plugins/skipper/go.mod +++ b/plugins/skipper/go.mod @@ -3,7 +3,7 @@ module github.com/darkweak/souin/plugins/skipper go 1.18 require ( - github.com/darkweak/souin v1.6.21 + github.com/darkweak/souin v1.6.22 github.com/zalando/skipper v0.13.225 ) @@ -121,4 +121,4 @@ require ( layeh.com/gopher-json v0.0.0-20201124131017-552bb3c4c3bf // indirect ) -replace github.com/darkweak/souin v1.6.21 => ../.. +replace github.com/darkweak/souin v1.6.22 => ../.. diff --git a/plugins/traefik/go.mod b/plugins/traefik/go.mod index e7fb1fe73..9f0452cb0 100644 --- a/plugins/traefik/go.mod +++ b/plugins/traefik/go.mod @@ -3,7 +3,7 @@ module github.com/darkweak/souin/plugins/traefik go 1.18 require ( - github.com/darkweak/souin v1.6.21 + github.com/darkweak/souin v1.6.22 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pquerna/cachecontrol v0.1.0 go.uber.org/zap v1.21.0 @@ -76,4 +76,4 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace github.com/darkweak/souin v1.6.21 => ../.. +replace github.com/darkweak/souin v1.6.22 => ../.. diff --git a/plugins/traefik/override/context/types.go b/plugins/traefik/override/context/types.go index 241896ff5..7135b985a 100644 --- a/plugins/traefik/override/context/types.go +++ b/plugins/traefik/override/context/types.go @@ -23,6 +23,8 @@ type ( } ) +const CacheControlCtx ctxKey = "CACHE-CONTROL-CTX" + func GetContext() *Context { return &Context{ CacheName: &cacheContext{}, diff --git a/plugins/traefik/vendor/github.com/darkweak/souin/context/types.go b/plugins/traefik/vendor/github.com/darkweak/souin/context/types.go index 241896ff5..7135b985a 100644 --- a/plugins/traefik/vendor/github.com/darkweak/souin/context/types.go +++ b/plugins/traefik/vendor/github.com/darkweak/souin/context/types.go @@ -23,6 +23,8 @@ type ( } ) +const CacheControlCtx ctxKey = "CACHE-CONTROL-CTX" + func GetContext() *Context { return &Context{ CacheName: &cacheContext{}, diff --git a/plugins/traefik/vendor/github.com/darkweak/souin/rfc/bridge.go b/plugins/traefik/vendor/github.com/darkweak/souin/rfc/bridge.go index 684ae5cb9..ce2f5fa08 100644 --- a/plugins/traefik/vendor/github.com/darkweak/souin/rfc/bridge.go +++ b/plugins/traefik/vendor/github.com/darkweak/souin/rfc/bridge.go @@ -3,6 +3,7 @@ package rfc import ( "bufio" "bytes" + ctx "context" "net/http" "time" @@ -108,12 +109,30 @@ func commonVaryMatchesVerification(cachedResp *http.Response, req *http.Request) return nil } +func getAppropriateCacheControlHeader(h http.Header, cacheName string) string { + if v := h.Get(cacheName + "-Cache-Control"); v != "" { + return v + } + if v := h.Get("CDN-Cache-Control"); v != "" { + return v + } + return h.Get("Cache-Control") +} + // UpdateCacheEventually will handle Request and update the previous one in the cache provider func (t *VaryTransport) UpdateCacheEventually(req *http.Request) (*http.Response, error) { - if req.Response.Header.Get("Cache-Control") == "" && t.ConfigurationURL.DefaultCacheControl != "" { + select { + case <-req.Context().Done(): + return nil, nil + default: + } + ccHeaderValue := getAppropriateCacheControlHeader(req.Response.Header, req.Context().Value(context.CacheName).(string)) + req = req.WithContext(ctx.WithValue(req.Context(), context.CacheControlCtx, ccHeaderValue)) + if ccHeaderValue == "" && t.ConfigurationURL.DefaultCacheControl != "" { if req.Response.Header == nil { req.Response.Header = http.Header{} } + req = req.WithContext(ctx.WithValue(req.Context(), context.CacheControlCtx, t.ConfigurationURL.DefaultCacheControl)) req.Response.Header.Set("Cache-Control", t.ConfigurationURL.DefaultCacheControl) } diff --git a/plugins/traefik/vendor/github.com/darkweak/souin/rfc/transport.go b/plugins/traefik/vendor/github.com/darkweak/souin/rfc/transport.go index 4c0e3b747..b301bb6f5 100644 --- a/plugins/traefik/vendor/github.com/darkweak/souin/rfc/transport.go +++ b/plugins/traefik/vendor/github.com/darkweak/souin/rfc/transport.go @@ -68,8 +68,8 @@ func (t *VaryTransport) SetSurrogateKeys(s providers.SurrogateInterface) { } // SetCache set the cache -func (t *VaryTransport) SetCache(key string, resp *http.Response) { - co, e := cacheobject.ParseResponseCacheControl(resp.Header.Get("Cache-Control")) +func (t *VaryTransport) SetCache(key string, resp *http.Response, ccValue string) { + co, e := cacheobject.ParseResponseCacheControl(ccValue) if e != nil { return } diff --git a/plugins/traefik/vendor/github.com/darkweak/souin/rfc/vary.go b/plugins/traefik/vendor/github.com/darkweak/souin/rfc/vary.go index ec5cfe968..279c76139 100644 --- a/plugins/traefik/vendor/github.com/darkweak/souin/rfc/vary.go +++ b/plugins/traefik/vendor/github.com/darkweak/souin/rfc/vary.go @@ -29,7 +29,7 @@ func validateVary(req *http.Request, resp *http.Response, key string, t *VaryTra resp.Header.Set("Cache-Status", fmt.Sprintf("%s; fwd=uri-miss; stored", req.Context().Value(context.CacheName))) resp.Header.Del("Age") _ = t.SurrogateStorage.Store(resp, cacheKey) - t.SetCache(cacheKey, resp) + t.SetCache(cacheKey, resp, req.Context().Value(context.CacheControlCtx).(string)) go func() { t.CoalescingLayerStorage.Delete(cacheKey) }() diff --git a/plugins/traefik/vendor/modules.txt b/plugins/traefik/vendor/modules.txt index 48787b9ce..ffd25fc2b 100644 --- a/plugins/traefik/vendor/modules.txt +++ b/plugins/traefik/vendor/modules.txt @@ -55,7 +55,7 @@ github.com/coreos/go-semver/semver # github.com/coreos/go-systemd/v22 v22.3.2 ## explicit; go 1.12 github.com/coreos/go-systemd/v22/journal -# github.com/darkweak/souin v1.6.21 => ../.. +# github.com/darkweak/souin v1.6.22 => ../.. ## explicit; go 1.16 github.com/darkweak/souin/api github.com/darkweak/souin/api/auth diff --git a/plugins/tyk/go.mod b/plugins/tyk/go.mod index 35c0621cc..6114f4d26 100644 --- a/plugins/tyk/go.mod +++ b/plugins/tyk/go.mod @@ -8,7 +8,7 @@ require ( github.com/armon/go-metrics v0.4.1 // indirect github.com/buraksezer/consistent v0.9.0 // indirect github.com/coreos/go-systemd/v22 v22.4.0 // indirect - github.com/darkweak/souin v1.6.21 + github.com/darkweak/souin v1.6.22 github.com/eclipse/paho.mqtt.golang v1.4.1 // indirect github.com/evanphx/json-patch/v5 v5.5.0 // indirect github.com/go-redis/redis/v8 v8.11.5 // indirect @@ -65,4 +65,4 @@ require ( gorm.io/gorm v1.23.9 // indirect ) -replace github.com/darkweak/souin v1.6.21 => ../.. +replace github.com/darkweak/souin v1.6.22 => ../.. diff --git a/plugins/tyk/override/rfc/vary.go b/plugins/tyk/override/rfc/vary.go index 286ab54f3..fabce7859 100644 --- a/plugins/tyk/override/rfc/vary.go +++ b/plugins/tyk/override/rfc/vary.go @@ -37,7 +37,7 @@ func validateVary(req *http.Request, resp *http.Response, key string, t *VaryTra re := *resp re.Body = ioutil.NopCloser(r) _ = t.SurrogateStorage.Store(&re, cacheKey) - t.SetCache(cacheKey, &re) + t.SetCache(cacheKey, &re, req.Context().Value(context.CacheControlCtx).(string)) go func() { t.CoalescingLayerStorage.Delete(cacheKey) }() diff --git a/plugins/webgo/go.mod b/plugins/webgo/go.mod index 4dc8e5bef..52715ef5a 100644 --- a/plugins/webgo/go.mod +++ b/plugins/webgo/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/bnkamalesh/webgo/v6 v6.6.1 - github.com/darkweak/souin v1.6.21 + github.com/darkweak/souin v1.6.22 ) require ( @@ -77,4 +77,4 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace github.com/darkweak/souin v1.6.21 => ../.. +replace github.com/darkweak/souin v1.6.22 => ../.. diff --git a/rfc/bridge.go b/rfc/bridge.go index 684ae5cb9..ce2f5fa08 100644 --- a/rfc/bridge.go +++ b/rfc/bridge.go @@ -3,6 +3,7 @@ package rfc import ( "bufio" "bytes" + ctx "context" "net/http" "time" @@ -108,12 +109,30 @@ func commonVaryMatchesVerification(cachedResp *http.Response, req *http.Request) return nil } +func getAppropriateCacheControlHeader(h http.Header, cacheName string) string { + if v := h.Get(cacheName + "-Cache-Control"); v != "" { + return v + } + if v := h.Get("CDN-Cache-Control"); v != "" { + return v + } + return h.Get("Cache-Control") +} + // UpdateCacheEventually will handle Request and update the previous one in the cache provider func (t *VaryTransport) UpdateCacheEventually(req *http.Request) (*http.Response, error) { - if req.Response.Header.Get("Cache-Control") == "" && t.ConfigurationURL.DefaultCacheControl != "" { + select { + case <-req.Context().Done(): + return nil, nil + default: + } + ccHeaderValue := getAppropriateCacheControlHeader(req.Response.Header, req.Context().Value(context.CacheName).(string)) + req = req.WithContext(ctx.WithValue(req.Context(), context.CacheControlCtx, ccHeaderValue)) + if ccHeaderValue == "" && t.ConfigurationURL.DefaultCacheControl != "" { if req.Response.Header == nil { req.Response.Header = http.Header{} } + req = req.WithContext(ctx.WithValue(req.Context(), context.CacheControlCtx, t.ConfigurationURL.DefaultCacheControl)) req.Response.Header.Set("Cache-Control", t.ConfigurationURL.DefaultCacheControl) } diff --git a/rfc/transport.go b/rfc/transport.go index 4c0e3b747..b301bb6f5 100644 --- a/rfc/transport.go +++ b/rfc/transport.go @@ -68,8 +68,8 @@ func (t *VaryTransport) SetSurrogateKeys(s providers.SurrogateInterface) { } // SetCache set the cache -func (t *VaryTransport) SetCache(key string, resp *http.Response) { - co, e := cacheobject.ParseResponseCacheControl(resp.Header.Get("Cache-Control")) +func (t *VaryTransport) SetCache(key string, resp *http.Response, ccValue string) { + co, e := cacheobject.ParseResponseCacheControl(ccValue) if e != nil { return } diff --git a/rfc/transport_test.go b/rfc/transport_test.go index a8ca8ce3c..7861f284d 100644 --- a/rfc/transport_test.go +++ b/rfc/transport_test.go @@ -86,6 +86,6 @@ func TestVaryTransport_SetCache(t *testing.T) { key := req.Context().Value(context.Key).(string) prs := providers.InitializeProvider(config) tr := NewTransport(prs, ykeys.InitializeYKeys(config.Ykeys), surrogate.InitializeSurrogate(config)) - tr.SetCache(key, res) + tr.SetCache(key, res, "public") time.Sleep(1 * time.Second) } diff --git a/rfc/vary.go b/rfc/vary.go index ec5cfe968..279c76139 100644 --- a/rfc/vary.go +++ b/rfc/vary.go @@ -29,7 +29,7 @@ func validateVary(req *http.Request, resp *http.Response, key string, t *VaryTra resp.Header.Set("Cache-Status", fmt.Sprintf("%s; fwd=uri-miss; stored", req.Context().Value(context.CacheName))) resp.Header.Del("Age") _ = t.SurrogateStorage.Store(resp, cacheKey) - t.SetCache(cacheKey, resp) + t.SetCache(cacheKey, resp, req.Context().Value(context.CacheControlCtx).(string)) go func() { t.CoalescingLayerStorage.Delete(cacheKey) }() diff --git a/rfc/vary_test.go b/rfc/vary_test.go index e686d05e3..48c6f92b4 100644 --- a/rfc/vary_test.go +++ b/rfc/vary_test.go @@ -32,6 +32,7 @@ func TestVaryMatches(t *testing.T) { co := context.GetContext() co.Init(c) r = co.SetContext(r) + r = r.WithContext(ctx.WithValue(r.Context(), context.CacheControlCtx, "public")) if !varyMatches(res, r) { errors.GenerateError(t, "Vary match should return true if no header sent") @@ -97,6 +98,7 @@ func TestValidateVary_Load(t *testing.T) { req, _ := http.NewRequest(http.MethodGet, "/", nil) req = req.WithContext(ctx.WithValue(req.Context(), context.CacheName, "Souin")) req = req.WithContext(ctx.WithValue(req.Context(), context.Key, "GET-domain.com-/something")) + req = req.WithContext(ctx.WithValue(req.Context(), context.CacheControlCtx, "public")) if !validateVary(req, response, "", transport) { errors.GenerateError(t, "The validateVary must return true when a valid response is passed as parameter.") }