Files
byre/internal/server/compress.go
T

65 lines
1.3 KiB
Go

package server
import (
"compress/gzip"
"log/slog"
"net/http"
"strings"
)
const gzipMin = 8 << 10
type gzipWriter struct {
http.ResponseWriter
held int
gz *gzip.Writer
}
func (w *gzipWriter) WriteHeader(status int) {
if status == http.StatusOK && w.Header().Get("Content-Type") == "application/json" {
w.held = status
return
}
w.ResponseWriter.WriteHeader(status)
}
func (w *gzipWriter) Write(b []byte) (int, error) {
if w.held != 0 {
if len(b) >= gzipMin {
w.Header().Set("Content-Encoding", "gzip")
w.Header().Del("Content-Length")
w.gz = gzip.NewWriter(w.ResponseWriter)
}
w.ResponseWriter.WriteHeader(w.held)
w.held = 0
}
if w.gz != nil {
return w.gz.Write(b)
}
return w.ResponseWriter.Write(b)
}
func (w *gzipWriter) Unwrap() http.ResponseWriter {
return w.ResponseWriter
}
func compress(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
next.ServeHTTP(w, r)
return
}
gw := &gzipWriter{ResponseWriter: w}
next.ServeHTTP(gw, r)
if gw.held != 0 {
w.WriteHeader(gw.held)
}
if gw.gz != nil {
err := gw.gz.Close()
if err != nil {
slog.Warn("write response", "err", err)
}
}
})
}