From 8ebdb1a183ed5b1563ac3b500ecb77076ba7fa71 Mon Sep 17 00:00:00 2001 From: LordMathis Date: Sat, 4 Oct 2025 22:16:28 +0200 Subject: [PATCH] Fix double read of json response when content-length header is missing --- pkg/server/handlers.go | 9 +++++++-- webui/src/lib/api.ts | 7 ++----- webui/src/lib/errorUtils.ts | 3 ++- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/pkg/server/handlers.go b/pkg/server/handlers.go index 594c273..98514ec 100644 --- a/pkg/server/handlers.go +++ b/pkg/server/handlers.go @@ -131,11 +131,16 @@ func (h *Handler) ListInstances() http.HandlerFunc { return } - w.Header().Set("Content-Type", "application/json") - if err := json.NewEncoder(w).Encode(instances); err != nil { + // Marshal to bytes first to set Content-Length header + data, err := json.Marshal(instances) + if err != nil { http.Error(w, "Failed to encode instances: "+err.Error(), http.StatusInternalServerError) return } + + w.Header().Set("Content-Type", "application/json") + w.Header().Set("Content-Length", strconv.Itoa(len(data))) + w.Write(data) } } diff --git a/webui/src/lib/api.ts b/webui/src/lib/api.ts index f7ecdf2..4e180e0 100644 --- a/webui/src/lib/api.ts +++ b/webui/src/lib/api.ts @@ -49,11 +49,8 @@ async function apiCall( } else { // Handle empty responses for JSON endpoints const contentLength = response.headers.get('content-length'); - if (contentLength === '0' || contentLength === null) { - const text = await response.text(); - if (text.trim() === '') { - return {} as T; // Return empty object for empty JSON responses - } + if (contentLength === '0') { + return {} as T; // Return empty object for empty JSON responses } const data = await response.json() as T; return data; diff --git a/webui/src/lib/errorUtils.ts b/webui/src/lib/errorUtils.ts index 1860bf9..85cdf03 100644 --- a/webui/src/lib/errorUtils.ts +++ b/webui/src/lib/errorUtils.ts @@ -26,7 +26,8 @@ export async function handleApiError(response: Response): Promise { } if (!response.ok) { - const errorMessage = await parseErrorResponse(response) + // Clone the response before reading to avoid consuming the body stream + const errorMessage = await parseErrorResponse(response.clone()) throw new Error(errorMessage) } } \ No newline at end of file