Skip to content

Commit 8ed3105

Browse files
Merge pull request #400 from tanmay4l/ws-fix
fix: keep websocket request IDs within JSON-safe range
2 parents edcedcc + 91dc72f commit 8ed3105

3 files changed

Lines changed: 44 additions & 6 deletions

File tree

rpc/ws/client.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,12 @@ func getUint64(data []byte, keys ...string) (val uint64, err error) {
170170
if e != nil {
171171
return 0, e
172172
}
173-
if t != jsonparser.Number {
174-
return 0, fmt.Errorf("value is not a number: %s", string(v))
173+
switch t {
174+
case jsonparser.Number, jsonparser.String:
175+
return strconv.ParseUint(string(v), 10, 64)
176+
default:
177+
return 0, fmt.Errorf("value is not a number/string: type=%d data=%s", t, string(v))
175178
}
176-
return strconv.ParseUint(string(v), 10, 64)
177179
}
178180

179181
func getUint64WithOk(data []byte, path ...string) (uint64, bool) {

rpc/ws/types.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ package ws
2020
import (
2121
stdjson "encoding/json"
2222
"fmt"
23-
"math/rand"
23+
rand "math/rand/v2"
2424
"net/http"
2525
"time"
2626
)
@@ -32,15 +32,17 @@ type request struct {
3232
ID uint64 `json:"id"`
3333
}
3434

35+
const maxJSONSafeInteger = uint64(1<<53 - 1)
36+
3537
func newRequest(params []any, method string, configuration map[string]any, shortID bool) *request {
3638
if params != nil && configuration != nil {
3739
params = append(params, configuration)
3840
}
3941
var ID uint64
4042
if !shortID {
41-
ID = uint64(rand.Int63())
43+
ID = rand.Uint64N(maxJSONSafeInteger + 1)
4244
} else {
43-
ID = uint64(rand.Int31())
45+
ID = uint64(rand.Uint32N(1 << 31))
4446
}
4547
return &request{
4648
Version: "2.0",

rpc/ws/types_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package ws
2+
3+
import (
4+
"math"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
func TestNewRequest_IDWithinJSONSafeInteger(t *testing.T) {
11+
for range 2_000 {
12+
req := newRequest(nil, "slotSubscribe", nil, false)
13+
require.LessOrEqual(t, req.ID, maxJSONSafeInteger)
14+
}
15+
}
16+
17+
func TestNewRequest_ShortIDWithinInt31(t *testing.T) {
18+
for range 2_000 {
19+
req := newRequest(nil, "slotSubscribe", nil, true)
20+
require.LessOrEqual(t, req.ID, uint64(math.MaxInt32))
21+
}
22+
}
23+
24+
func TestGetUint64_AcceptsNumberAndString(t *testing.T) {
25+
numberPayload := []byte(`{"id":3338220398172203928}`)
26+
id, err := getUint64(numberPayload, "id")
27+
require.NoError(t, err)
28+
require.Equal(t, uint64(3338220398172203928), id)
29+
30+
stringPayload := []byte(`{"id":"3338220398172203928"}`)
31+
id, err = getUint64(stringPayload, "id")
32+
require.NoError(t, err)
33+
require.Equal(t, uint64(3338220398172203928), id)
34+
}

0 commit comments

Comments
 (0)