github.com/sunblockterminal/go-sunblocktediuma@v0.0.0-20210616083421-160a35ed7cfa/rpc/json.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package rpc 18 19 import ( 20 "bytes" 21 "context" 22 "encoding/json" 23 "errors" 24 "fmt" 25 "io" 26 "reflect" 27 "strings" 28 "sync" 29 "time" 30 ) 31 32 const ( 33 vsn = "2.0" 34 serviceMethodSeparator = "_" 35 subscribeMethodSuffix = "_subscribe" 36 unsubscribeMethodSuffix = "_unsubscribe" 37 notificationMethodSuffix = "_subscription" 38 39 defaultWriteTimeout = 10 * time.Second // used if context has no deadline 40 ) 41 42 var null = json.RawMessage("null") 43 44 type subscriptionResult struct { 45 ID string `json:"subscription"` 46 Result json.RawMessage `json:"result,omitempty"` 47 } 48 49 // A value of this type can a JSON-RPC request, notification, successful response or 50 // error response. Which one it is depends on the fields. 51 type jsonrpcMessage struct { 52 Version string `json:"jsonrpc,omitempty"` 53 ID json.RawMessage `json:"id,omitempty"` 54 Method string `json:"method,omitempty"` 55 Params json.RawMessage `json:"params,omitempty"` 56 Error *jsonError `json:"error,omitempty"` 57 Result json.RawMessage `json:"result,omitempty"` 58 } 59 60 func (msg *jsonrpcMessage) isNotification() bool { 61 return msg.ID == nil && msg.Method != "" 62 } 63 64 func (msg *jsonrpcMessage) isCall() bool { 65 return msg.hasValidID() && msg.Method != "" 66 } 67 68 func (msg *jsonrpcMessage) isResponse() bool { 69 return msg.hasValidID() && msg.Method == "" && msg.Params == nil && (msg.Result != nil || msg.Error != nil) 70 } 71 72 func (msg *jsonrpcMessage) hasValidID() bool { 73 return len(msg.ID) > 0 && msg.ID[0] != '{' && msg.ID[0] != '[' 74 } 75 76 func (msg *jsonrpcMessage) isSubscribe() bool { 77 return strings.HasSuffix(msg.Method, subscribeMethodSuffix) 78 } 79 80 func (msg *jsonrpcMessage) isUnsubscribe() bool { 81 return strings.HasSuffix(msg.Method, unsubscribeMethodSuffix) 82 } 83 84 func (msg *jsonrpcMessage) namespace() string { 85 elem := strings.SplitN(msg.Method, serviceMethodSeparator, 2) 86 return elem[0] 87 } 88 89 func (msg *jsonrpcMessage) String() string { 90 b, _ := json.Marshal(msg) 91 return string(b) 92 } 93 94 func (msg *jsonrpcMessage) errorResponse(err error) *jsonrpcMessage { 95 resp := errorMessage(err) 96 resp.ID = msg.ID 97 return resp 98 } 99 100 func (msg *jsonrpcMessage) response(result interface{}) *jsonrpcMessage { 101 enc, err := json.Marshal(result) 102 if err != nil { 103 // TODO: wrap with 'internal server error' 104 return msg.errorResponse(err) 105 } 106 return &jsonrpcMessage{Version: vsn, ID: msg.ID, Result: enc} 107 } 108 109 func errorMessage(err error) *jsonrpcMessage { 110 msg := &jsonrpcMessage{Version: vsn, ID: null, Error: &jsonError{ 111 Code: defaultErrorCode, 112 Message: err.Error(), 113 }} 114 ec, ok := err.(Error) 115 if ok { 116 msg.Error.Code = ec.ErrorCode() 117 } 118 return msg 119 } 120 121 type jsonError struct { 122 Code int `json:"code"` 123 Message string `json:"message"` 124 Data interface{} `json:"data,omitempty"` 125 } 126 127 func (err *jsonError) Error() string { 128 if err.Message == "" { 129 return fmt.Sprintf("json-rpc error %d", err.Code) 130 } 131 return err.Message 132 } 133 134 func (err *jsonError) ErrorCode() int { 135 return err.Code 136 } 137 138 // Conn is a subset of the methods of net.Conn which are sufficient for ServerCodec. 139 type Conn interface { 140 io.ReadWriteCloser 141 SetWriteDeadline(time.Time) error 142 } 143 144 // ConnRemoteAddr wraps the RemoteAddr operation, which returns a description 145 // of the peer address of a connection. If a Conn also implements ConnRemoteAddr, this 146 // description is used in log messages. 147 type ConnRemoteAddr interface { 148 RemoteAddr() string 149 } 150 151 // connWithRemoteAddr overrides the remote address of a connection. 152 type connWithRemoteAddr struct { 153 Conn 154 addr string 155 } 156 157 func (c connWithRemoteAddr) RemoteAddr() string { return c.addr } 158 159 // jsonCodec reads and writes JSON-RPC messages to the underlying connection. It also has 160 // support for parsing arguments and serializing (result) objects. 161 type jsonCodec struct { 162 remoteAddr string 163 closer sync.Once // close closed channel once 164 closed chan interface{} // closed on Close 165 decode func(v interface{}) error // decoder to allow multiple transports 166 encMu sync.Mutex // guards the encoder 167 encode func(v interface{}) error // encoder to allow multiple transports 168 conn Conn 169 } 170 171 // NewCodec creates a new RPC server codec with support for JSON-RPC 2.0 based 172 // on explicitly given encoding and decoding methods. 173 func NewCodec(conn Conn, encode, decode func(v interface{}) error) ServerCodec { 174 codec := &jsonCodec{ 175 closed: make(chan interface{}), 176 encode: encode, 177 decode: decode, 178 conn: conn, 179 } 180 if ra, ok := conn.(ConnRemoteAddr); ok { 181 codec.remoteAddr = ra.RemoteAddr() 182 } 183 return codec 184 } 185 186 // NewJSONCodec creates a new RPC server codec with support for JSON-RPC 2.0. 187 func NewJSONCodec(conn Conn) ServerCodec { 188 enc := json.NewEncoder(conn) 189 dec := json.NewDecoder(conn) 190 dec.UseNumber() 191 return NewCodec(conn, enc.Encode, dec.Decode) 192 } 193 194 func (c *jsonCodec) RemoteAddr() string { 195 return c.remoteAddr 196 } 197 198 func (c *jsonCodec) Read() (msg []*jsonrpcMessage, batch bool, err error) { 199 // Decode the next JSON object in the input stream. 200 // This verifies basic syntax, etc. 201 var rawmsg json.RawMessage 202 if err := c.decode(&rawmsg); err != nil { 203 return nil, false, err 204 } 205 msg, batch = parseMessage(rawmsg) 206 return msg, batch, nil 207 } 208 209 // Write sends a message to client. 210 func (c *jsonCodec) Write(ctx context.Context, v interface{}) error { 211 c.encMu.Lock() 212 defer c.encMu.Unlock() 213 214 deadline, ok := ctx.Deadline() 215 if !ok { 216 deadline = time.Now().Add(defaultWriteTimeout) 217 } 218 c.conn.SetWriteDeadline(deadline) 219 return c.encode(v) 220 } 221 222 // Close the underlying connection 223 func (c *jsonCodec) Close() { 224 c.closer.Do(func() { 225 close(c.closed) 226 c.conn.Close() 227 }) 228 } 229 230 // Closed returns a channel which will be closed when Close is called 231 func (c *jsonCodec) Closed() <-chan interface{} { 232 return c.closed 233 } 234 235 // parseMessage parses raw bytes as a (batch of) JSON-RPC message(s). There are no error 236 // checks in this function because the raw message has already been syntax-checked when it 237 // is called. Any non-JSON-RPC messages in the input return the zero value of 238 // jsonrpcMessage. 239 func parseMessage(raw json.RawMessage) ([]*jsonrpcMessage, bool) { 240 if !isBatch(raw) { 241 msgs := []*jsonrpcMessage{{}} 242 json.Unmarshal(raw, &msgs[0]) 243 return msgs, false 244 } 245 dec := json.NewDecoder(bytes.NewReader(raw)) 246 dec.Token() // skip '[' 247 var msgs []*jsonrpcMessage 248 for dec.More() { 249 msgs = append(msgs, new(jsonrpcMessage)) 250 dec.Decode(&msgs[len(msgs)-1]) 251 } 252 return msgs, true 253 } 254 255 // isBatch returns true when the first non-whitespace characters is '[' 256 func isBatch(raw json.RawMessage) bool { 257 for _, c := range raw { 258 // skip insignificant whitespace (http://www.ietf.org/rfc/rfc4627.txt) 259 if c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d { 260 continue 261 } 262 return c == '[' 263 } 264 return false 265 } 266 267 // parsePositionalArguments tries to parse the given args to an array of values with the 268 // given types. It returns the parsed values or an error when the args could not be 269 // parsed. Missing optional arguments are returned as reflect.Zero values. 270 func parsePositionalArguments(rawArgs json.RawMessage, types []reflect.Type) ([]reflect.Value, error) { 271 dec := json.NewDecoder(bytes.NewReader(rawArgs)) 272 var args []reflect.Value 273 tok, err := dec.Token() 274 switch { 275 case err == io.EOF || tok == nil && err == nil: 276 // "params" is optional and may be empty. Also allow "params":null even though it's 277 // not in the spec because our own client used to send it. 278 case err != nil: 279 return nil, err 280 case tok == json.Delim('['): 281 // Read argument array. 282 if args, err = parseArgumentArray(dec, types); err != nil { 283 return nil, err 284 } 285 default: 286 return nil, errors.New("non-array args") 287 } 288 // Set any missing args to nil. 289 for i := len(args); i < len(types); i++ { 290 if types[i].Kind() != reflect.Ptr { 291 return nil, fmt.Errorf("missing value for required argument %d", i) 292 } 293 args = append(args, reflect.Zero(types[i])) 294 } 295 return args, nil 296 } 297 298 func parseArgumentArray(dec *json.Decoder, types []reflect.Type) ([]reflect.Value, error) { 299 args := make([]reflect.Value, 0, len(types)) 300 for i := 0; dec.More(); i++ { 301 if i >= len(types) { 302 return args, fmt.Errorf("too many arguments, want at most %d", len(types)) 303 } 304 argval := reflect.New(types[i]) 305 if err := dec.Decode(argval.Interface()); err != nil { 306 return args, fmt.Errorf("invalid argument %d: %v", i, err) 307 } 308 if argval.IsNil() && types[i].Kind() != reflect.Ptr { 309 return args, fmt.Errorf("missing value for required argument %d", i) 310 } 311 args = append(args, argval.Elem()) 312 } 313 // Read end of args array. 314 _, err := dec.Token() 315 return args, err 316 } 317 318 // parseSubscriptionName extracts the subscription name from an encoded argument array. 319 func parseSubscriptionName(rawArgs json.RawMessage) (string, error) { 320 dec := json.NewDecoder(bytes.NewReader(rawArgs)) 321 if tok, _ := dec.Token(); tok != json.Delim('[') { 322 return "", errors.New("non-array args") 323 } 324 v, _ := dec.Token() 325 method, ok := v.(string) 326 if !ok { 327 return "", errors.New("expected subscription name as first argument") 328 } 329 return method, nil 330 }