Gzip large JSON API responses to cut transcript download time
This commit is contained in:
@@ -0,0 +1,64 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -135,7 +135,7 @@ func (s *Server) Handler() http.Handler {
|
|||||||
writeError(w, http.StatusBadRequest, err)
|
writeError(w, http.StatusBadRequest, err)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return timing(http.NewCrossOriginProtection().Handler(mux))
|
return timing(compress(http.NewCrossOriginProtection().Handler(mux)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) LoopbackHandler() http.Handler {
|
func (s *Server) LoopbackHandler() http.Handler {
|
||||||
|
|||||||
Reference in New Issue
Block a user