| 1 | package rpcwire |
| 2 | |
| 3 | import ( |
| 4 | "bufio" |
| 5 | "bytes" |
| 6 | "encoding/json" |
| 7 | "errors" |
| 8 | "io" |
| 9 | "testing" |
| 10 | ) |
| 11 | |
| 12 | func TestReadStrictRequestFramePreservesExactFrameAndBufferedRemainder(t *testing.T) { |
| 13 | first := " {\"jsonrpc\":\"2.0\",\"id\":\"init-1\",\"method\":\"remote/initialize\",\"params\":{\"x\":1}} \r\n" |
| 14 | second := "{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"next\",\"params\":{}}\n" |
| 15 | reader := bufio.NewReaderSize(bytes.NewBufferString(first+second), 16) |
| 16 | frame, err := ReadStrictRequestFrame(reader, 8<<20) |
| 17 | if err != nil { |
| 18 | t.Fatal(err) |
| 19 | } |
| 20 | if string(frame.Raw) != first || string(frame.ID) != `"init-1"` || frame.Method != "remote/initialize" || string(frame.Params) != `{"x":1}` { |
| 21 | t.Fatalf("frame = %+v raw=%q", frame, frame.Raw) |
| 22 | } |
| 23 | remainder, err := io.ReadAll(reader) |
| 24 | if err != nil { |
| 25 | t.Fatal(err) |
| 26 | } |
| 27 | if string(remainder) != second { |
| 28 | t.Fatalf("buffered remainder = %q, want %q", remainder, second) |
| 29 | } |
| 30 | } |
| 31 | |
| 32 | func TestReadStrictRequestFrameRejectsNonRequestsAndLimit(t *testing.T) { |
| 33 | for _, input := range []string{ |
| 34 | "{\"jsonrpc\":\"2.0\",\"method\":\"note\",\"params\":{}}\n", |
| 35 | "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{}}\n", |
| 36 | "{\"jsonrpc\":\"1.0\",\"id\":1,\"method\":\"bad\"}\n", |
| 37 | } { |
| 38 | if _, err := ReadStrictRequestFrame(bufio.NewReader(bytes.NewBufferString(input)), 8<<20); err == nil { |
| 39 | t.Fatalf("invalid bootstrap frame accepted: %s", input) |
| 40 | } |
| 41 | } |
| 42 | _, err := ReadStrictRequestFrame(bufio.NewReader(bytes.NewBufferString("{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"x\"}\n")), 8) |
| 43 | var tooLarge *FrameTooLargeError |
| 44 | if !errors.As(err, &tooLarge) { |
| 45 | t.Fatalf("frame limit error = %v", err) |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | func TestResponseIDForErrorRejectsUnsafeIDs(t *testing.T) { |
| 50 | tests := []struct { |
| 51 | id string |
| 52 | want string |
| 53 | }{ |
| 54 | {id: `"request"`, want: `"request"`}, |
| 55 | {id: `-17`, want: `-17`}, |
| 56 | {id: `null`, want: `null`}, |
| 57 | {id: ``, want: `null`}, |
| 58 | {id: `true`, want: `null`}, |
| 59 | {id: `{}`, want: `null`}, |
| 60 | {id: `[]`, want: `null`}, |
| 61 | {id: `1.5`, want: `null`}, |
| 62 | } |
| 63 | for _, test := range tests { |
| 64 | if got := string(ResponseIDForError(json.RawMessage(test.id))); got != test.want { |
| 65 | t.Errorf("ResponseIDForError(%q) = %s, want %s", test.id, got, test.want) |
| 66 | } |
| 67 | } |
| 68 | } |
| 69 |