From aaf9029a3e6982c644009ac62394dea78444d0d4 Mon Sep 17 00:00:00 2001 From: Benedikt Kulmann Date: Mon, 16 Nov 2020 22:13:26 +0100 Subject: [PATCH 1/3] Rename "Cache" middleware to "NoCache" --- accounts/pkg/server/http/server.go | 2 +- konnectd/pkg/server/http/server.go | 2 +- ocis-phoenix/pkg/server/http/server.go | 2 +- ocis-pkg/middleware/header.go | 4 ++-- ocis-pkg/service/debug/service.go | 2 +- ocs/pkg/server/http/server.go | 2 +- settings/pkg/server/http/server.go | 2 +- webdav/pkg/server/http/server.go | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/accounts/pkg/server/http/server.go b/accounts/pkg/server/http/server.go index b4a3bed7c..7f0ecd8ea 100644 --- a/accounts/pkg/server/http/server.go +++ b/accounts/pkg/server/http/server.go @@ -29,7 +29,7 @@ func Server(opts ...Option) http.Service { mux.Use(middleware.RealIP) mux.Use(middleware.RequestID) - mux.Use(middleware.Cache) + mux.Use(middleware.NoCache) mux.Use(middleware.Cors) mux.Use(middleware.Secure) mux.Use(middleware.ExtractAccountUUID( diff --git a/konnectd/pkg/server/http/server.go b/konnectd/pkg/server/http/server.go index 1f302d3b5..bd6f081f5 100644 --- a/konnectd/pkg/server/http/server.go +++ b/konnectd/pkg/server/http/server.go @@ -58,7 +58,7 @@ func Server(opts ...Option) (http.Service, error) { svc.Middleware( middleware.RealIP, middleware.RequestID, - middleware.Cache, + middleware.NoCache, middleware.Cors, middleware.Secure, middleware.Version( diff --git a/ocis-phoenix/pkg/server/http/server.go b/ocis-phoenix/pkg/server/http/server.go index 00f853c75..1d35592c0 100644 --- a/ocis-phoenix/pkg/server/http/server.go +++ b/ocis-phoenix/pkg/server/http/server.go @@ -28,7 +28,7 @@ func Server(opts ...Option) (http.Service, error) { svc.Middleware( middleware.RealIP, middleware.RequestID, - middleware.Cache, + middleware.NoCache, middleware.Cors, middleware.Secure, phoenixmid.SilentRefresh, diff --git a/ocis-pkg/middleware/header.go b/ocis-pkg/middleware/header.go index 0b311ac60..0087d84f5 100644 --- a/ocis-pkg/middleware/header.go +++ b/ocis-pkg/middleware/header.go @@ -5,8 +5,8 @@ import ( "time" ) -// Cache writes required cache headers to all requests. -func Cache(next http.Handler) http.Handler { +// NoCache writes required cache headers to all requests. +func NoCache(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate, value") w.Header().Set("Expires", "Thu, 01 Jan 1970 00:00:00 GMT") diff --git a/ocis-pkg/service/debug/service.go b/ocis-pkg/service/debug/service.go index f523ed356..1771fb074 100644 --- a/ocis-pkg/service/debug/service.go +++ b/ocis-pkg/service/debug/service.go @@ -49,7 +49,7 @@ func NewService(opts ...Option) *http.Server { Handler: alice.New( middleware.RealIP, middleware.RequestID, - middleware.Cache, + middleware.NoCache, middleware.Cors, middleware.Secure, middleware.Version( diff --git a/ocs/pkg/server/http/server.go b/ocs/pkg/server/http/server.go index 08aa12e2a..f555a4820 100644 --- a/ocs/pkg/server/http/server.go +++ b/ocs/pkg/server/http/server.go @@ -26,7 +26,7 @@ func Server(opts ...Option) (http.Service, error) { svc.Middleware( middleware.RealIP, middleware.RequestID, - middleware.Cache, + middleware.NoCache, middleware.Cors, middleware.Secure, middleware.Version( diff --git a/settings/pkg/server/http/server.go b/settings/pkg/server/http/server.go index cfab78fda..d4c8819a9 100644 --- a/settings/pkg/server/http/server.go +++ b/settings/pkg/server/http/server.go @@ -37,7 +37,7 @@ func Server(opts ...Option) http.Service { mux.Use(middleware.RealIP) mux.Use(middleware.RequestID) - mux.Use(middleware.Cache) + mux.Use(middleware.NoCache) mux.Use(middleware.Cors) mux.Use(middleware.Secure) mux.Use(middleware.ExtractAccountUUID( diff --git a/webdav/pkg/server/http/server.go b/webdav/pkg/server/http/server.go index 5811ade5f..5996322f9 100644 --- a/webdav/pkg/server/http/server.go +++ b/webdav/pkg/server/http/server.go @@ -26,7 +26,7 @@ func Server(opts ...Option) (http.Service, error) { svc.Middleware( middleware.RealIP, middleware.RequestID, - middleware.Cache, + middleware.NoCache, middleware.Cors, middleware.Secure, middleware.Version( From 9c6dac8328f961eec37a69991d54ef603d9c5e24 Mon Sep 17 00:00:00 2001 From: Benedikt Kulmann Date: Mon, 16 Nov 2020 23:22:56 +0100 Subject: [PATCH 2/3] Add caching for static web assets --- accounts/pkg/config/config.go | 1 + accounts/pkg/flagset/flagset.go | 7 +++++++ accounts/pkg/server/http/server.go | 1 + ocis-phoenix/pkg/config/config.go | 1 + ocis-phoenix/pkg/flagset/flagset.go | 7 +++++++ ocis-phoenix/pkg/service/v0/service.go | 18 ++++++++++++++---- ocis-pkg/middleware/static.go | 11 ++++++++++- settings/pkg/config/config.go | 1 + settings/pkg/flagset/flagset.go | 7 +++++++ settings/pkg/server/http/server.go | 1 + 10 files changed, 50 insertions(+), 5 deletions(-) diff --git a/accounts/pkg/config/config.go b/accounts/pkg/config/config.go index ac0b6abe8..2e5859a16 100644 --- a/accounts/pkg/config/config.go +++ b/accounts/pkg/config/config.go @@ -29,6 +29,7 @@ type HTTP struct { Addr string Namespace string Root string + CacheTTL int } // GRPC defines the available grpc configuration. diff --git a/accounts/pkg/flagset/flagset.go b/accounts/pkg/flagset/flagset.go index 1eb938153..f533f3b47 100644 --- a/accounts/pkg/flagset/flagset.go +++ b/accounts/pkg/flagset/flagset.go @@ -57,6 +57,13 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag { EnvVars: []string{"ACCOUNTS_HTTP_ROOT"}, Destination: &cfg.HTTP.Root, }, + &cli.IntFlag{ + Name: "http-cache-ttl", + Value: 604800, // 7 days + Usage: "Set the static assets caching duration in seconds", + EnvVars: []string{"ACCOUNTS_CACHE_TTL"}, + Destination: &cfg.HTTP.CacheTTL, + }, &cli.StringFlag{ Name: "grpc-namespace", Value: "com.owncloud.api", diff --git a/accounts/pkg/server/http/server.go b/accounts/pkg/server/http/server.go index 7f0ecd8ea..4514d412a 100644 --- a/accounts/pkg/server/http/server.go +++ b/accounts/pkg/server/http/server.go @@ -52,6 +52,7 @@ func Server(opts ...Option) http.Service { assets.Logger(options.Logger), assets.Config(options.Config), ), + options.Config.HTTP.CacheTTL, )) mux.Route(options.Config.HTTP.Root, func(r chi.Router) { diff --git a/ocis-phoenix/pkg/config/config.go b/ocis-phoenix/pkg/config/config.go index 1aa518d98..fcd898ffe 100644 --- a/ocis-phoenix/pkg/config/config.go +++ b/ocis-phoenix/pkg/config/config.go @@ -20,6 +20,7 @@ type HTTP struct { Addr string Root string Namespace string + CacheTTL int } // Tracing defines the available tracing configuration. diff --git a/ocis-phoenix/pkg/flagset/flagset.go b/ocis-phoenix/pkg/flagset/flagset.go index 45eadde1d..a832b4d2a 100644 --- a/ocis-phoenix/pkg/flagset/flagset.go +++ b/ocis-phoenix/pkg/flagset/flagset.go @@ -136,6 +136,13 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag { EnvVars: []string{"PHOENIX_NAMESPACE"}, Destination: &cfg.HTTP.Namespace, }, + &cli.IntFlag{ + Name: "http-cache-ttl", + Value: 604800, // 7 days + Usage: "Set the static assets caching duration in seconds", + EnvVars: []string{"PHOENIX_CACHE_TTL"}, + Destination: &cfg.HTTP.CacheTTL, + }, &cli.StringFlag{ Name: "asset-path", Value: "", diff --git a/ocis-phoenix/pkg/service/v0/service.go b/ocis-phoenix/pkg/service/v0/service.go index 11ea50e66..4bb9942b2 100644 --- a/ocis-phoenix/pkg/service/v0/service.go +++ b/ocis-phoenix/pkg/service/v0/service.go @@ -2,10 +2,13 @@ package svc import ( "encoding/json" + "fmt" "io/ioutil" "net/http" "os" + "strconv" "strings" + "time" "github.com/go-chi/chi" "github.com/owncloud/ocis/ocis-phoenix/pkg/assets" @@ -39,7 +42,7 @@ func NewService(opts ...Option) Service { m.Route(options.Config.HTTP.Root, func(r chi.Router) { r.Get("/config.json", svc.Config) - r.Mount("/", svc.Static()) + r.Mount("/", svc.Static(options.Config.HTTP.CacheTTL)) }) return svc @@ -124,7 +127,7 @@ func (p Phoenix) Config(w http.ResponseWriter, r *http.Request) { } // Static simply serves all static files. -func (p Phoenix) Static() http.HandlerFunc { +func (p Phoenix) Static(ttl int) http.HandlerFunc { rootWithSlash := p.config.HTTP.Root if !strings.HasSuffix(rootWithSlash, "/") { @@ -141,7 +144,10 @@ func (p Phoenix) Static() http.HandlerFunc { ), ) - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // we don't have a last modification date of the static assets, so we use the service start date + lastModified := time.Now().UTC().Format(http.TimeFormat) + + return func(w http.ResponseWriter, r *http.Request) { if rootWithSlash != "/" && r.URL.Path == p.config.HTTP.Root { http.Redirect( w, @@ -162,6 +168,10 @@ func (p Phoenix) Static() http.HandlerFunc { return } + w.Header().Set("Cache-Control", fmt.Sprintf("max-age=%s", strconv.Itoa(ttl))) + w.Header().Set("Last-Modified", lastModified) + w.Header().Del("Expires") + static.ServeHTTP(w, r) - }) + } } diff --git a/ocis-pkg/middleware/static.go b/ocis-pkg/middleware/static.go index 01bf4af94..718dd8435 100644 --- a/ocis-pkg/middleware/static.go +++ b/ocis-pkg/middleware/static.go @@ -1,13 +1,16 @@ package middleware import ( + "fmt" "net/http" "path" + "strconv" "strings" + "time" ) // Static is a middleware that serves static assets. -func Static(root string, fs http.FileSystem) func(http.Handler) http.Handler { +func Static(root string, fs http.FileSystem, ttl int) func(http.Handler) http.Handler { if !strings.HasSuffix(root, "/") { root = root + "/" } @@ -19,6 +22,9 @@ func Static(root string, fs http.FileSystem) func(http.Handler) http.Handler { ), ) + // we don't have a last modification date of the static assets, so we use the service start date + lastModified := time.Now().UTC().Format(http.TimeFormat) + return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if strings.HasPrefix(r.URL.Path, path.Join(root, "api")) { @@ -27,6 +33,9 @@ func Static(root string, fs http.FileSystem) func(http.Handler) http.Handler { if strings.HasSuffix(r.URL.Path, "/") { http.NotFound(w, r) } else { + w.Header().Set("Cache-Control", fmt.Sprintf("max-age=%s", strconv.Itoa(ttl))) + w.Header().Set("Last-Modified", lastModified) + w.Header().Del("Expires") static.ServeHTTP(w, r) } } diff --git a/settings/pkg/config/config.go b/settings/pkg/config/config.go index c0fd101c1..3b8a20201 100644 --- a/settings/pkg/config/config.go +++ b/settings/pkg/config/config.go @@ -20,6 +20,7 @@ type HTTP struct { Addr string Namespace string Root string + CacheTTL int } // GRPC defines the available grpc configuration. diff --git a/settings/pkg/flagset/flagset.go b/settings/pkg/flagset/flagset.go index 22eb72c5f..ab3adfdc1 100644 --- a/settings/pkg/flagset/flagset.go +++ b/settings/pkg/flagset/flagset.go @@ -136,6 +136,13 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag { EnvVars: []string{"SETTINGS_HTTP_ROOT"}, Destination: &cfg.HTTP.Root, }, + &cli.IntFlag{ + Name: "http-cache-ttl", + Value: 604800, // 7 days + Usage: "Set the static assets caching duration in seconds", + EnvVars: []string{"SETTINGS_CACHE_TTL"}, + Destination: &cfg.HTTP.CacheTTL, + }, &cli.StringFlag{ Name: "grpc-addr", Value: "0.0.0.0:9191", diff --git a/settings/pkg/server/http/server.go b/settings/pkg/server/http/server.go index d4c8819a9..aa46a0251 100644 --- a/settings/pkg/server/http/server.go +++ b/settings/pkg/server/http/server.go @@ -60,6 +60,7 @@ func Server(opts ...Option) http.Service { assets.Logger(options.Logger), assets.Config(options.Config), ), + options.Config.HTTP.CacheTTL, )) mux.Route(options.Config.HTTP.Root, func(r chi.Router) { From 4ca7382104faa2f8d5ebd12ee1018c1d7d8f8f59 Mon Sep 17 00:00:00 2001 From: Benedikt Kulmann Date: Mon, 16 Nov 2020 23:27:35 +0100 Subject: [PATCH 3/3] Changelog --- changelog/unreleased/web-assets-caching.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 changelog/unreleased/web-assets-caching.md diff --git a/changelog/unreleased/web-assets-caching.md b/changelog/unreleased/web-assets-caching.md new file mode 100644 index 000000000..e6fc2547f --- /dev/null +++ b/changelog/unreleased/web-assets-caching.md @@ -0,0 +1,7 @@ +Change: Caching for static web assets + +Tags: accounts, settings, web + +We now set http caching headers for static web assets, so that they don't get force-reloaded on each request. The max-age for the caching is configurable and defaults to 7 days. The last modified date of the assets is set to the service start date, so that a service restart results in cache invalidation. + +https://github.com/owncloud/ocis/pull/866