mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-05 22:48:36 +00:00
rpc: pre-encode error data for batch size checks
Store jsonError.Data as json.RawMessage so error data is encoded once when the error response is built. This avoids re-serializing error data when enforcing the batch response size limit.
This commit is contained in:
parent
acf314f533
commit
45352c684a
2 changed files with 48 additions and 12 deletions
|
|
@ -238,13 +238,7 @@ func (h *handler) handleBatch(msgs []*jsonrpcMessage) {
|
||||||
callBuffer.pushResponse(resp)
|
callBuffer.pushResponse(resp)
|
||||||
if resp != nil && h.batchResponseMaxSize != 0 {
|
if resp != nil && h.batchResponseMaxSize != 0 {
|
||||||
if resp.Error != nil {
|
if resp.Error != nil {
|
||||||
b, err := json.Marshal(resp.Error)
|
responseBytes += resp.Error.encodedSize()
|
||||||
if err != nil {
|
|
||||||
// If we can't marshal the error, don't continue processing further calls.
|
|
||||||
responseBytes = h.batchResponseMaxSize + 1
|
|
||||||
} else {
|
|
||||||
responseBytes += len(b)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
responseBytes += len(resp.Result)
|
responseBytes += len(resp.Result)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
52
rpc/json.go
52
rpc/json.go
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -132,15 +133,19 @@ func errorMessage(err error) *jsonrpcMessage {
|
||||||
}
|
}
|
||||||
de, ok := err.(DataError)
|
de, ok := err.(DataError)
|
||||||
if ok {
|
if ok {
|
||||||
msg.Error.Data = de.ErrorData()
|
data, err := marshalErrorData(de.ErrorData())
|
||||||
|
if err != nil {
|
||||||
|
return errorMessage(&internalServerError{errcodeMarshalError, err.Error()})
|
||||||
|
}
|
||||||
|
msg.Error.Data = data
|
||||||
}
|
}
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
type jsonError struct {
|
type jsonError struct {
|
||||||
Code int `json:"code"`
|
Code int `json:"code"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
Data interface{} `json:"data,omitempty"`
|
Data json.RawMessage `json:"data,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err *jsonError) Error() string {
|
func (err *jsonError) Error() string {
|
||||||
|
|
@ -155,7 +160,44 @@ func (err *jsonError) ErrorCode() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err *jsonError) ErrorData() interface{} {
|
func (err *jsonError) ErrorData() interface{} {
|
||||||
return err.Data
|
if len(err.Data) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
dec := json.NewDecoder(bytes.NewReader(err.Data))
|
||||||
|
dec.UseNumber()
|
||||||
|
|
||||||
|
var data interface{}
|
||||||
|
if err := dec.Decode(&data); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err *jsonError) encodedSize() int {
|
||||||
|
size := len(`{"code":`) + len(strconv.Itoa(err.Code)) + len(`,"message":`) + jsonStringSize(err.Message)
|
||||||
|
if len(err.Data) > 0 {
|
||||||
|
size += len(`,"data":`) + len(err.Data)
|
||||||
|
}
|
||||||
|
return size + len(`}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalErrorData(data interface{}) (json.RawMessage, error) {
|
||||||
|
if data == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
enc, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return json.RawMessage(enc), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func jsonStringSize(s string) int {
|
||||||
|
enc, err := json.Marshal(s)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return len(enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conn is a subset of the methods of net.Conn which are sufficient for ServerCodec.
|
// Conn is a subset of the methods of net.Conn which are sufficient for ServerCodec.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue