render.go (1376B)
1 package handlers 2 3 import ( 4 "crypto/sha256" 5 "fmt" 6 "net/http" 7 "os" 8 "strings" 9 10 "git.prime8.dev/moncheeta/prime8dev/internal/web" 11 ) 12 13 func (h *Handler) renderTemplate(w http.ResponseWriter, r *http.Request, name string, data web.Data, maxAgeSeconds int) { 14 if maxAgeSeconds < 0 { 15 maxAgeSeconds = 0 16 } 17 18 body, err := h.renderer.Render(name, data) 19 if err != nil { 20 http.Error(w, "Failed to render content", http.StatusInternalServerError) 21 return 22 } 23 24 sum := sha256.Sum256([]byte(body)) 25 etag := fmt.Sprintf(`W/"%x"`, sum) 26 cacheEnabled := shouldCacheResponses() 27 28 w.Header().Set("Content-Type", "text/html; charset=utf-8") 29 if !cacheEnabled { 30 applyNoCacheHeaders(w) 31 } else if maxAgeSeconds > 0 { 32 w.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%d", maxAgeSeconds)) 33 w.Header().Set("ETag", etag) 34 } 35 w.Header().Set("Vary", "HX-Request") 36 37 if cacheEnabled && maxAgeSeconds > 0 && strings.Contains(r.Header.Get("If-None-Match"), etag) { 38 w.WriteHeader(http.StatusNotModified) 39 return 40 } 41 42 _, _ = w.Write([]byte(body)) 43 } 44 45 func shouldCacheResponses() bool { 46 mode := strings.ToLower(strings.TrimSpace(os.Getenv("APP_ENV"))) 47 return mode == "prod" 48 } 49 50 func applyNoCacheHeaders(w http.ResponseWriter) { 51 w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0") 52 w.Header().Set("Pragma", "no-cache") 53 w.Header().Set("Expires", "0") 54 }