Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(configuration): extends with allowed_addional_status_code #577

Merged
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -106,6 +106,9 @@ default_cache:
- GET
- POST
- HEAD
allowed_addional_status_code: # Allowed additional HTTP status code to cache.
- 202
- 400
cache_name: Souin # Override the cache name to use in the Cache-Status header
distributed: true # Use Olric or Etcd distributed storage
key:
@@ -196,6 +199,7 @@ surrogate_keys:
| `cdn.service_id` | The service id if required, depending the provider | `123456_id` |
| `cdn.zone_id` | The zone id if required, depending the provider | `anywhere_zone` |
| `default_cache.allowed_http_verbs` | The HTTP verbs to support cache | `- GET`<br/><br/>`- POST`<br/><br/>`(default: GET, HEAD)` |
| `default_cache.allowed_addional_status_code` | The additional HTTP status code to support cache | `- 200`<br/><br/>`- 404` |
| `default_cache.badger` | Configure the Badger cache storage | |
| `default_cache.badger.path` | Configure Badger with a file | `/anywhere/badger_configuration.json` |
| `default_cache.badger.configuration` | Configure Badger directly in the Caddyfile or your JSON caddy configuration | [See the Badger configuration for the options](https://dgraph.io/docs/badger/get-started/) |
@@ -425,6 +429,7 @@ There is the fully configuration below
}
cache {
allowed_http_verbs GET POST PATCH
allowed_addional_status_code 202
api {
basepath /some-basepath
prometheus {
@@ -882,6 +887,9 @@ http:
- GET
- POST
- HEAD
allowed_addional_status_code:
- 202
- 400
cdn:
api_key: XXXX
dynamic: true
@@ -979,6 +987,9 @@ http:
- GET
- HEAD
- POST
allowed_addional_status_code:
- 202
- 400
default_cache_control: no-store
log_level: debug
urls:
3 changes: 3 additions & 0 deletions configuration/configuration.sample.yml
Original file line number Diff line number Diff line change
@@ -18,6 +18,9 @@ default_cache: # Required part
- GET
- POST
- HEAD
allowed_addional_status_code: # Allowed additional HTTP status code to cache.
- 202
- 400
cache_name: Souin # Override the Cache-Status name
distributed: true # Use Olric distributed storage
headers: # Default headers concatenated in stored keys
55 changes: 31 additions & 24 deletions configurationtypes/types.go
Original file line number Diff line number Diff line change
@@ -230,37 +230,43 @@ type Key struct {

// DefaultCache configuration
type DefaultCache struct {
AllowedHTTPVerbs []string `json:"allowed_http_verbs" yaml:"allowed_http_verbs"`
Badger CacheProvider `json:"badger" yaml:"badger"`
CDN CDN `json:"cdn" yaml:"cdn"`
CacheName string `json:"cache_name" yaml:"cache_name"`
Distributed bool `json:"distributed" yaml:"distributed"`
Headers []string `json:"headers" yaml:"headers"`
Key Key `json:"key" yaml:"key"`
Etcd CacheProvider `json:"etcd" yaml:"etcd"`
Mode string `json:"mode" yaml:"mode"`
Nats CacheProvider `json:"nats" yaml:"nats"`
Nuts CacheProvider `json:"nuts" yaml:"nuts"`
Olric CacheProvider `json:"olric" yaml:"olric"`
Otter CacheProvider `json:"otter" yaml:"otter"`
Redis CacheProvider `json:"redis" yaml:"redis"`
Port Port `json:"port" yaml:"port"`
Regex Regex `json:"regex" yaml:"regex"`
SimpleFS CacheProvider `json:"simplefs" yaml:"simplefs"`
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"`
MaxBodyBytes uint64 `json:"max_cacheable_body_bytes" yaml:"max_cacheable_body_bytes"`
DisableCoalescing bool `json:"disable_coalescing" yaml:"disable_coalescing"`
AllowedHTTPVerbs []string `json:"allowed_http_verbs" yaml:"allowed_http_verbs"`
AllowedAdditionalStatusCodes []int `json:"allowed_additional_status_codes" yaml:"allowed_additional_status_codes"`
Badger CacheProvider `json:"badger" yaml:"badger"`
CDN CDN `json:"cdn" yaml:"cdn"`
CacheName string `json:"cache_name" yaml:"cache_name"`
Distributed bool `json:"distributed" yaml:"distributed"`
Headers []string `json:"headers" yaml:"headers"`
Key Key `json:"key" yaml:"key"`
Etcd CacheProvider `json:"etcd" yaml:"etcd"`
Mode string `json:"mode" yaml:"mode"`
Nats CacheProvider `json:"nats" yaml:"nats"`
Nuts CacheProvider `json:"nuts" yaml:"nuts"`
Olric CacheProvider `json:"olric" yaml:"olric"`
Otter CacheProvider `json:"otter" yaml:"otter"`
Redis CacheProvider `json:"redis" yaml:"redis"`
Port Port `json:"port" yaml:"port"`
Regex Regex `json:"regex" yaml:"regex"`
SimpleFS CacheProvider `json:"simplefs" yaml:"simplefs"`
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"`
MaxBodyBytes uint64 `json:"max_cacheable_body_bytes" yaml:"max_cacheable_body_bytes"`
DisableCoalescing bool `json:"disable_coalescing" yaml:"disable_coalescing"`
}

// GetAllowedHTTPVerbs returns the allowed verbs to cache
func (d *DefaultCache) GetAllowedHTTPVerbs() []string {
return d.AllowedHTTPVerbs
}

// GetAllowedAdditionalStatusCodes returns the allowed verbs to cache
func (d *DefaultCache) GetAllowedAdditionalStatusCodes() []int {
return d.AllowedAdditionalStatusCodes
}

// GetBadger returns the Badger configuration
func (d *DefaultCache) GetBadger() CacheProvider {
return d.Badger
@@ -374,6 +380,7 @@ func (d *DefaultCache) IsCoalescingDisable() bool {
// DefaultCacheInterface interface
type DefaultCacheInterface interface {
GetAllowedHTTPVerbs() []string
GetAllowedAdditionalStatusCodes() []int
GetBadger() CacheProvider
GetCacheName() string
GetCDN() CDN
4 changes: 4 additions & 0 deletions docs/website/content/docs/configuration.md
Original file line number Diff line number Diff line change
@@ -122,6 +122,10 @@ The default_cache prefix configure the default cache behavior. (e.g. `default_ca
The allowed_http_verbs prefix configure the HTTP verbs allowed to get cached. (e.g. `default_cache.allowed_http_verbs`).
default: `[GET, HEAD]`

#### Allowed additional status code
The allowed_addional_status_code prefix configure the additional HTTP status codes allowed to get cached. (e.g. `default_cache.allowed_addional_status_code`).
default: `[]`

#### Badger
The badger prefix configure the badger storage. (e.g. `default_cache.badger`).

16 changes: 13 additions & 3 deletions pkg/middleware/middleware.go
Original file line number Diff line number Diff line change
@@ -204,6 +204,16 @@ func canBypassAuthorizationRestriction(headers http.Header, bypassed []string) b
return strings.Contains(strings.ToLower(headers.Get("Vary")), "authorization")
}

func (s *SouinBaseHandler) hasAllowedAdditionalStatusCodesToCache(code int) bool {
for _, sc := range s.Configuration.GetDefaultCache().GetAllowedAdditionalStatusCodes() {
if sc == code {
return true
}
}

return false
}

func (s *SouinBaseHandler) Store(
customWriter *CustomWriter,
rq *http.Request,
@@ -212,7 +222,7 @@ func (s *SouinBaseHandler) Store(
uri string,
) error {
statusCode := customWriter.GetStatusCode()
if !isCacheableCode(statusCode) {
if !isCacheableCode(statusCode) && !s.hasAllowedAdditionalStatusCodesToCache(statusCode) {
customWriter.Header().Set("Cache-Status", fmt.Sprintf("%s; fwd=uri-miss; key=%s; detail=UNCACHEABLE-STATUS-CODE", rq.Context().Value(context.CacheName), rfc.GetCacheKeyFromCtx(rq.Context())))

switch statusCode {
@@ -323,7 +333,7 @@ func (s *SouinBaseHandler) Store(
}
res.Header.Set(rfc.StoredLengthHeader, res.Header.Get("Content-Length"))
response, err := httputil.DumpResponse(&res, true)
if err == nil && (bLen > 0 || canStatusCodeEmptyContent(statusCode)) {
if err == nil && (bLen > 0 || canStatusCodeEmptyContent(statusCode) || s.hasAllowedAdditionalStatusCodesToCache(statusCode)) {
variedHeaders, isVaryStar := rfc.VariedHeaderAllCommaSepValues(res.Header)
if isVaryStar {
// "Implies that the response is uncacheable"
@@ -442,7 +452,7 @@ func (s *SouinBaseHandler) Upstream(
s.SurrogateKeyStorer.Invalidate(rq.Method, customWriter.Header())

statusCode := customWriter.GetStatusCode()
if !isCacheableCode(statusCode) {
if !isCacheableCode(statusCode) && !s.hasAllowedAdditionalStatusCodesToCache(statusCode) {
customWriter.Header().Set("Cache-Status", fmt.Sprintf("%s; fwd=uri-miss; key=%s; detail=UNCACHEABLE-STATUS-CODE", rq.Context().Value(context.CacheName), rfc.GetCacheKeyFromCtx(rq.Context())))

switch statusCode {
4 changes: 3 additions & 1 deletion plugins/beego/go.mod
Original file line number Diff line number Diff line change
@@ -48,6 +48,7 @@ require (
github.com/darkweak/storages/olric v0.0.8 // indirect
github.com/darkweak/storages/otter v0.0.8 // indirect
github.com/darkweak/storages/redis v0.0.8 // indirect
github.com/darkweak/storages/simplefs v0.0.11 // indirect
github.com/dgraph-io/badger v1.6.2 // indirect
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
github.com/dgraph-io/badger/v3 v3.2103.5 // indirect
@@ -94,6 +95,7 @@ require (
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgtype v1.14.0 // indirect
github.com/jackc/pgx/v4 v4.18.3 // indirect
github.com/jellydator/ttlcache/v3 v3.3.0 // indirect
github.com/klauspost/compress v1.17.8 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/libdns/libdns v0.2.2 // indirect
@@ -168,7 +170,7 @@ require (
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // 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.8.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/term v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
8 changes: 6 additions & 2 deletions plugins/beego/go.sum
Original file line number Diff line number Diff line change
@@ -157,6 +157,8 @@ github.com/darkweak/storages/otter v0.0.8 h1:Tsv4NiLAiZyvovs4oCWT+WQUYe5YvbFvEx2
github.com/darkweak/storages/otter v0.0.8/go.mod h1:BBYxyWClX3PFdbvns6W95kLNNihq1FxljBYGIzP4snI=
github.com/darkweak/storages/redis v0.0.8 h1:0CHLkImyaI/sYs+IOurYLAxFkrmz5dFblhfpF7oGhQc=
github.com/darkweak/storages/redis v0.0.8/go.mod h1:pypJ5T3hweQWfHzFUjmZWeb1KaNK3ikNg1+rn0G+rD0=
github.com/darkweak/storages/simplefs v0.0.11 h1:BagJxTJVtWCnCsQi4kMuJdHGN8LHzARAEEiQ1WJYJl4=
github.com/darkweak/storages/simplefs v0.0.11/go.mod h1:FegezzdPj5m3ExDea64WxcDxPz7dFdu8G5WoIaYfbLM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -384,6 +386,8 @@ github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc=
github.com/jellydator/ttlcache/v3 v3.3.0/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -770,8 +774,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
1 change: 1 addition & 0 deletions plugins/caddy/README.md
Original file line number Diff line number Diff line change
@@ -354,6 +354,7 @@ What does these directives mean?
| Key | Description | Value example |
|:------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------|
| `allowed_http_verbs` | The HTTP verbs allowed to be cached | `GET POST PATCH`<br/><br/>`(default: GET HEAD)` |
| `allowed_addional_status_code` | The additional HTTP status codes allowed to be cached | `202 400` |
| `api` | The cache-handler API cache management | |
| `api.basepath` | BasePath for all APIs to avoid conflicts | `/your-non-conflict-route`<br/><br/>`(default: /souin-api)` |
| `api.prometheus` | Enable the Prometheus metrics | |
18 changes: 18 additions & 0 deletions plugins/caddy/configuration.go
Original file line number Diff line number Diff line change
@@ -15,6 +15,8 @@ import (
type DefaultCache struct {
// Allowed HTTP verbs to be cached by the system.
AllowedHTTPVerbs []string `json:"allowed_http_verbs"`
// Allowed additional status code to be cached by the system.
AllowedAdditionalStatusCodes []int `json:"allowed_additional_status_codes"`
// Badger provider configuration.
Badger configurationtypes.CacheProvider `json:"badger"`
// The cache name to use in the Cache-Status response header.
@@ -65,6 +67,11 @@ func (d *DefaultCache) GetAllowedHTTPVerbs() []string {
return d.AllowedHTTPVerbs
}

// GetAllowedAdditionalStatusCodes returns the allowed verbs to cache
func (d *DefaultCache) GetAllowedAdditionalStatusCodes() []int {
return d.AllowedAdditionalStatusCodes
}

// GetBadger returns the Badger configuration
func (d *DefaultCache) GetBadger() configurationtypes.CacheProvider {
return d.Badger
@@ -364,6 +371,17 @@ func parseConfiguration(cfg *Configuration, h *caddyfile.Dispenser, isGlobal boo
allowed := cfg.DefaultCache.AllowedHTTPVerbs
allowed = append(allowed, h.RemainingArgs()...)
cfg.DefaultCache.AllowedHTTPVerbs = allowed
case "allowed_additional_status_codes":
allowed := cfg.DefaultCache.AllowedAdditionalStatusCodes
additional := h.RemainingArgs()
codes := make([]int, 0)
for _, code := range additional {
if c, err := strconv.Atoi(code); err == nil {
codes = append(codes, c)
}
}
allowed = append(allowed, codes...)
cfg.DefaultCache.AllowedAdditionalStatusCodes = allowed
case "api":
if !isGlobal {
return h.Err("'api' block must be global")
Loading