Skip to content

Commit

Permalink
Merge pull request #17 from darkweak/proposal/use-souin-as-cache-system
Browse files Browse the repository at this point in the history
Proposal to use Souin as cache system
  • Loading branch information
darkweak authored Jan 4, 2022
2 parents 30a06de + 9ebf338 commit dda26ee
Show file tree
Hide file tree
Showing 22 changed files with 1,806 additions and 940 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
# The Windows build currently fail because of https://github.com/golang/go/issues/40795, and because xcaddy isn't compatible with the known workaround
#os: [ ubuntu-latest, macos-latest, windows-latest ]
os: [ ubuntu-latest, macos-latest ]
go: [ '1.15' ]
go: [ '1.16', '1.17' ]

runs-on: ${{ matrix.os }}

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/caddy
vendor/
42 changes: 42 additions & 0 deletions Caddyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
order cache before rewrite
log {
level debug
}
cache {
api {
souin {
enable true
}
}
regex {
exclude /test2.*
}
headers Content-Type Authorization
log_level debug
ttl 1000s
}
}

:4443
respond "Hello World!"

@match path /test1*
@match2 path /test2*
@matchdefault path /default
@souin-api path /souin-api*

cache @match {
ttl 5s
}

cache @match2 {
ttl 50s
headers Authorization
}

cache @matchdefault {
ttl 5s
}

cache @souin-api {}
135 changes: 114 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,125 @@
Caddy Module: http.handlers.cache
================================

**⚠️ Work-in-progress**

