From 6df385bd3712f9940a7f4631c4b40a9fb994ea33 Mon Sep 17 00:00:00 2001 From: Jan Svabenik Date: Mon, 6 Apr 2026 07:21:01 +0200 Subject: [PATCH] feat: limit config request body size --- internal/control/control.go | 10 +++++++++- internal/control/control_test.go | 13 +++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/internal/control/control.go b/internal/control/control.go index 5ec9a97..7f98c03 100644 --- a/internal/control/control.go +++ b/internal/control/control.go @@ -5,6 +5,7 @@ import ( "encoding/json" "io" "net/http" + "strings" "sync" "github.com/jan/fm-rds-tx/internal/audio" @@ -49,6 +50,8 @@ type Server struct { streamSrc *audio.StreamSource // optional, for live audio ingest } +const maxConfigBodyBytes = 64 << 10 // 64 KiB + type ConfigPatch struct { FrequencyMHz *float64 `json:"frequencyMHz,omitempty"` OutputDrive *float64 `json:"outputDrive,omitempty"` @@ -296,9 +299,14 @@ func (s *Server) handleConfig(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(cfg) case http.MethodPost: + r.Body = http.MaxBytesReader(w, r.Body, maxConfigBodyBytes) var patch ConfigPatch if err := json.NewDecoder(r.Body).Decode(&patch); err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) + statusCode := http.StatusBadRequest + if strings.Contains(err.Error(), "http: request body too large") { + statusCode = http.StatusRequestEntityTooLarge + } + http.Error(w, err.Error(), statusCode) return } diff --git a/internal/control/control_test.go b/internal/control/control_test.go index e67ae4c..6d883c5 100644 --- a/internal/control/control_test.go +++ b/internal/control/control_test.go @@ -133,6 +133,19 @@ func TestConfigPatch(t *testing.T) { } } +func TestConfigPatchRejectsOversizeBody(t *testing.T) { + srv := NewServer(cfgpkg.Default()) + rec := httptest.NewRecorder() + payload := bytes.Repeat([]byte("x"), maxConfigBodyBytes+32) + body := append([]byte(`{"ps":"`), payload...) + body = append(body, []byte(`"}`)...) + req := httptest.NewRequest(http.MethodPost, "/config", bytes.NewReader(body)) + srv.Handler().ServeHTTP(rec, req) + if rec.Code != http.StatusRequestEntityTooLarge { + t.Fatalf("expected 413, got %d response=%q", rec.Code, rec.Body.String()) + } +} + func TestRuntimeWithoutDriver(t *testing.T) { srv := NewServer(cfgpkg.Default()) rec := httptest.NewRecorder()