Something something etag middleware

This commit is contained in:
Maximilian Friedersdorff 2025-06-27 19:58:15 +01:00
parent 91cc68efe7
commit f2e52a18e5

View file

@ -0,0 +1,66 @@
package middleware
import (
"fmt"
"hash/crc64"
"log"
"net/http"
"strings"
"time"
)
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)
}
func (etag *ETag) CacheControlHeader() string {
return fmt.Sprintf("max-age=%d", int(etag.Expiration.Seconds()))
}
func StaticEtagMiddleware(etag ETag, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cc := etag.CacheControlHeader()
w.Header().Set("ETag", etag.Header())
w.Header().Set("Cache-Control", cc)
log.Printf("Returned etag with Cache-Control '%s'", cc)
if match := r.Header.Get("If-None-Match"); match != "" {
if strings.Contains(match, etag.Value) {
log.Print("ETag cache hit")
w.WriteHeader(http.StatusNotModified)
return
}
}
next.ServeHTTP(w, r)
})
}
// 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{
Name: name,
Expiration: expiration,
Value: fmt.Sprintf("%x", hash.Sum64()),
HashTime: time.Since(start),
}
etags = append(etags, etag)
return etag, nil
}