Skip to content

Commit

Permalink
fix(traefik): resolves #558, full rewrite to match the actual cache b…
Browse files Browse the repository at this point in the history
…ehavior. Yaegi sucks!
  • Loading branch information
darkweak committed Oct 27, 2024
1 parent bbff56e commit 2cc58c1
Show file tree
Hide file tree
Showing 31 changed files with 1,431 additions and 539 deletions.
6 changes: 3 additions & 3 deletions plugins/traefik/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,13 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/darkweak/go-esi v0.0.5
github.com/darkweak/go-esi v0.0.5 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/golang/glog v1.2.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/google/uuid v1.6.0
github.com/imdario/mergo v0.3.13 // indirect
github.com/klauspost/compress v1.17.8 // indirect
github.com/miekg/dns v1.1.59 // indirect
Expand All @@ -115,7 +115,7 @@ require (
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sync v0.7.0
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
golang.org/x/tools v0.21.0 // indirect
Expand Down
18 changes: 12 additions & 6 deletions plugins/traefik/override/configurationtypes/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,10 @@ type URL struct {

// CacheProvider config
type CacheProvider struct {
// Uuid to identify a unique instance.
Uuid string
// Found to determine if we can use that storage.
Found bool `json:"found" yaml:"found"`
// URL to connect to the storage system.
URL string `json:"url" yaml:"url"`
// Path to the configuration file.
Expand Down Expand Up @@ -247,7 +251,7 @@ type DefaultCache struct {
Timeout Timeout `json:"timeout" yaml:"timeout"`
TTL Duration `json:"ttl" yaml:"ttl"`
DefaultCacheControl string `json:"default_cache_control" yaml:"default_cache_control"`
MaxBodyBytes uint64 `json:"max_cachable_body_bytes" yaml:"max_cachable_body_bytes"`
MaxBodyBytes uint64 `json:"max_cacheable_body_bytes" yaml:"max_cacheable_body_bytes"`
DisableCoalescing bool `json:"disable_coalescing" yaml:"disable_coalescing"`
}

Expand Down Expand Up @@ -326,11 +330,6 @@ func (d *DefaultCache) GetRegex() Regex {
return d.Regex
}

// GetSimpleFS returns simpleFS configuration
func (d *DefaultCache) GetSimpleFS() CacheProvider {
return d.SimpleFS
}

// GetTimeout returns the backend and cache timeouts
func (d *DefaultCache) GetTimeout() Timeout {
return d.Timeout
Expand All @@ -341,6 +340,11 @@ func (d *DefaultCache) GetTTL() time.Duration {
return d.TTL.Duration
}

// GetSimpleFS returns simplefs configuration
func (d *DefaultCache) GetSimpleFS() CacheProvider {
return d.SimpleFS
}

// GetStale returns the stale duration
func (d *DefaultCache) GetStale() time.Duration {
return d.Stale.Duration
Expand Down Expand Up @@ -376,6 +380,7 @@ type DefaultCacheInterface interface {
GetEtcd() CacheProvider
GetMode() string
GetOtter() CacheProvider
GetNats() CacheProvider
GetNuts() CacheProvider
GetOlric() CacheProvider
GetRedis() CacheProvider
Expand All @@ -389,6 +394,7 @@ type DefaultCacheInterface interface {
GetTTL() time.Duration
GetDefaultCacheControl() string
GetMaxBodyBytes() uint64
IsCoalescingDisable() bool
}

// APIEndpoint is the minimal structure to define an endpoint
Expand Down
4 changes: 4 additions & 0 deletions plugins/traefik/override/context/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ type cacheContext struct {
cacheName string
}

func (*cacheContext) SetContextWithBaseRequest(req *http.Request, _ *http.Request) *http.Request {
return req
}

func (cc *cacheContext) SetupContext(c configurationtypes.AbstractConfigurationInterface) {
cc.cacheName = defaultCacheName
if c.GetDefaultCache().GetCacheName() != "" {
Expand Down
26 changes: 26 additions & 0 deletions plugins/traefik/override/context/graphql.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,32 @@ type graphQLContext struct {
custom bool
}

func (g *graphQLContext) SetContextWithBaseRequest(req *http.Request, baseRq *http.Request) *http.Request {
ctx := req.Context()
ctx = context.WithValue(ctx, GraphQL, g.custom)
ctx = context.WithValue(ctx, HashBody, "")
ctx = context.WithValue(ctx, IsMutationRequest, false)

if g.custom && req.Body != nil {
b := bytes.NewBuffer([]byte{})
_, _ = io.Copy(b, req.Body)
req.Body = io.NopCloser(b)
baseRq.Body = io.NopCloser(b)

if b.Len() > 0 {
if isMutation(b.Bytes()) {
ctx = context.WithValue(ctx, IsMutationRequest, true)
} else {
h := sha256.New()
h.Write(b.Bytes())
ctx = context.WithValue(ctx, HashBody, fmt.Sprintf("-%x", h.Sum(nil)))
}
}
}

return req.WithContext(ctx)
}

func (g *graphQLContext) SetupContext(c configurationtypes.AbstractConfigurationInterface) {
if len(c.GetDefaultCache().GetAllowedHTTPVerbs()) != 0 {
g.custom = true
Expand Down
128 changes: 68 additions & 60 deletions plugins/traefik/override/context/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const (
Key ctxKey = "souin_ctx.CACHE_KEY"
DisplayableKey ctxKey = "souin_ctx.DISPLAYABLE_KEY"
IgnoredHeaders ctxKey = "souin_ctx.IGNORE_HEADERS"
Hashed ctxKey = "souin_ctx.HASHED"
)

type keyContext struct {
Expand All @@ -20,10 +21,17 @@ type keyContext struct {
disable_method bool
disable_query bool
disable_scheme bool
hash bool
displayable bool
hash bool
headers []string
template string
overrides []map[*regexp.Regexp]keyContext

initializer func(r *http.Request) *http.Request
}

func (*keyContext) SetContextWithBaseRequest(req *http.Request, _ *http.Request) *http.Request {
return req
}

func (g *keyContext) SetupContext(c configurationtypes.AbstractConfigurationInterface) {
Expand All @@ -35,89 +43,76 @@ func (g *keyContext) SetupContext(c configurationtypes.AbstractConfigurationInte
g.disable_scheme = k.DisableScheme
g.hash = k.Hash
g.displayable = !k.Hide
g.template = k.Template
g.headers = k.Headers

g.overrides = make([]map[*regexp.Regexp]keyContext, 0)

for _, cacheKey := range c.GetCacheKeys() {
for r, v := range cacheKey {
g.overrides = append(g.overrides, map[*regexp.Regexp]keyContext{r.Regexp: {
disable_body: v.DisableBody,
disable_host: v.DisableHost,
disable_method: v.DisableMethod,
disable_query: v.DisableQuery,
disable_scheme: v.DisableScheme,
hash: v.Hash,
displayable: !v.Hide,
headers: v.Headers,
}})
}
// for _, cacheKey := range c.GetCacheKeys() {
// for r, v := range cacheKey {
// g.overrides = append(g.overrides, map[*regexp.Regexp]keyContext{r.Regexp: {
// disable_body: v.DisableBody,
// disable_host: v.DisableHost,
// disable_method: v.DisableMethod,
// disable_query: v.DisableQuery,
// disable_scheme: v.DisableScheme,
// hash: v.Hash,
// displayable: !v.Hide,
// template: v.Template,
// headers: v.Headers,
// }})
// }
// }

g.initializer = func(r *http.Request) *http.Request {
return r
}
}

func (g *keyContext) SetContext(req *http.Request) *http.Request {
key := req.URL.Path
var headers []string
func parseKeyInformations(req *http.Request, kCtx keyContext) (query, body, host, scheme, method, headerValues string, headers []string, displayable, hash bool) {
displayable = kCtx.displayable
hash = kCtx.hash

scheme := "http-"
if req.TLS != nil {
scheme = "https-"
}
query := ""
body := ""
host := ""
method := ""
headerValues := ""
displayable := g.displayable

if !g.disable_query && len(req.URL.RawQuery) > 0 {
if !kCtx.disable_query && len(req.URL.RawQuery) > 0 {
query += "?" + req.URL.RawQuery
}

if !g.disable_body {
if !kCtx.disable_body {
body = req.Context().Value(HashBody).(string)
}

if !g.disable_host {
if !kCtx.disable_host {
host = req.Host + "-"
}

if !g.disable_method {
if !kCtx.disable_scheme {
scheme = "http-"
if req.TLS != nil {
scheme = "https-"
}
}

if !kCtx.disable_method {
method = req.Method + "-"
}

headers = g.headers
for _, hn := range g.headers {
headers = kCtx.headers
for _, hn := range kCtx.headers {
headerValues += "-" + req.Header.Get(hn)
}

return
}

func (g *keyContext) computeKey(req *http.Request) (key string, headers []string, hash, displayable bool) {
key = req.URL.Path
query, body, host, scheme, method, headerValues, headers, displayable, hash := parseKeyInformations(req, *g)

hasOverride := false
for _, current := range g.overrides {
for k, v := range current {
if k.MatchString(req.RequestURI) {
displayable = v.displayable
host = ""
method = ""
query = ""
if !v.disable_query && len(req.URL.RawQuery) > 0 {
query = "?" + req.URL.RawQuery
}
if !v.disable_body {
body = req.Context().Value(HashBody).(string)
}
if !v.disable_method {
method = req.Method + "-"
}
if !v.disable_host {
host = req.Host + "-"
}
if len(v.headers) > 0 {
headerValues = ""
for _, hn := range v.headers {
headers = v.headers
headerValues += "-" + req.Header.Get(hn)
}
}
query, body, host, scheme, method, headerValues, headers, displayable, hash = parseKeyInformations(req, v)
hasOverride = true
break
}
Expand All @@ -128,13 +123,26 @@ func (g *keyContext) SetContext(req *http.Request) *http.Request {
}
}

key = method + scheme + host + key + query + body + headerValues

return
}

func (g *keyContext) SetContext(req *http.Request) *http.Request {
rq := g.initializer(req)
key, headers, hash, displayable := g.computeKey(rq)

return req.WithContext(
context.WithValue(
context.WithValue(
context.WithValue(
req.Context(),
Key,
method+scheme+host+key+query+body+headerValues,
context.WithValue(
req.Context(),
Key,
key,
),
Hashed,
hash,
),
IgnoredHeaders,
headers,
Expand Down
4 changes: 4 additions & 0 deletions plugins/traefik/override/context/method.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ type methodContext struct {
custom bool
}

func (*methodContext) SetContextWithBaseRequest(req *http.Request, _ *http.Request) *http.Request {
return req
}

func (m *methodContext) SetupContext(c configurationtypes.AbstractConfigurationInterface) {
m.allowedVerbs = defaultVerbs
if len(c.GetDefaultCache().GetAllowedHTTPVerbs()) != 0 {
Expand Down
6 changes: 5 additions & 1 deletion plugins/traefik/override/context/mode.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ type ModeContext struct {
Strict, Bypass_request, Bypass_response bool
}

func (*ModeContext) SetContextWithBaseRequest(req *http.Request, _ *http.Request) *http.Request {
return req
}

func (mc *ModeContext) SetupContext(c configurationtypes.AbstractConfigurationInterface) {
mode := c.GetDefaultCache().GetMode()
mc.Bypass_request = mode == "bypass" || mode == "bypass_request"
Expand All @@ -24,4 +28,4 @@ func (mc *ModeContext) SetContext(req *http.Request) *http.Request {
return req.WithContext(context.WithValue(req.Context(), Mode, mc))
}

var _ ctx = (*cacheContext)(nil)
var _ ctx = (*ModeContext)(nil)
4 changes: 4 additions & 0 deletions plugins/traefik/override/context/now.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ const Now ctxKey = "souin_ctx.NOW"

type nowContext struct{}

func (*nowContext) SetContextWithBaseRequest(req *http.Request, _ *http.Request) *http.Request {
return req
}

func (cc *nowContext) SetupContext(_ configurationtypes.AbstractConfigurationInterface) {}

func (cc *nowContext) SetContext(req *http.Request) *http.Request {
Expand Down
6 changes: 5 additions & 1 deletion plugins/traefik/override/context/timeout.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ type timeoutContext struct {
timeoutCache, timeoutBackend time.Duration
}

func (*timeoutContext) SetContextWithBaseRequest(req *http.Request, _ *http.Request) *http.Request {
return req
}

func (t *timeoutContext) SetupContext(c configurationtypes.AbstractConfigurationInterface) {
t.timeoutBackend = defaultTimeoutBackend
t.timeoutCache = defaultTimeoutCache
Expand All @@ -38,4 +42,4 @@ func (t *timeoutContext) SetContext(req *http.Request) *http.Request {
return req.WithContext(context.WithValue(context.WithValue(ctx, TimeoutCancel, cancel), TimeoutCache, t.timeoutCache))
}

var _ ctx = (*cacheContext)(nil)
var _ ctx = (*timeoutContext)(nil)
5 changes: 3 additions & 2 deletions plugins/traefik/override/context/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type (
ctx interface {
SetupContext(c configurationtypes.AbstractConfigurationInterface)
SetContext(req *http.Request) *http.Request
SetContextWithBaseRequest(req *http.Request, baseRq *http.Request) *http.Request
}

Context struct {
Expand Down Expand Up @@ -53,6 +54,6 @@ func (c *Context) SetBaseContext(req *http.Request) *http.Request {
return c.Mode.SetContext(c.Timeout.SetContext(c.Method.SetContext(c.CacheName.SetContext(c.Now.SetContext(req)))))
}

func (c *Context) SetContext(req *http.Request) *http.Request {
return c.Key.SetContext(c.GraphQL.SetContext(req))
func (c *Context) SetContext(req *http.Request, baseRq *http.Request) *http.Request {
return c.Key.SetContext(c.GraphQL.SetContextWithBaseRequest(req, baseRq))
}
Loading

0 comments on commit 2cc58c1

Please sign in to comment.