From 1b5f855bff52c46c3de1d24c0ebf414f18abef5d Mon Sep 17 00:00:00 2001 From: Deluan Date: Sat, 26 Nov 2022 13:13:05 -0500 Subject: [PATCH] Compress more http content-types. Also, some minor refactoring --- cmd/root.go | 2 +- server/middlewares.go | 19 ++++++++++++++++--- server/serve_index.go | 1 + server/server.go | 8 +++----- server/subsonic/api.go | 34 +++++++++++++++++----------------- 5 files changed, 38 insertions(+), 26 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 0826ba25..25a50fee 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -62,7 +62,7 @@ func runNavidrome() { if err := db.Close(); err != nil { log.Error("Error closing DB", err) } - log.Info("Navidrome stopped gracefully. Bye.") + log.Info("Navidrome stopped, bye.") }() g, ctx := errgroup.WithContext(context.Background()) diff --git a/server/middlewares.go b/server/middlewares.go index 16025f59..effed772 100644 --- a/server/middlewares.go +++ b/server/middlewares.go @@ -61,7 +61,7 @@ func loggerInjector(next http.Handler) http.Handler { }) } -func robotsTXT(fs fs.FS) func(next http.Handler) http.Handler { +func robotsTXT(fs fs.FS) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if strings.HasSuffix(r.URL.Path, "/robots.txt") { @@ -74,7 +74,7 @@ func robotsTXT(fs fs.FS) func(next http.Handler) http.Handler { } } -func corsHandler() func(h http.Handler) http.Handler { +func corsHandler() func(http.Handler) http.Handler { return cors.Handler(cors.Options{ AllowedOrigins: []string{"*"}, AllowedMethods: []string{ @@ -91,7 +91,7 @@ func corsHandler() func(h http.Handler) http.Handler { }) } -func secureMiddleware() func(h http.Handler) http.Handler { +func secureMiddleware() func(http.Handler) http.Handler { sec := secure.New(secure.Options{ ContentTypeNosniff: true, FrameDeny: true, @@ -102,6 +102,19 @@ func secureMiddleware() func(h http.Handler) http.Handler { return sec.Handler } +func compressMiddleware() func(http.Handler) http.Handler { + return middleware.Compress( + 5, + "application/xml", + "application/json", + "application/javascript", + "text/html", + "text/plain", + "text/css", + "text/javascript", + ) +} + func clientUniqueIdAdder(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() diff --git a/server/serve_index.go b/server/serve_index.go index 5102525d..fe3df021 100644 --- a/server/serve_index.go +++ b/server/serve_index.go @@ -73,6 +73,7 @@ func serveIndex(ds model.DataStore, fs fs.FS) http.HandlerFunc { "AppConfig": string(j), "Version": version, } + w.Header().Set("Content-Type", "text/html") err = t.Execute(w, data) if err != nil { log.Error(r, "Could not execute `index.html` template", err) diff --git a/server/server.go b/server/server.go index d536befc..d095d586 100644 --- a/server/server.go +++ b/server/server.go @@ -42,8 +42,6 @@ func (s *Server) MountRouter(description, urlPath string, subRouter http.Handler }) } -var startTime = time.Now() - func (s *Server) Run(ctx context.Context, addr string) error { s.MountRouter("WebUI", consts.URLPathUI, s.frontendAssetsHandler()) server := &http.Server{ @@ -55,13 +53,13 @@ func (s *Server) Run(ctx context.Context, addr string) error { // Start HTTP server in its own goroutine, send a signal (errC) if failed to start errC := make(chan error) go func() { - if err := server.ListenAndServe(); err != http.ErrServerClosed { + if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) { log.Error(ctx, "Could not start server. Aborting", err) errC <- err } }() - log.Info(ctx, "Navidrome server is ready!", "address", addr, "startupTime", time.Since(startTime)) + log.Info(ctx, "Navidrome server is ready!", "address", addr, "startupTime", time.Since(consts.ServerStart)) // Wait for a signal to terminate (or an error during startup) select { @@ -94,7 +92,7 @@ func (s *Server) initRoutes() { r.Use(middleware.RealIP) } r.Use(middleware.Recoverer) - r.Use(middleware.Compress(5, "application/xml", "application/json", "application/javascript")) + r.Use(compressMiddleware()) r.Use(middleware.Heartbeat("/ping")) r.Use(clientUniqueIdAdder) r.Use(loggerInjector) diff --git a/server/subsonic/api.go b/server/subsonic/api.go index cca2933c..e12c563c 100644 --- a/server/subsonic/api.go +++ b/server/subsonic/api.go @@ -166,8 +166,14 @@ func (api *Router) routes() http.Handler { return r } -// Add the Subsonic handler that requires a http.ResponseWriter, with and without `.view` extension. -// Ex: if path = `stream` it will create the routes `/stream` and `/stream.view` +// Add a Subsonic handler +func h(r chi.Router, path string, f handler) { + hr(r, path, func(_ http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) { + return f(r) + }) +} + +// Add a Subsonic handler that requires a http.ResponseWriter (ex: stream, getCoverArt...) func hr(r chi.Router, path string, f handlerRaw) { handle := func(w http.ResponseWriter, r *http.Request) { res, err := f(w, r) @@ -194,28 +200,18 @@ func hr(r chi.Router, path string, f handlerRaw) { sendResponse(w, r, res) } } - r.HandleFunc("/"+path, handle) - r.HandleFunc("/"+path+".view", handle) -} - -// Add the Subsonic handler, with and without `.view` extension -// Ex: if path = `ping` it will create the routes `/ping` and `/ping.view` -func h(r chi.Router, path string, f handler) { - hr(r, path, func(_ http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) { - return f(r) - }) + addHandler(r, path, handle) } // Add a handler that returns 501 - Not implemented. Used to signal that an endpoint is not implemented yet -func h501(r *chi.Mux, paths ...string) { +func h501(r chi.Router, paths ...string) { for _, path := range paths { handle := func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Cache-Control", "no-cache") w.WriteHeader(501) _, _ = w.Write([]byte("This endpoint is not implemented, but may be in future releases")) } - r.HandleFunc("/"+path, handle) - r.HandleFunc("/"+path+".view", handle) + addHandler(r, path, handle) } } @@ -226,11 +222,15 @@ func h410(r chi.Router, paths ...string) { w.WriteHeader(410) _, _ = w.Write([]byte("This endpoint will not be implemented")) } - r.HandleFunc("/"+path, handle) - r.HandleFunc("/"+path+".view", handle) + addHandler(r, path, handle) } } +func addHandler(r chi.Router, path string, handle func(w http.ResponseWriter, r *http.Request)) { + r.HandleFunc("/"+path, handle) + r.HandleFunc("/"+path+".view", handle) +} + func sendError(w http.ResponseWriter, r *http.Request, err error) { response := newResponse() code := responses.ErrorGeneric