diff --git a/internal/server/httpws/redisCmdAdapter.go b/internal/server/httpws/redisCmdAdapter.go index 87286679e..472a81ec6 100644 --- a/internal/server/httpws/redisCmdAdapter.go +++ b/internal/server/httpws/redisCmdAdapter.go @@ -86,17 +86,15 @@ func ParseHTTPRequest(r *http.Request) (*cmd.DiceDBCmd, error) { } // Step 1: Handle JSON body if present if r.Body != nil { - body, err := io.ReadAll(r.Body) - if err != nil { - return nil, err - } + decoder := json.NewDecoder(r.Body) + decoder.UseNumber() // avoids converting numbers to float64 - if len(body) > 0 { - var jsonBody map[string]interface{} - if err := json.Unmarshal(body, &jsonBody); err != nil { + var jsonBody map[string]interface{} + if err := decoder.Decode(&jsonBody); err != nil { + if err != io.EOF { // ignore EOF error return nil, err } - + } else { if len(jsonBody) == 0 && command != ABORT { return nil, fmt.Errorf("empty JSON object") } diff --git a/internal/server/httpws/redisCmdAdapter_test.go b/internal/server/httpws/redisCmdAdapter_test.go index 23207c468..ab8289a18 100644 --- a/internal/server/httpws/redisCmdAdapter_test.go +++ b/internal/server/httpws/redisCmdAdapter_test.go @@ -17,6 +17,7 @@ package httpws import ( + "io" "net/http/httptest" "strings" "testing" @@ -82,6 +83,14 @@ func TestParseHTTPRequest(t *testing.T) { expectedCmd: "SET", expectedArgs: []string{"k1", `[{"subKey1":"value1"},{"subKey2":"value2"}]`, "nx"}, }, + { + name: "Test SET command with int64", + method: "POST", + url: "/set", + body: `{"key": "k1", "value": -9223372036854775808}`, + expectedCmd: "SET", + expectedArgs: []string{"k1", "-9223372036854775808"}, + }, { name: "Test GET command", method: "POST", @@ -226,6 +235,14 @@ func TestParseHTTPRequest(t *testing.T) { expectedCmd: "JSON.ARRPOP", expectedArgs: []string{"k1", "$", "1"}, }, + { + name: "Test ABORT command", + method: "POST", + url: "/abort", + body: `{}`, + expectedCmd: "ABORT", + expectedArgs: []string{}, + }, } for _, tc := range commands { @@ -251,6 +268,48 @@ func TestParseHTTPRequest(t *testing.T) { } } +func TestParseHTTPRequestError(t *testing.T) { + commands := []struct { + name string + method string + url string + body string + expectedErr string + }{ + { + name: "Unexpected EOF", + method: "POST", + url: "/set", + body: `{"key": "malformed json}"`, + expectedErr: io.ErrUnexpectedEOF.Error(), + }, + { + name: "Empty body", + method: "POST", + url: "/set", + body: `{}`, + expectedErr: "empty JSON object", + }, + { + name: "Syntax error", + method: "POST", + url: "/set", + body: `{'key': "k1"}`, + expectedErr: "invalid character '\\'' looking for beginning of object key string", + }, + } + for _, tc := range commands { + t.Run(tc.name, func(t *testing.T) { + req := httptest.NewRequest(tc.method, tc.url, strings.NewReader(tc.body)) + req.Header.Set("Content-Type", "application/json") + + _, err := ParseHTTPRequest(req) + assert.Error(t, err) + assert.EqualError(t, err, tc.expectedErr) + }) + } +} + func TestParseWebsocketMessage(t *testing.T) { commands := []struct { name string