diff --git a/cmd/server/main.go b/cmd/server/main.go index baea7dd..8435b13 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -6,10 +6,8 @@ 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" ) @@ -26,22 +24,12 @@ func main() { router := http.NewServeMux() notesRouter := views.GetRoutes("/notes") - 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("/", logger(http.RedirectHandler("/notes/", http.StatusFound))) + router.Handle("/notes/", logger(http.StripPrefix("/notes", notesRouter))) router.Handle( "/static/", - middleware.LoggingMiddleware( - middleware.StaticEtagMiddleware( - *etag, - http.FileServer(http.FS(conf.Static)), - ), + logger( + http.FileServer(http.FS(conf.Static)), ), ) @@ -51,3 +39,28 @@ 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 47a27a2..d19cfbe 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,10 +13,13 @@ 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("\"gn-%s-%s\"", etag.Name, etag.Value) + return fmt.Sprintf("\"pb-%s-%s\"", etag.Name, etag.Value) } func (etag *ETag) CacheControlHeader() string { @@ -43,10 +46,21 @@ func StaticEtagMiddleware(etag ETag, next http.Handler) http.Handler { } // GenerateETagFromBuffer calculates etag value from one or more buffers (e.g. embedded files) -func NewETag(name string, expiration time.Duration) *ETag { - return &ETag{ +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{ Name: name, Expiration: expiration, - Value: fmt.Sprintf("%d", time.Now().Unix()), + Value: fmt.Sprintf("%x", hash.Sum64()), + HashTime: time.Since(start), } + etags = append(etags, etag) + return etag, nil } diff --git a/internal/middleware/logger.go b/internal/middleware/logger.go deleted file mode 100644 index b8c279a..0000000 --- a/internal/middleware/logger.go +++ /dev/null @@ -1,36 +0,0 @@ -// 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) - } - }) -}