Skip to content

Commit 278c9f1

Browse files
authored
fix(multiple): october 2024 wave (#558)
* fix(multiple): october 2024 wave * feat(middleware): serve stale content if not strict * fix(ci): mod * feat(deps): bump storages version * fix(chore): stale-if-error * feat(global): implement simplefs storage & add missing cdn props support * fix(deny-request): text/event-stream drop closes #562 * feat(caddy): allow to configure TLSConfig in Caddyfile * fix(api): delete by regexp * bump(deps): use storages core v0.0.11 * fix(traefik): resolves #558, full rewrite to match the actual cache behavior. Yaegi sucks! * fix(chore): bypass on some cases
1 parent 13ce774 commit 278c9f1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+2006
-689
lines changed

configurationtypes/types.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ type DefaultCache struct {
246246
Redis CacheProvider `json:"redis" yaml:"redis"`
247247
Port Port `json:"port" yaml:"port"`
248248
Regex Regex `json:"regex" yaml:"regex"`
249+
SimpleFS CacheProvider `json:"simplefs" yaml:"simplefs"`
249250
Stale Duration `json:"stale" yaml:"stale"`
250251
Storers []string `json:"storers" yaml:"storers"`
251252
Timeout Timeout `json:"timeout" yaml:"timeout"`
@@ -300,7 +301,7 @@ func (d *DefaultCache) GetMode() string {
300301
return d.Mode
301302
}
302303

303-
// GetNats returns nuts configuration
304+
// GetNats returns nats configuration
304305
func (d *DefaultCache) GetNats() CacheProvider {
305306
return d.Nats
306307
}
@@ -340,6 +341,11 @@ func (d *DefaultCache) GetTTL() time.Duration {
340341
return d.TTL.Duration
341342
}
342343

344+
// GetSimpleFS returns simplefs configuration
345+
func (d *DefaultCache) GetSimpleFS() CacheProvider {
346+
return d.SimpleFS
347+
}
348+
343349
// GetStale returns the stale duration
344350
func (d *DefaultCache) GetStale() time.Duration {
345351
return d.Stale.Duration
@@ -382,6 +388,7 @@ type DefaultCacheInterface interface {
382388
GetHeaders() []string
383389
GetKey() Key
384390
GetRegex() Regex
391+
GetSimpleFS() CacheProvider
385392
GetStale() time.Duration
386393
GetStorers() []string
387394
GetTimeout() Timeout

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ go 1.22.1
55
require (
66
github.com/caddyserver/caddy/v2 v2.8.4
77
github.com/cespare/xxhash/v2 v2.2.0
8-
github.com/darkweak/storages/core v0.0.8
8+
github.com/darkweak/storages/core v0.0.11
99
github.com/google/uuid v1.6.0
1010
github.com/pierrec/lz4/v4 v4.1.21
1111
github.com/pquerna/cachecontrol v0.2.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
9898
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
9999
github.com/darkweak/go-esi v0.0.5 h1:b9LHI8Tz46R+i6p8avKPHAIBRQUCZDebNmKm5w/Zrns=
100100
github.com/darkweak/go-esi v0.0.5/go.mod h1:koCJqwum1u6mslyZuq/Phm6hfG1K3ZK5Y7jrUBTH654=
101-
github.com/darkweak/storages/core v0.0.8 h1:9e7rOxHiJwnvADDVCZ7LFRnUnOHGT+UMpNOFlR8BOiw=
102-
github.com/darkweak/storages/core v0.0.8/go.mod h1:ajTpB9IFLRIRY0EEFLjM5vtsrcNTh+TJK9yRxgG5/wY=
101+
github.com/darkweak/storages/core v0.0.11 h1:IwvpAtkhOmxC5pIffJ8opW6erpTnIi5zqPveiAQs8ew=
102+
github.com/darkweak/storages/core v0.0.11/go.mod h1:ajTpB9IFLRIRY0EEFLjM5vtsrcNTh+TJK9yRxgG5/wY=
103103
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
104104
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
105105
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

pkg/api/souin.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ var storageToInfiniteTTLMap = map[string]time.Duration{
158158
"OLRIC": types.OneYearDuration,
159159
"OTTER": types.OneYearDuration,
160160
"REDIS": -1,
161+
"SIMPLEFS": 0,
161162
types.DefaultStorageName: types.OneYearDuration,
162163
}
163164

@@ -305,7 +306,9 @@ func (s *SouinAPI) HandleRequest(w http.ResponseWriter, r *http.Request) {
305306
s.purgeMapping()
306307
} else {
307308
submatch := keysRg.FindAllStringSubmatch(r.RequestURI, -1)[0][1]
308-
s.BulkDelete(submatch, true)
309+
for _, current := range s.storers {
310+
current.DeleteMany(submatch)
311+
}
309312
}
310313
} else {
311314
ck, _ := s.surrogateStorage.Purge(r.Header)

pkg/middleware/middleware.go

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func NewHTTPCacheHandler(c configurationtypes.AbstractConfigurationInterface) *S
6767
storers := []types.Storer{}
6868
if len(storedStorers) != 0 {
6969
dc := c.GetDefaultCache()
70-
for _, s := range []string{dc.GetBadger().Uuid, dc.GetEtcd().Uuid, dc.GetNats().Uuid, dc.GetNuts().Uuid, dc.GetOlric().Uuid, dc.GetOtter().Uuid, dc.GetRedis().Uuid} {
70+
for _, s := range []string{dc.GetBadger().Uuid, dc.GetEtcd().Uuid, dc.GetNats().Uuid, dc.GetNuts().Uuid, dc.GetOlric().Uuid, dc.GetOtter().Uuid, dc.GetRedis().Uuid, dc.GetSimpleFS().Uuid} {
7171
if s != "" {
7272
if st := core.GetRegisteredStorer(s); st != nil {
7373
storers = append(storers, st.(types.Storer))
@@ -244,7 +244,7 @@ func (s *SouinBaseHandler) Store(
244244
ma = time.Duration(responseCc.SMaxAge) * time.Second
245245
} else if responseCc.MaxAge >= 0 {
246246
ma = time.Duration(responseCc.MaxAge) * time.Second
247-
} else if customWriter.Header().Get("Expires") != "" {
247+
} else if !modeContext.Bypass_response && customWriter.Header().Get("Expires") != "" {
248248
exp, err := time.Parse(time.RFC1123, customWriter.Header().Get("Expires"))
249249
if err != nil {
250250
return nil
@@ -569,7 +569,7 @@ func (s *SouinBaseHandler) ServeHTTP(rw http.ResponseWriter, rq *http.Request, n
569569

570570
req := s.context.SetBaseContext(rq)
571571
cacheName := req.Context().Value(context.CacheName).(string)
572-
if rq.Header.Get("Upgrade") == "websocket" || (s.ExcludeRegex != nil && s.ExcludeRegex.MatchString(rq.RequestURI)) {
572+
if rq.Header.Get("Upgrade") == "websocket" || rq.Header.Get("Accept") == "text/event-stream" || (s.ExcludeRegex != nil && s.ExcludeRegex.MatchString(rq.RequestURI)) {
573573
rw.Header().Set("Cache-Status", cacheName+"; fwd=bypass; detail=EXCLUDED-REQUEST-URI")
574574
return next(rw, req)
575575
}
@@ -673,13 +673,13 @@ func (s *SouinBaseHandler) ServeHTTP(rw http.ResponseWriter, rq *http.Request, n
673673
return nil
674674
}
675675

676-
if validator.NeedRevalidation {
676+
if !modeContext.Bypass_request && validator.NeedRevalidation {
677677
err := s.Revalidate(validator, next, customWriter, req, requestCc, cachedKey, uri)
678678
_, _ = customWriter.Send()
679679

680680
return err
681681
}
682-
if resCc, _ := cacheobject.ParseResponseCacheControl(rfc.HeaderAllCommaSepValuesString(response.Header, headerName)); resCc.NoCachePresent {
682+
if resCc, _ := cacheobject.ParseResponseCacheControl(rfc.HeaderAllCommaSepValuesString(response.Header, headerName)); !modeContext.Bypass_response && resCc.NoCachePresent {
683683
prometheus.Increment(prometheus.NoCachedResponseCounter)
684684
err := s.Revalidate(validator, next, customWriter, req, requestCc, cachedKey, uri)
685685
_, _ = customWriter.Send()
@@ -726,7 +726,7 @@ func (s *SouinBaseHandler) ServeHTTP(rw http.ResponseWriter, rq *http.Request, n
726726
return err
727727
}
728728

729-
if responseCc.MustRevalidate || responseCc.NoCachePresent || validator.NeedRevalidation {
729+
if modeContext.Bypass_response || responseCc.MustRevalidate || responseCc.NoCachePresent || validator.NeedRevalidation {
730730
req.Header["If-None-Match"] = append(req.Header["If-None-Match"], validator.ResponseETag)
731731
err := s.Revalidate(validator, next, customWriter, req, requestCc, cachedKey, uri)
732732
statusCode := customWriter.GetStatusCode()
@@ -737,6 +737,7 @@ func (s *SouinBaseHandler) ServeHTTP(rw http.ResponseWriter, rq *http.Request, n
737737
response.Header.Set("Cache-Status", response.Header.Get("Cache-Status")+code)
738738
maps.Copy(customWriter.Header(), response.Header)
739739
customWriter.WriteHeader(response.StatusCode)
740+
customWriter.Buf.Reset()
740741
_, _ = io.Copy(customWriter.Buf, response.Body)
741742
_, err := customWriter.Send()
742743

@@ -774,7 +775,7 @@ func (s *SouinBaseHandler) ServeHTTP(rw http.ResponseWriter, rq *http.Request, n
774775
return err
775776
}
776777

777-
if rfc.ValidateMaxAgeCachedStaleResponse(requestCc, response, int(addTime.Seconds())) != nil {
778+
if !modeContext.Strict || rfc.ValidateMaxAgeCachedStaleResponse(requestCc, responseCc, response, int(addTime.Seconds())) != nil {
778779
customWriter.WriteHeader(response.StatusCode)
779780
rfc.HitStaleCache(&response.Header)
780781
maps.Copy(customWriter.Header(), response.Header)
@@ -784,6 +785,47 @@ func (s *SouinBaseHandler) ServeHTTP(rw http.ResponseWriter, rq *http.Request, n
784785
return err
785786
}
786787
}
788+
} else if stale != nil {
789+
response := stale
790+
791+
if !modeContext.Strict {
792+
rfc.SetCacheStatusHeader(response, storerName)
793+
customWriter.WriteHeader(response.StatusCode)
794+
rfc.HitStaleCache(&response.Header)
795+
maps.Copy(customWriter.Header(), response.Header)
796+
_, _ = io.Copy(customWriter.Buf, response.Body)
797+
_, err := customWriter.Send()
798+
799+
return err
800+
}
801+
802+
addTime, _ := time.ParseDuration(response.Header.Get(rfc.StoredTTLHeader))
803+
responseCc, _ := cacheobject.ParseResponseCacheControl(rfc.HeaderAllCommaSepValuesString(response.Header, "Cache-Control"))
804+
805+
if !modeContext.Strict || rfc.ValidateMaxAgeCachedStaleResponse(requestCc, responseCc, response, int(addTime.Seconds())) != nil {
806+
_, _ = time.ParseDuration(response.Header.Get(rfc.StoredTTLHeader))
807+
rfc.SetCacheStatusHeader(response, storerName)
808+
809+
responseCc, _ := cacheobject.ParseResponseCacheControl(rfc.HeaderAllCommaSepValuesString(response.Header, "Cache-Control"))
810+
811+
if responseCc.StaleIfError > -1 || requestCc.StaleIfError > 0 {
812+
err := s.Revalidate(validator, next, customWriter, req, requestCc, cachedKey, uri)
813+
statusCode := customWriter.GetStatusCode()
814+
if err != nil {
815+
code := fmt.Sprintf("; fwd-status=%d", statusCode)
816+
rfc.HitStaleCache(&response.Header)
817+
response.Header.Set("Cache-Status", response.Header.Get("Cache-Status")+code)
818+
maps.Copy(customWriter.Header(), response.Header)
819+
customWriter.WriteHeader(response.StatusCode)
820+
customWriter.Buf.Reset()
821+
_, _ = io.Copy(customWriter.Buf, response.Body)
822+
_, err := customWriter.Send()
823+
824+
return err
825+
}
826+
}
827+
828+
}
787829
}
788830
}
789831

pkg/rfc/age.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,25 @@ func ValidateMaxAgeCachedResponse(co *cacheobject.RequestCacheDirectives, res *h
3131
return validateMaxAgeCachedResponse(res, int(ma), 0)
3232
}
3333

34-
func ValidateMaxAgeCachedStaleResponse(co *cacheobject.RequestCacheDirectives, res *http.Response, addTime int) *http.Response {
34+
func ValidateMaxAgeCachedStaleResponse(co *cacheobject.RequestCacheDirectives, resCo *cacheobject.ResponseCacheDirectives, res *http.Response, addTime int) *http.Response {
3535
if co.MaxStaleSet {
3636
return res
3737
}
3838

39+
if resCo != nil && (resCo.StaleIfError > -1 || co.StaleIfError > 0) {
40+
if resCo.StaleIfError > -1 {
41+
if response := validateMaxAgeCachedResponse(res, int(resCo.StaleIfError), addTime); response != nil {
42+
return response
43+
}
44+
}
45+
46+
if co.StaleIfError > 0 {
47+
if response := validateMaxAgeCachedResponse(res, int(co.StaleIfError), addTime); response != nil {
48+
return response
49+
}
50+
}
51+
}
52+
3953
if co.MaxStale < 0 {
4054
return nil
4155
}

pkg/rfc/age_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,20 @@ func Test_ValidateMaxStaleCachedResponse(t *testing.T) {
6363
},
6464
}
6565

66-
if ValidateMaxAgeCachedStaleResponse(&coWithoutMaxStale, &expiredMaxAge, 3) != nil {
66+
if ValidateMaxAgeCachedStaleResponse(&coWithoutMaxStale, nil, &expiredMaxAge, 3) != nil {
6767
t.Errorf("The max-stale validation should return nil instead of the response with the given parameters:\nRequestCacheDirectives: %+v\nResponse: %+v\n", coWithoutMaxStale, expiredMaxAge)
6868
}
69-
if ValidateMaxAgeCachedStaleResponse(&coWithoutMaxStale, &validMaxAge, 14) != nil {
69+
if ValidateMaxAgeCachedStaleResponse(&coWithoutMaxStale, nil, &validMaxAge, 14) != nil {
7070
t.Errorf("The max-stale validation should return the response instead of nil with the given parameters:\nRequestCacheDirectives: %+v\nResponse: %+v\n", coWithoutMaxStale, validMaxAge)
7171
}
7272

73-
if ValidateMaxAgeCachedStaleResponse(&coWithMaxStale, &expiredMaxAge, 0) != nil {
73+
if ValidateMaxAgeCachedStaleResponse(&coWithMaxStale, nil, &expiredMaxAge, 0) != nil {
7474
t.Errorf("The max-stale validation should return nil instead of the response with the given parameters:\nRequestCacheDirectives: %+v\nResponse: %+v\n", coWithMaxStale, expiredMaxAge)
7575
}
76-
if ValidateMaxAgeCachedStaleResponse(&coWithMaxStaleSet, &expiredMaxAge, 0) == nil {
76+
if ValidateMaxAgeCachedStaleResponse(&coWithMaxStaleSet, nil, &expiredMaxAge, 0) == nil {
7777
t.Errorf("The max-stale validation should return the response instead of nil with the given parameters:\nRequestCacheDirectives: %+v\nResponse: %+v\n", coWithMaxStaleSet, expiredMaxAge)
7878
}
79-
if ValidateMaxAgeCachedStaleResponse(&coWithMaxStale, &validMaxAge, 5) == nil {
79+
if ValidateMaxAgeCachedStaleResponse(&coWithMaxStale, nil, &validMaxAge, 5) == nil {
8080
t.Errorf("The max-stale validation should return the response instead of nil with the given parameters:\nRequestCacheDirectives: %+v\nResponse: %+v\n", coWithMaxStale, expiredMaxAge)
8181
}
8282
}

pkg/surrogate/providers/common.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,17 @@ var storageToInfiniteTTLMap = map[string]time.Duration{
3737
"OLRIC": types.OneYearDuration,
3838
"OTTER": types.OneYearDuration,
3939
"REDIS": -1,
40+
"SIMPLEFS": 0,
4041
types.DefaultStorageName: types.OneYearDuration,
4142
}
4243

4344
func (s *baseStorage) ParseHeaders(value string) []string {
44-
return strings.Split(value, s.parent.getHeaderSeparator())
45+
res := strings.Split(value, s.parent.getHeaderSeparator())
46+
for i, v := range res {
47+
res[i] = strings.TrimSpace(v)
48+
}
49+
50+
return res
4551
}
4652

4753
func getCandidateHeader(header http.Header, getCandidates func() []string) (string, string) {

plugins/beego/go.mod

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ toolchain go1.22.4
77
require (
88
github.com/beego/beego/v2 v2.1.1
99
github.com/darkweak/souin v1.7.2
10-
github.com/darkweak/souin/plugins/souin v0.0.0-00010101000000-000000000000
11-
github.com/darkweak/souin/plugins/souin/storages v0.0.0-00010101000000-000000000000
10+
github.com/darkweak/souin/plugins/souin v1.7.2
11+
github.com/darkweak/souin/plugins/souin/storages v1.7.2
1212
)
1313

1414
require (
@@ -41,7 +41,7 @@ require (
4141
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
4242
github.com/darkweak/go-esi v0.0.5 // indirect
4343
github.com/darkweak/storages/badger v0.0.8 // indirect
44-
github.com/darkweak/storages/core v0.0.8 // indirect
44+
github.com/darkweak/storages/core v0.0.11 // indirect
4545
github.com/darkweak/storages/etcd v0.0.8 // indirect
4646
github.com/darkweak/storages/nats v0.0.8 // indirect
4747
github.com/darkweak/storages/nuts v0.0.8 // indirect
@@ -186,5 +186,4 @@ require (
186186
replace (
187187
github.com/darkweak/souin v1.7.2 => ../..
188188
github.com/darkweak/souin/plugins/souin => ../souin
189-
github.com/darkweak/souin/plugins/souin/storages => ../souin/storages
190189
)

plugins/beego/go.sum

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,12 @@ github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
141141
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
142142
github.com/darkweak/go-esi v0.0.5 h1:b9LHI8Tz46R+i6p8avKPHAIBRQUCZDebNmKm5w/Zrns=
143143
github.com/darkweak/go-esi v0.0.5/go.mod h1:koCJqwum1u6mslyZuq/Phm6hfG1K3ZK5Y7jrUBTH654=
144+
github.com/darkweak/souin/plugins/souin/storages v1.7.2 h1:vA1oFap6sbWO+Ebbq6NGtjmCFuCRJOZeG+XXPhhSIWA=
145+
github.com/darkweak/souin/plugins/souin/storages v1.7.2/go.mod h1:VfkwGN+ubAuluSwbjGHqImbUjxdEA0N9xGJUTCcFBV0=
144146
github.com/darkweak/storages/badger v0.0.8 h1:rKVXrasVA74xgiqGRgW0kH11NUIlWwn9HiFyHUok85k=
145147
github.com/darkweak/storages/badger v0.0.8/go.mod h1:ZmrNmKkFzyu/B3+1nsvVeTvyg2I2mOV5yTpT46mZ06o=
146-
github.com/darkweak/storages/core v0.0.8 h1:9e7rOxHiJwnvADDVCZ7LFRnUnOHGT+UMpNOFlR8BOiw=
147-
github.com/darkweak/storages/core v0.0.8/go.mod h1:ajTpB9IFLRIRY0EEFLjM5vtsrcNTh+TJK9yRxgG5/wY=
148+
github.com/darkweak/storages/core v0.0.11 h1:IwvpAtkhOmxC5pIffJ8opW6erpTnIi5zqPveiAQs8ew=
149+
github.com/darkweak/storages/core v0.0.11/go.mod h1:ajTpB9IFLRIRY0EEFLjM5vtsrcNTh+TJK9yRxgG5/wY=
148150
github.com/darkweak/storages/etcd v0.0.8 h1:Guzv6zgxkQJLjak36KsbtQqkmwMRJoZZI0B7ztZKIik=
149151
github.com/darkweak/storages/etcd v0.0.8/go.mod h1:Yw9xJramKAzIRoC7tizVMYPSwUBHqxY5BPTh8OgyISY=
150152
github.com/darkweak/storages/nats v0.0.8 h1:HRS3i2zzzIq1Qb3yoOUWD6MoRQgGV1NbECF1ex4wZjg=

0 commit comments

Comments
 (0)