This is a distributed HTTP cache module for Caddy.
This is a distributed HTTP cache module for Caddy based on [Souin](https://github.com/darkweak/souin) cache.

## Features

* Supports most HTTP cache headers defined in [RFC 7234](https://httpwg.org/specs/rfc7234.html) (see the TODO section for limitations)
* Sets [the `Cache-Status` HTTP Response Header](https://httpwg.org/http-extensions/draft-ietf-httpbis-cache-header.html)
* [RFC 7234](https://httpwg.org/specs/rfc7234.html) compliant HTTP Cache.
* Sets [the `Cache-Status` HTTP Response Header](https://httpwg.org/http-extensions/draft-ietf-httpbis-cache-header.html)
* REST API to purge the cache and list stored resources.
* Builtin support for distributed cache.


## Example Configurations
There is the fully configuration below
```caddy
{
order cache before rewrite
log {
level debug
}
cache {
api {
basepath /some-basepath
souin {
enable true
security true
}
}
badger {
path the_path_to_a_file.json
configuration {
# Your badger configuration here
}
}
cdn {
api_key XXXX
dynamic true
email [email protected]
hostname domain.com
network your_network
provider fastly
strategy soft
service_id 123456_id
zone_id anywhere_zone
}
headers Content-Type Authorization
log_level debug
olric {
url url_to_your_cluster:3320
path the_path_to_a_file.yaml
configuration {
# Your badger configuration here
}
}
regex {
exclude /test2.*
}
stale 200s
ttl 1000s
}
}
:4443
respond "Hello World!"
@match path /test1*
@match2 path /test2*
@matchdefault path /default
@souin-api path /souin-api*
cache @match {
ttl 5s
}
cache @match2 {
ttl 50s
headers Authorization
}
cache @matchdefault {
ttl 5s
}
cache @souin-api {}
```
What does these directives mean?
| Key | Description | Value example |
|:-------------------------------------------------:|:----------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------:|
| `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.souin.enable` | Enable the souin API with related routes | `true`<br/><br/>`(default: false)` |
| `api.souin.security` | Enable JWT validation to access the resource | `true`<br/><br/>`(default: false)` |
| `badger` | Configure the Badger cache storage | |
| `badger.path` | Configure Badger with a file | `/anywhere/badger_configuration.json` |
| `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/) |
| `cdn` | The CDN management, if you use any cdn to proxy your requests Souin will handle that | |
| `cdn.provider` | The provider placed before Souin | `akamai`<br/><br/>`fastly`<br/><br/>`souin` |
| `cdn.api_key` | The api key used to access to the provider | `XXXX` |
| `cdn.dynamic` | Enable the dynamic keys returned by your backend application | `true`<br/><br/>`(default: false)` |
| `cdn.email` | The api key used to access to the provider if required, depending the provider | `XXXX` |
| `cdn.hostname` | The hostname if required, depending the provider | `domain.com` |
| `cdn.network` | The network if required, depending the provider | `your_network` |
| `cdn.strategy` | The strategy to use to purge the cdn cache, soft will keep the content as a stale resource | `hard`<br/><br/>`(default: soft)` |
| `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` |
| `headers` | List of headers to include to the cache | `Authorization Content-Type X-Additional-Header` |
| `olric` | Configure the Olric cache storage | |
| `olric.path` | Configure Olric with a file | `/anywhere/badger_configuration.json` |
| `olric.configuration` | Configure Olric directly in the Caddyfile or your JSON caddy configuration | [See the Badger configuration for the options](https://github.com/buraksezer/olric/blob/master/cmd/olricd/olricd.yaml/) |
| `port.{web,tls}` | The device's local HTTP/TLS port that Souin should be listening on | Respectively `80` and `443` |
| `regex.exclude` | The regex used to prevent paths being cached | `^[A-z]+.*$` |
| `stale` | The stale duration | `25m` |
| `ttl` | The TTL duration | `120s` |
| `log_level` | The log level | `One of DEBUG, INFO, WARN, ERROR, DPANIC, PANIC, FATAL it's case insensitive` |

## Example Configuration
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)

See [`Caddyfile`](fixtures/Caddyfile) and [olricd.yaml](fixtures/olricd.yaml)

## TODO

We are looking for volunteers to improve this module. Are you interested? Please comment in an issue!

* [x] Add support for `Age`
* [ ] Add support for `Vary`
* [x] Enable the distributed mode of Olric (our cache library)
* [ ] Allow to serve stale responses if the backend is down or while the new version is being generated
* [x] Add Caddyfile directives
* [ ] Add support for the `stale-if-error` directive
* [ ] Add support for the `stale-while-revalidate` directive
* [ ] Add support for cache validation
* [ ] Add support for request coalescing
* [ ] Add support for cache invalidation (purge/ban)
* [ ] Add support for cache tags (similar to Varnish ykey)
* [ ] Add support for the `ttl` attribute of the `Cache-Status` header
* [ ] Improve the API and add relevant endpoints
61 changes: 0 additions & 61 deletions age.go

This file was deleted.

55 changes: 55 additions & 0 deletions app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package httpcache

import (
"errors"

"github.com/caddyserver/caddy/v2"
"github.com/darkweak/souin/cache/surrogate/providers"
"github.com/darkweak/souin/cache/types"
"github.com/darkweak/souin/configurationtypes"
)

// SouinApp contains the whole Souin necessary items
type SouinApp struct {
*DefaultCache
Provider types.AbstractProviderInterface
SurrogateStorage providers.SurrogateInterface
API configurationtypes.API `json:"api,omitempty"`
LogLevel string `json:"log_level,omitempty"`
}

func init() {
caddy.RegisterModule(SouinApp{})
}

// Provision implements caddy.Provisioner
func (s *SouinApp) Provision(_ caddy.Context) error {
return nil
}

// Start will start the App
func (s SouinApp) Start() error {
if s.DefaultCache != nil && s.DefaultCache.GetTTL() == 0 {
return errors.New("Invalid/Incomplete default cache declaration")
}
return nil
}

// Stop will stop the App
func (s SouinApp) Stop() error {
return nil
}

// CaddyModule implements caddy.ModuleInfo
func (s SouinApp) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: moduleName,
New: func() caddy.Module { return new(SouinApp) },
}
}

var (
_ caddy.App = (*SouinApp)(nil)
_ caddy.Module = (*SouinApp)(nil)
_ caddy.Provisioner = (*SouinApp)(nil)
)
Loading

0 comments on commit dda26ee

Please sign in to comment.