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  }