diff --git a/cmd/server/main.go b/cmd/server/main.go index 8435b13..baea7dd 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -6,8 +6,10 @@ import ( "net" "net/http" "os" + "time" "forgejo.gwairfelin.com/max/gonotes/internal/conf" + "forgejo.gwairfelin.com/max/gonotes/internal/middleware" "forgejo.gwairfelin.com/max/gonotes/internal/notes/views" ) @@ -24,12 +26,22 @@ func main() { router := http.NewServeMux() notesRouter := views.GetRoutes("/notes") - router.Handle("/", logger(http.RedirectHandler("/notes/", http.StatusFound))) - router.Handle("/notes/", logger(http.StripPrefix("/notes", notesRouter))) + cacheExpiration, err := time.ParseDuration("24h") + if err != nil { + log.Fatal(err) + } + + etag := middleware.NewETag("static", cacheExpiration) + + router.Handle("/", middleware.LoggingMiddleware(http.RedirectHandler("/notes/", http.StatusFound))) + router.Handle("/notes/", middleware.LoggingMiddleware(http.StripPrefix("/notes", notesRouter))) router.Handle( "/static/", - logger( - http.FileServer(http.FS(conf.Static)), + middleware.LoggingMiddleware( + middleware.StaticEtagMiddleware( + *etag, + http.FileServer(http.FS(conf.Static)), + ), ), ) @@ -39,28 +51,3 @@ func main() { } log.Fatal(http.Serve(listener, router)) } - -type loggingResponseWriter struct { - http.ResponseWriter - statusCode int -} - -func NewLoggingResponseWriter(w http.ResponseWriter) *loggingResponseWriter { - return &loggingResponseWriter{w, http.StatusOK} -} - -func (w *loggingResponseWriter) WriteHeader(code int) { - w.statusCode = code - w.ResponseWriter.WriteHeader(code) -} - -func logger(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - lwr := NewLoggingResponseWriter(w) - next.ServeHTTP(lwr, r) - - if conf.Conf.LogAccess { - log.Printf("%s %s %s%s %d", r.RemoteAddr, r.Method, r.Host, r.URL.Path, lwr.statusCode) - } - }) -} diff --git a/internal/middleware/etag_cache.go b/internal/middleware/etag_cache.go index d19cfbe..47a27a2 100644 --- a/internal/middleware/etag_cache.go +++ b/internal/middleware/etag_cache.go @@ -1,8 +1,8 @@ +// Middleware to add naive caching headers package middleware import ( "fmt" - "hash/crc64" "log" "net/http" "strings" @@ -13,13 +13,10 @@ type ETag struct { Name string Value string Expiration time.Duration - HashTime time.Duration } -var etags = make([]*ETag, 0) - func (etag *ETag) Header() string { - return fmt.Sprintf("\"pb-%s-%s\"", etag.Name, etag.Value) + return fmt.Sprintf("\"gn-%s-%s\"", etag.Name, etag.Value) } func (etag *ETag) CacheControlHeader() string { @@ -46,21 +43,10 @@ func StaticEtagMiddleware(etag ETag, next http.Handler) http.Handler { } // GenerateETagFromBuffer calculates etag value from one or more buffers (e.g. embedded files) -func GenerateETagFromBuffer(name string, expiration time.Duration, buffers ...[]byte) (*ETag, error) { - start := time.Now() - hash := crc64.New(crc64.MakeTable(crc64.ECMA)) - for _, buffer := range buffers { - _, err := hash.Write(buffer) - if err != nil { - return nil, fmt.Errorf("unable to generate etag from buffer: %w", err) - } - } - etag := &ETag{ +func NewETag(name string, expiration time.Duration) *ETag { + return &ETag{ Name: name, Expiration: expiration, - Value: fmt.Sprintf("%x", hash.Sum64()), - HashTime: time.Since(start), + Value: fmt.Sprintf("%d", time.Now().Unix()), } - etags = append(etags, etag) - return etag, nil } diff --git a/internal/middleware/logger.go b/internal/middleware/logger.go new file mode 100644 index 0000000..b8c279a --- /dev/null +++ b/internal/middleware/logger.go @@ -0,0 +1,36 @@ +// Middleware to Log out requests and response status code +package middleware + +import ( + "log" + "net/http" + + "forgejo.gwairfelin.com/max/gonotes/internal/conf" +) + +// Response writer that store the status code for logging +type loggingResponseWriter struct { + http.ResponseWriter + statusCode int +} + +func NewLoggingResponseWriter(w http.ResponseWriter) *loggingResponseWriter { + return &loggingResponseWriter{w, http.StatusOK} +} + +func (w *loggingResponseWriter) WriteHeader(code int) { + w.statusCode = code + w.ResponseWriter.WriteHeader(code) +} + +// Middleware to log out requests and response status code +func LoggingMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + lwr := NewLoggingResponseWriter(w) + next.ServeHTTP(lwr, r) + + if conf.Conf.LogAccess { + log.Printf("%s %s %s%s %d", r.RemoteAddr, r.Method, r.Host, r.URL.Path, lwr.statusCode) + } + }) +}