summaryrefslogtreecommitdiff
path: root/player-server/internal/api/handlers.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-20 07:18:42 +0300
committerPaul Buetow <paul@buetow.org>2026-05-20 07:18:42 +0300
commit925ef996f2661f5e5cf57a1cd5a842303578330c (patch)
tree6d4810e4393f33ede7d23c63c60a20c1f52a1b16 /player-server/internal/api/handlers.go
parentf45737298d9536819c094ab90917db362b28332a (diff)
Buffer JSON before writing response in writeJSON (y9)
Previously writeJSON wrote the status header before encoding, so an encode failure produced a misleading 200 (or other caller status) with a truncated body. Marshal into a bytes.Buffer first; on error emit 500 with a JSON error envelope instead.
Diffstat (limited to 'player-server/internal/api/handlers.go')
-rw-r--r--player-server/internal/api/handlers.go21
1 files changed, 18 insertions, 3 deletions
diff --git a/player-server/internal/api/handlers.go b/player-server/internal/api/handlers.go
index f04ec19..8635c92 100644
--- a/player-server/internal/api/handlers.go
+++ b/player-server/internal/api/handlers.go
@@ -1,6 +1,7 @@
package api
import (
+ "bytes"
"encoding/json"
"errors"
"fmt"
@@ -26,12 +27,26 @@ func fileETag(size int64, modTime time.Time) string {
// Helpers
// ------------------------------------------------------------------
+// writeJSON serialises data to JSON and writes it to w with the given status.
+//
+// Marshalling happens into an in-memory buffer BEFORE any status or body is
+// written to the response. This avoids the previous footgun where the headers
+// (and a 200/whatever status) were committed first and then encoding failed
+// halfway through, producing a response with a misleading success status and a
+// truncated/invalid body. If encoding fails we instead emit a 500 with a small
+// JSON error payload so callers always see a consistent error shape.
func writeJSON(w http.ResponseWriter, status int, data interface{}) {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(status)
- if err := json.NewEncoder(w).Encode(data); err != nil {
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(data); err != nil {
slog.Error("encode json", "err", err)
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusInternalServerError)
+ _, _ = w.Write([]byte(`{"error":"internal encoding error"}`))
+ return
}
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(status)
+ _, _ = w.Write(buf.Bytes())
}
func writeError(w http.ResponseWriter, status int, message string) {