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