Render templates via a buffer, not the ResponseWriter (closes #123)
All checks were successful
check / check (push) Superseded by a newer commit; never tested

This commit was merged in pull request #131.
This commit is contained in:
2026-08-14 06:18:22 +02:00
parent 5f18bc3eae
commit 0b457ea713
3 changed files with 99 additions and 3 deletions

View File

@@ -3,6 +3,7 @@
package handlers
import (
"bytes"
"context"
"encoding/json"
"errors"
@@ -224,13 +225,20 @@ func (s *Handlers) renderTemplate(
s.executeTemplate(w, tmpl, wrapper)
}
// executeTemplate runs the template and handles errors.
// executeTemplate renders the template into a buffer and writes to
// the response only once rendering has fully succeeded. Executing
// straight into the ResponseWriter commits a partial body and a 200
// status before a mid-render error can be reported, leaving no way
// to serve a 500. These pages are small, so holding one in memory is
// the right trade.
func (s *Handlers) executeTemplate(
w http.ResponseWriter,
tmpl *template.Template,
data any,
) {
err := tmpl.Execute(w, data)
var buf bytes.Buffer
err := tmpl.Execute(&buf, data)
if err != nil {
s.log.Error(
"failed to execute template", "error", err,
@@ -239,5 +247,16 @@ func (s *Handlers) executeTemplate(
w, "Internal server error",
http.StatusInternalServerError,
)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
_, err = buf.WriteTo(w)
if err != nil {
s.log.Error(
"failed to write rendered page", "error", err,
)
}
}