From ecd31ffa1c890cca394f19dd4e2cce427283069e Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Tue, 31 Mar 2026 20:53:59 -0300 Subject: [PATCH] service: parse json job requests once --- pkg/service/server.go | 30 ++++++++++++++++++++---------- pkg/service/server_test.go | 16 ++++++++++++++++ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/pkg/service/server.go b/pkg/service/server.go index e1e2481..f70a104 100644 --- a/pkg/service/server.go +++ b/pkg/service/server.go @@ -95,7 +95,8 @@ func (a *App) handleBuild(w http.ResponseWriter, r *http.Request) { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } - node := requestValue(r, "node") + values := requestValues(r) + node := values["node"] job, err := a.Build(node) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) @@ -109,9 +110,10 @@ func (a *App) handleReplace(w http.ResponseWriter, r *http.Request) { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } - node := requestValue(r, "node") - host := requestValue(r, "host") - device := requestValue(r, "device") + values := requestValues(r) + node := values["node"] + host := values["host"] + device := values["device"] job, err := a.Replace(node, host, device) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) @@ -204,19 +206,27 @@ func normalizeGroupValue(raw string) string { return strings.TrimPrefix(value, "/") } -func requestValue(r *http.Request, key string) string { +func requestValues(r *http.Request) map[string]string { + values := map[string]string{} if err := r.ParseForm(); err == nil { - if value := strings.TrimSpace(r.Form.Get(key)); value != "" { - return value + for key, rawValues := range r.Form { + for _, raw := range rawValues { + if value := strings.TrimSpace(raw); value != "" { + values[key] = value + break + } + } } } var payload map[string]any if err := json.NewDecoder(r.Body).Decode(&payload); err == nil { - if value, ok := payload[key].(string); ok { - return strings.TrimSpace(value) + for key, raw := range payload { + if value, ok := raw.(string); ok && strings.TrimSpace(value) != "" { + values[key] = strings.TrimSpace(value) + } } } - return "" + return values } func writeJSON(w http.ResponseWriter, status int, payload any) { diff --git a/pkg/service/server_test.go b/pkg/service/server_test.go index 50fef26..2d154d9 100644 --- a/pkg/service/server_test.go +++ b/pkg/service/server_test.go @@ -121,6 +121,22 @@ func TestInternalSnapshotAndWatch(t *testing.T) { } } +func TestRequestValuesJSONBody(t *testing.T) { + req := httptest.NewRequest(http.MethodPost, "/api/jobs/replace", strings.NewReader(`{"node":"titan-13","host":"titan-20","device":"hosttmp:///tmp"}`)) + req.Header.Set("Content-Type", "application/json") + + values := requestValues(req) + if values["node"] != "titan-13" { + t.Fatalf("expected node titan-13, got %q", values["node"]) + } + if values["host"] != "titan-20" { + t.Fatalf("expected host titan-20, got %q", values["host"]) + } + if values["device"] != "hosttmp:///tmp" { + t.Fatalf("expected device hosttmp:///tmp, got %q", values["device"]) + } +} + func newTestApp(t *testing.T) *App { t.Helper() dir := t.TempDir()