Skip to content

Commit f5dfc42

Browse files
authored
Merge pull request #198 from OffchainLabs/batch-response-size-limit
Add a batch response size limit
2 parents 46c6132 + cc111cd commit f5dfc42

File tree

1 file changed

+23
-10
lines changed

1 file changed

+23
-10
lines changed

rpc/handler.go

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package rpc
1919
import (
2020
"context"
2121
"encoding/json"
22+
"fmt"
2223
"reflect"
2324
"strconv"
2425
"strings"
@@ -34,21 +35,20 @@ import (
3435
//
3536
// The entry points for incoming messages are:
3637
//
37-
// h.handleMsg(message)
38-
// h.handleBatch(message)
38+
// h.handleMsg(message)
39+
// h.handleBatch(message)
3940
//
4041
// Outgoing calls use the requestOp struct. Register the request before sending it
4142
// on the connection:
4243
//
43-
// op := &requestOp{ids: ...}
44-
// h.addRequestOp(op)
44+
// op := &requestOp{ids: ...}
45+
// h.addRequestOp(op)
4546
//
4647
// Now send the request, then wait for the reply to be delivered through handleMsg:
4748
//
48-
// if err := op.wait(...); err != nil {
49-
// h.removeRequestOp(op) // timeout, etc.
50-
// }
51-
//
49+
// if err := op.wait(...); err != nil {
50+
// h.removeRequestOp(op) // timeout, etc.
51+
// }
5252
type handler struct {
5353
reg *serviceRegistry
5454
unsubscribeCb *callback
@@ -92,6 +92,8 @@ func newHandler(connCtx context.Context, conn jsonWriter, idgen func() ID, reg *
9292
return h
9393
}
9494

95+
const maxBatchResponseSize int = 10_000_000 // 10MB
96+
9597
// handleBatch executes all messages in a batch and returns the responses.
9698
func (h *handler) handleBatch(msgs []*jsonrpcMessage) {
9799
// Emit error response for empty batches:
@@ -114,10 +116,21 @@ func (h *handler) handleBatch(msgs []*jsonrpcMessage) {
114116
}
115117
// Process calls on a goroutine because they may block indefinitely:
116118
h.startCallProc(func(cp *callProc) {
117-
answers := make([]*jsonrpcMessage, 0, len(msgs))
119+
answers := make([]json.RawMessage, 0, len(msgs))
120+
var totalSize int
118121
for _, msg := range calls {
119122
if answer := h.handleCallMsg(cp, msg); answer != nil {
120-
answers = append(answers, answer)
123+
serialized, err := json.Marshal(answer)
124+
if err != nil {
125+
h.conn.writeJSON(cp.ctx, errorMessage(&parseError{"error serializing response: " + err.Error()}))
126+
return
127+
}
128+
totalSize += len(serialized)
129+
if totalSize > maxBatchResponseSize {
130+
h.conn.writeJSON(cp.ctx, errorMessage(&invalidRequestError{fmt.Sprintf("batch response exceeded limit of %v bytes", maxBatchResponseSize)}))
131+
return
132+
}
133+
answers = append(answers, serialized)
121134
}
122135
}
123136
h.addSubscriptions(cp.notifiers)

0 commit comments

Comments
 (0)