Skip to content

Commit 7c4a4eb

Browse files
fjlkaralabe
authored andcommitted
rpc, p2p/simulations: use github.com/gorilla/websocket (#20289)
* rpc: improve codec abstraction rpc.ServerCodec is an opaque interface. There was only one way to get a codec using existing APIs: rpc.NewJSONCodec. This change exports newCodec (as NewFuncCodec) and NewJSONCodec (as NewCodec). It also makes all codec methods non-public to avoid showing internals in godoc. While here, remove codec options in tests because they are not supported anymore. * p2p/simulations: use github.com/gorilla/websocket This package was the last remaining user of golang.org/x/net/websocket. Migrating to the new library wasn't straightforward because it is no longer possible to treat WebSocket connections as a net.Conn. * vendor: delete golang.org/x/net/websocket * rpc: fix godoc comments and run gofmt
1 parent 9e71f55 commit 7c4a4eb

23 files changed

+121
-1391
lines changed

p2p/simulations/adapters/exec.go

+27-21
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ import (
4141
"github.com/ethereum/go-ethereum/p2p"
4242
"github.com/ethereum/go-ethereum/p2p/enode"
4343
"github.com/ethereum/go-ethereum/rpc"
44-
"golang.org/x/net/websocket"
44+
"github.com/gorilla/websocket"
4545
)
4646

4747
func init() {
@@ -118,7 +118,7 @@ func (e *ExecAdapter) NewNode(config *NodeConfig) (Node, error) {
118118
conf.Stack.P2P.NAT = nil
119119
conf.Stack.NoUSB = true
120120

121-
// listen on a localhost port, which we set when we
121+
// Listen on a localhost port, which we set when we
122122
// initialise NodeConfig (usually a random port)
123123
conf.Stack.P2P.ListenAddr = fmt.Sprintf(":%d", config.Port)
124124

@@ -205,17 +205,17 @@ func (n *ExecNode) Start(snapshots map[string][]byte) (err error) {
205205
}
206206
n.Cmd = cmd
207207

208-
// read the WebSocket address from the stderr logs
208+
// Wait for the node to start.
209209
status := <-statusC
210210
if status.Err != "" {
211211
return errors.New(status.Err)
212212
}
213-
client, err := rpc.DialWebsocket(ctx, status.WSEndpoint, "http://localhost")
213+
client, err := rpc.DialWebsocket(ctx, status.WSEndpoint, "")
214214
if err != nil {
215215
return fmt.Errorf("can't connect to RPC server: %v", err)
216216
}
217217

218-
// node ready :)
218+
// Node ready :)
219219
n.client = client
220220
n.wsAddr = status.WSEndpoint
221221
n.Info = status.NodeInfo
@@ -314,31 +314,37 @@ func (n *ExecNode) NodeInfo() *p2p.NodeInfo {
314314

315315
// ServeRPC serves RPC requests over the given connection by dialling the
316316
// node's WebSocket address and joining the two connections
317-
func (n *ExecNode) ServeRPC(clientConn net.Conn) error {
318-
conn, err := websocket.Dial(n.wsAddr, "", "http://localhost")
317+
func (n *ExecNode) ServeRPC(clientConn *websocket.Conn) error {
318+
conn, _, err := websocket.DefaultDialer.Dial(n.wsAddr, nil)
319319
if err != nil {
320320
return err
321321
}
322322
var wg sync.WaitGroup
323323
wg.Add(2)
324-
join := func(src, dst net.Conn) {
325-
defer wg.Done()
326-
io.Copy(dst, src)
327-
// close the write end of the destination connection
328-
if cw, ok := dst.(interface {
329-
CloseWrite() error
330-
}); ok {
331-
cw.CloseWrite()
332-
} else {
333-
dst.Close()
334-
}
335-
}
336-
go join(conn, clientConn)
337-
go join(clientConn, conn)
324+
go wsCopy(&wg, conn, clientConn)
325+
go wsCopy(&wg, clientConn, conn)
338326
wg.Wait()
327+
conn.Close()
339328
return nil
340329
}
341330

331+
func wsCopy(wg *sync.WaitGroup, src, dst *websocket.Conn) {
332+
defer wg.Done()
333+
for {
334+
msgType, r, err := src.NextReader()
335+
if err != nil {
336+
return
337+
}
338+
w, err := dst.NextWriter(msgType)
339+
if err != nil {
340+
return
341+
}
342+
if _, err = io.Copy(w, r); err != nil {
343+
return
344+
}
345+
}
346+
}
347+
342348
// Snapshots creates snapshots of the services by calling the
343349
// simulation_snapshot RPC method
344350
func (n *ExecNode) Snapshots() (map[string][]byte, error) {

p2p/simulations/adapters/inproc.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/ethereum/go-ethereum/p2p/enode"
3131
"github.com/ethereum/go-ethereum/p2p/simulations/pipes"
3232
"github.com/ethereum/go-ethereum/rpc"
33+
"github.com/gorilla/websocket"
3334
)
3435

3536
// SimAdapter is a NodeAdapter which creates in-memory simulation nodes and
@@ -210,13 +211,14 @@ func (sn *SimNode) Client() (*rpc.Client, error) {
210211
}
211212

212213
// ServeRPC serves RPC requests over the given connection by creating an
213-
// in-memory client to the node's RPC server
214-
func (sn *SimNode) ServeRPC(conn net.Conn) error {
214+
// in-memory client to the node's RPC server.
215+
func (sn *SimNode) ServeRPC(conn *websocket.Conn) error {
215216
handler, err := sn.node.RPCHandler()
216217
if err != nil {
217218
return err
218219
}
219-
handler.ServeCodec(rpc.NewJSONCodec(conn), rpc.OptionMethodInvocation|rpc.OptionSubscriptions)
220+
codec := rpc.NewFuncCodec(conn, conn.WriteJSON, conn.ReadJSON)
221+
handler.ServeCodec(codec, 0)
220222
return nil
221223
}
222224

p2p/simulations/adapters/types.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"github.com/ethereum/go-ethereum/p2p/enode"
3434
"github.com/ethereum/go-ethereum/p2p/enr"
3535
"github.com/ethereum/go-ethereum/rpc"
36+
"github.com/gorilla/websocket"
3637
)
3738

3839
// Node represents a node in a simulation network which is created by a
@@ -51,7 +52,7 @@ type Node interface {
5152
Client() (*rpc.Client, error)
5253

5354
// ServeRPC serves RPC requests over the given connection
54-
ServeRPC(net.Conn) error
55+
ServeRPC(*websocket.Conn) error
5556

5657
// Start starts the node with the given snapshots
5758
Start(snapshots map[string][]byte) error

p2p/simulations/http.go

+11-7
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ import (
3434
"github.com/ethereum/go-ethereum/p2p/enode"
3535
"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
3636
"github.com/ethereum/go-ethereum/rpc"
37+
"github.com/gorilla/websocket"
3738
"github.com/julienschmidt/httprouter"
38-
"golang.org/x/net/websocket"
3939
)
4040

4141
// DefaultClient is the default simulation API client which expects the API
@@ -654,16 +654,20 @@ func (s *Server) Options(w http.ResponseWriter, req *http.Request) {
654654
w.WriteHeader(http.StatusOK)
655655
}
656656

657+
var wsUpgrade = websocket.Upgrader{
658+
CheckOrigin: func(*http.Request) bool { return true },
659+
}
660+
657661
// NodeRPC forwards RPC requests to a node in the network via a WebSocket
658662
// connection
659663
func (s *Server) NodeRPC(w http.ResponseWriter, req *http.Request) {
660-
node := req.Context().Value("node").(*Node)
661-
662-
handler := func(conn *websocket.Conn) {
663-
node.ServeRPC(conn)
664+
conn, err := wsUpgrade.Upgrade(w, req, nil)
665+
if err != nil {
666+
return
664667
}
665-
666-
websocket.Server{Handler: handler}.ServeHTTP(w, req)
668+
defer conn.Close()
669+
node := req.Context().Value("node").(*Node)
670+
node.ServeRPC(conn)
667671
}
668672

669673
// ServeHTTP implements the http.Handler interface by delegating to the

rpc/client.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ func (c *Client) newClientConn(conn ServerCodec) *clientConn {
117117

118118
func (cc *clientConn) close(err error, inflightReq *requestOp) {
119119
cc.handler.close(err, inflightReq)
120-
cc.codec.Close()
120+
cc.codec.close()
121121
}
122122

123123
type readOp struct {
@@ -484,7 +484,7 @@ func (c *Client) write(ctx context.Context, msg interface{}) error {
484484
return err
485485
}
486486
}
487-
err := c.writeConn.Write(ctx, msg)
487+
err := c.writeConn.writeJSON(ctx, msg)
488488
if err != nil {
489489
c.writeConn = nil
490490
}
@@ -511,7 +511,7 @@ func (c *Client) reconnect(ctx context.Context) error {
511511
c.writeConn = newconn
512512
return nil
513513
case <-c.didClose:
514-
newconn.Close()
514+
newconn.close()
515515
return ErrClientQuit
516516
}
517517
}
@@ -558,7 +558,7 @@ func (c *Client) dispatch(codec ServerCodec) {
558558

559559
// Reconnect:
560560
case newcodec := <-c.reconnected:
561-
log.Debug("RPC client reconnected", "reading", reading, "conn", newcodec.RemoteAddr())
561+
log.Debug("RPC client reconnected", "reading", reading, "conn", newcodec.remoteAddr())
562562
if reading {
563563
// Wait for the previous read loop to exit. This is a rare case which
564564
// happens if this loop isn't notified in time after the connection breaks.
@@ -612,9 +612,9 @@ func (c *Client) drainRead() {
612612
// read decodes RPC messages from a codec, feeding them into dispatch.
613613
func (c *Client) read(codec ServerCodec) {
614614
for {
615-
msgs, batch, err := codec.Read()
615+
msgs, batch, err := codec.readBatch()
616616
if _, ok := err.(*json.SyntaxError); ok {
617-
codec.Write(context.Background(), errorMessage(&parseError{err.Error()}))
617+
codec.writeJSON(context.Background(), errorMessage(&parseError{err.Error()}))
618618
}
619619
if err != nil {
620620
c.readErr <- err

rpc/handler.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ func newHandler(connCtx context.Context, conn jsonWriter, idgen func() ID, reg *
8585
serverSubs: make(map[ID]*Subscription),
8686
log: log.Root(),
8787
}
88-
if conn.RemoteAddr() != "" {
89-
h.log = h.log.New("conn", conn.RemoteAddr())
88+
if conn.remoteAddr() != "" {
89+
h.log = h.log.New("conn", conn.remoteAddr())
9090
}
9191
h.unsubscribeCb = newCallback(reflect.Value{}, reflect.ValueOf(h.unsubscribe))
9292
return h
@@ -97,7 +97,7 @@ func (h *handler) handleBatch(msgs []*jsonrpcMessage) {
9797
// Emit error response for empty batches:
9898
if len(msgs) == 0 {
9999
h.startCallProc(func(cp *callProc) {
100-
h.conn.Write(cp.ctx, errorMessage(&invalidRequestError{"empty batch"}))
100+
h.conn.writeJSON(cp.ctx, errorMessage(&invalidRequestError{"empty batch"}))
101101
})
102102
return
103103
}
@@ -122,7 +122,7 @@ func (h *handler) handleBatch(msgs []*jsonrpcMessage) {
122122
}
123123
h.addSubscriptions(cp.notifiers)
124124
if len(answers) > 0 {
125-
h.conn.Write(cp.ctx, answers)
125+
h.conn.writeJSON(cp.ctx, answers)
126126
}
127127
for _, n := range cp.notifiers {
128128
n.activate()
@@ -139,7 +139,7 @@ func (h *handler) handleMsg(msg *jsonrpcMessage) {
139139
answer := h.handleCallMsg(cp, msg)
140140
h.addSubscriptions(cp.notifiers)
141141
if answer != nil {
142-
h.conn.Write(cp.ctx, answer)
142+
h.conn.writeJSON(cp.ctx, answer)
143143
}
144144
for _, n := range cp.notifiers {
145145
n.activate()

rpc/http.go

+13-13
Original file line numberDiff line numberDiff line change
@@ -47,29 +47,29 @@ type httpConn struct {
4747
client *http.Client
4848
req *http.Request
4949
closeOnce sync.Once
50-
closed chan interface{}
50+
closeCh chan interface{}
5151
}
5252

5353
// httpConn is treated specially by Client.
54-
func (hc *httpConn) Write(context.Context, interface{}) error {
55-
panic("Write called on httpConn")
54+
func (hc *httpConn) writeJSON(context.Context, interface{}) error {
55+
panic("writeJSON called on httpConn")
5656
}
5757

58-
func (hc *httpConn) RemoteAddr() string {
58+
func (hc *httpConn) remoteAddr() string {
5959
return hc.req.URL.String()
6060
}
6161

62-
func (hc *httpConn) Read() ([]*jsonrpcMessage, bool, error) {
63-
<-hc.closed
62+
func (hc *httpConn) readBatch() ([]*jsonrpcMessage, bool, error) {
63+
<-hc.closeCh
6464
return nil, false, io.EOF
6565
}
6666

67-
func (hc *httpConn) Close() {
68-
hc.closeOnce.Do(func() { close(hc.closed) })
67+
func (hc *httpConn) close() {
68+
hc.closeOnce.Do(func() { close(hc.closeCh) })
6969
}
7070

71-
func (hc *httpConn) Closed() <-chan interface{} {
72-
return hc.closed
71+
func (hc *httpConn) closed() <-chan interface{} {
72+
return hc.closeCh
7373
}
7474

7575
// HTTPTimeouts represents the configuration params for the HTTP RPC server.
@@ -116,7 +116,7 @@ func DialHTTPWithClient(endpoint string, client *http.Client) (*Client, error) {
116116

117117
initctx := context.Background()
118118
return newClient(initctx, func(context.Context) (ServerCodec, error) {
119-
return &httpConn{client: client, req: req, closed: make(chan interface{})}, nil
119+
return &httpConn{client: client, req: req, closeCh: make(chan interface{})}, nil
120120
})
121121
}
122122

@@ -195,7 +195,7 @@ type httpServerConn struct {
195195
func newHTTPServerConn(r *http.Request, w http.ResponseWriter) ServerCodec {
196196
body := io.LimitReader(r.Body, maxRequestContentLength)
197197
conn := &httpServerConn{Reader: body, Writer: w, r: r}
198-
return NewJSONCodec(conn)
198+
return NewCodec(conn)
199199
}
200200

201201
// Close does nothing and always returns nil.
@@ -266,7 +266,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
266266

267267
w.Header().Set("content-type", contentType)
268268
codec := newHTTPServerConn(r, w)
269-
defer codec.Close()
269+
defer codec.close()
270270
s.serveSingleRequest(ctx, codec)
271271
}
272272

rpc/inproc.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ func DialInProc(handler *Server) *Client {
2626
initctx := context.Background()
2727
c, _ := newClient(initctx, func(context.Context) (ServerCodec, error) {
2828
p1, p2 := net.Pipe()
29-
go handler.ServeCodec(NewJSONCodec(p1), OptionMethodInvocation|OptionSubscriptions)
30-
return NewJSONCodec(p2), nil
29+
go handler.ServeCodec(NewCodec(p1), 0)
30+
return NewCodec(p2), nil
3131
})
3232
return c
3333
}

rpc/ipc.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func (s *Server) ServeListener(l net.Listener) error {
3535
return err
3636
}
3737
log.Trace("Accepted RPC connection", "conn", conn.RemoteAddr())
38-
go s.ServeCodec(NewJSONCodec(conn), OptionMethodInvocation|OptionSubscriptions)
38+
go s.ServeCodec(NewCodec(conn), 0)
3939
}
4040
}
4141

@@ -51,6 +51,6 @@ func DialIPC(ctx context.Context, endpoint string) (*Client, error) {
5151
if err != nil {
5252
return nil, err
5353
}
54-
return NewJSONCodec(conn), err
54+
return NewCodec(conn), err
5555
})
5656
}

0 commit comments

Comments
 (0)