Skip to content

Commit

Permalink
rpc: add separate size limit for websocket (ethereum#22385)
Browse files Browse the repository at this point in the history
This makes the WebSocket message size limit independent of the
limit used for HTTP requests. The new limit for WebSocket messages 
is 15MB.
  • Loading branch information
fjl committed Feb 26, 2021
1 parent dc109cc commit 27b3137
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 1 deletion.
25 changes: 25 additions & 0 deletions rpc/http_test.go
Expand Up @@ -98,3 +98,28 @@ func confirmHTTPRequestYieldsStatusCode(t *testing.T, method, contentType, body
func TestHTTPResponseWithEmptyGet(t *testing.T) {
confirmHTTPRequestYieldsStatusCode(t, http.MethodGet, "", "", http.StatusOK)
}

// This checks that maxRequestContentLength is not applied to the response of a request.
func TestHTTPRespBodyUnlimited(t *testing.T) {
const respLength = maxRequestContentLength * 3

s := NewServer()
defer s.Stop()
s.RegisterName("test", largeRespService{respLength})
ts := httptest.NewServer(s)
defer ts.Close()

c, err := DialHTTP(ts.URL)
if err != nil {
t.Fatal(err)
}
defer c.Close()

var r string
if err := c.Call(&r, "test_largeResp"); err != nil {
t.Fatal(err)
}
if len(r) != respLength {
t.Fatalf("response has wrong length %d, want %d", len(r), respLength)
}
}
10 changes: 10 additions & 0 deletions rpc/testservice_test.go
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"encoding/binary"
"errors"
"strings"
"sync"
"time"
)
Expand Down Expand Up @@ -194,3 +195,12 @@ func (s *notificationTestService) HangSubscription(ctx context.Context, val int)
}()
return subscription, nil
}

// largeRespService generates arbitrary-size JSON responses.
type largeRespService struct {
length int
}

func (x largeRespService) LargeResp() string {
return strings.Repeat("x", x.length)
}
3 changes: 2 additions & 1 deletion rpc/websocket.go
Expand Up @@ -37,6 +37,7 @@ const (
wsWriteBuffer = 1024
wsPingInterval = 60 * time.Second
wsPingWriteTimeout = 5 * time.Second
wsMessageSizeLimit = 15 * 1024 * 1024
)

var wsBufferPool = new(sync.Pool)
Expand Down Expand Up @@ -239,7 +240,7 @@ type websocketCodec struct {
}

func newWebsocketCodec(conn *websocket.Conn) ServerCodec {
conn.SetReadLimit(maxRequestContentLength)
conn.SetReadLimit(wsMessageSizeLimit)
wc := &websocketCodec{
jsonCodec: NewFuncCodec(conn, conn.WriteJSON, conn.ReadJSON).(*jsonCodec),
conn: conn,
Expand Down
27 changes: 27 additions & 0 deletions rpc/websocket_test.go
Expand Up @@ -157,6 +157,33 @@ func TestClientWebsocketPing(t *testing.T) {
}
}

// This checks that the websocket transport can deal with large messages.
func TestClientWebsocketLargeMessage(t *testing.T) {
var (
srv = NewServer()
httpsrv = httptest.NewServer(srv.WebsocketHandler(nil))
wsURL = "ws:" + strings.TrimPrefix(httpsrv.URL, "http:")
)
defer srv.Stop()
defer httpsrv.Close()

respLength := wsMessageSizeLimit - 50
srv.RegisterName("test", largeRespService{respLength})

c, err := DialWebsocket(context.Background(), wsURL, "")
if err != nil {
t.Fatal(err)
}

var r string
if err := c.Call(&r, "test_largeResp"); err != nil {
t.Fatal("call failed:", err)
}
if len(r) != respLength {
t.Fatalf("response has wrong length %d, want %d", len(r), respLength)
}
}

// wsPingTestServer runs a WebSocket server which accepts a single subscription request.
// When a value arrives on sendPing, the server sends a ping frame, waits for a matching
// pong and finally delivers a single subscription result.
Expand Down

0 comments on commit 27b3137

Please sign in to comment.