dubbo.apache.org/dubbo-go/v3@v3.1.1/protocol/jsonrpc/json.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package jsonrpc
    19  
    20  import (
    21  	"bytes"
    22  	"encoding/json"
    23  	"fmt"
    24  	"io"
    25  	"reflect"
    26  	"strings"
    27  )
    28  
    29  import (
    30  	perrors "github.com/pkg/errors"
    31  )
    32  
    33  const (
    34  	MAX_JSONRPC_ID = 0x7FFFFFFF // max jsonrpc request/response id
    35  	VERSION        = "2.0"      // jsonrpc version
    36  )
    37  
    38  // CodecData is codec data for json RPC.
    39  type CodecData struct {
    40  	ID     int64
    41  	Method string
    42  	Args   interface{}
    43  	Error  string
    44  }
    45  
    46  // Errors defined in the JSON-RPC spec. See
    47  // http://www.jsonrpc.org/specification#error_object.
    48  const (
    49  	CodeParseError     = -32700
    50  	CodeInvalidRequest = -32600
    51  	CodeMethodNotFound = -32601
    52  	CodeInvalidParams  = -32602
    53  	CodeInternalError  = -32603
    54  )
    55  
    56  // Error response Error
    57  type Error struct {
    58  	Code    int         `json:"code"`
    59  	Message string      `json:"message"`
    60  	Data    interface{} `json:"data,omitempty"`
    61  }
    62  
    63  // Error decodes response error for a string.
    64  func (e *Error) Error() string {
    65  	buf, err := json.Marshal(e)
    66  	if err != nil {
    67  		msg, retryErr := json.Marshal(err.Error())
    68  		if retryErr != nil {
    69  			msg = []byte("jsonrpc2.Error: json.Marshal failed")
    70  		}
    71  		return fmt.Sprintf(`{"code":%d,"message":%s}`, -32001, string(msg))
    72  	}
    73  	return string(buf)
    74  }
    75  
    76  type clientRequest struct {
    77  	Version string      `json:"jsonrpc"`
    78  	Method  string      `json:"method"`
    79  	Params  interface{} `json:"params"`
    80  	ID      int64       `json:"id"`
    81  }
    82  
    83  type clientResponse struct {
    84  	Version string           `json:"jsonrpc"`
    85  	ID      int64            `json:"id"`
    86  	Result  *json.RawMessage `json:"result,omitempty"`
    87  	Error   *Error           `json:"error,omitempty"`
    88  }
    89  
    90  func (r *clientResponse) reset() {
    91  	r.Version = ""
    92  	r.ID = 0
    93  	r.Result = nil
    94  }
    95  
    96  type jsonClientCodec struct {
    97  	// temporary work space
    98  	req clientRequest
    99  	rsp clientResponse
   100  
   101  	pending map[int64]string
   102  }
   103  
   104  func newJsonClientCodec() *jsonClientCodec {
   105  	return &jsonClientCodec{
   106  		pending: make(map[int64]string),
   107  	}
   108  }
   109  
   110  // Write codec data as byte.
   111  func (c *jsonClientCodec) Write(d *CodecData) ([]byte, error) {
   112  	// If return error: it will be returned as is for this call.
   113  	// Allow param to be only Array, Slice, Map or Struct.
   114  	// When param is nil or uninitialized Map or Slice - omit "params".
   115  	param := d.Args
   116  	if param != nil {
   117  		switch k := reflect.TypeOf(param).Kind(); k {
   118  		case reflect.Map:
   119  			if reflect.TypeOf(param).Key().Kind() == reflect.String && reflect.ValueOf(param).IsNil() {
   120  				param = nil
   121  			}
   122  		case reflect.Slice:
   123  			if reflect.ValueOf(param).IsNil() {
   124  				param = nil
   125  			}
   126  		case reflect.Array, reflect.Struct:
   127  		case reflect.Ptr:
   128  			switch ptrK := reflect.TypeOf(param).Elem().Kind(); ptrK {
   129  			case reflect.Map:
   130  				if reflect.TypeOf(param).Elem().Key().Kind() == reflect.String && reflect.ValueOf(param).Elem().IsNil() {
   131  					param = nil
   132  				}
   133  			case reflect.Slice:
   134  				if reflect.ValueOf(param).Elem().IsNil() {
   135  					param = nil
   136  				}
   137  			case reflect.Array, reflect.Struct:
   138  			default:
   139  				return nil, perrors.New("unsupported param type: Ptr to " + ptrK.String())
   140  			}
   141  		default:
   142  			return nil, perrors.New("unsupported param type: " + k.String())
   143  		}
   144  	}
   145  
   146  	c.req.Version = "2.0"
   147  	c.req.Method = d.Method
   148  	c.req.Params = param
   149  	c.req.ID = d.ID & MAX_JSONRPC_ID
   150  	// can not use d.ID. otherwise you will get error: can not find method of response id 280698512
   151  	c.pending[c.req.ID] = d.Method
   152  
   153  	buf := bytes.NewBuffer(nil)
   154  	defer buf.Reset()
   155  	enc := json.NewEncoder(buf)
   156  	if err := enc.Encode(&c.req); err != nil {
   157  		return nil, perrors.WithStack(err)
   158  	}
   159  
   160  	return buf.Bytes(), nil
   161  }
   162  
   163  // Read bytes as structured data
   164  func (c *jsonClientCodec) Read(streamBytes []byte, x interface{}) error {
   165  	c.rsp.reset()
   166  
   167  	buf := bytes.NewBuffer(streamBytes)
   168  	defer buf.Reset()
   169  	dec := json.NewDecoder(buf)
   170  	if err := dec.Decode(&c.rsp); err != nil {
   171  		if err != io.EOF {
   172  			err = perrors.WithStack(err)
   173  		}
   174  		return err
   175  	}
   176  
   177  	_, ok := c.pending[c.rsp.ID]
   178  	if !ok {
   179  		err := perrors.Errorf("can not find method of rsponse id %v, rsponse error:%v", c.rsp.ID, c.rsp.Error)
   180  		return err
   181  	}
   182  	delete(c.pending, c.rsp.ID)
   183  
   184  	// c.rsp.ID
   185  	if c.rsp.Error != nil {
   186  		return perrors.New(c.rsp.Error.Error())
   187  	}
   188  
   189  	if c.rsp.Result == nil {
   190  		return nil
   191  	}
   192  	return perrors.WithStack(json.Unmarshal(*c.rsp.Result, x))
   193  }
   194  
   195  type serverRequest struct {
   196  	Version string           `json:"jsonrpc"`
   197  	Method  string           `json:"method"`
   198  	Params  *json.RawMessage `json:"params"`
   199  	ID      *json.RawMessage `json:"id"`
   200  }
   201  
   202  func (r *serverRequest) reset() {
   203  	r.Version = ""
   204  	r.Method = ""
   205  	if r.Params != nil {
   206  		*r.Params = (*r.Params)[:0]
   207  	}
   208  	if r.ID != nil {
   209  		*r.ID = (*r.ID)[:0]
   210  	}
   211  }
   212  
   213  // UnmarshalJSON unmarshals JSON for server request.
   214  func (r *serverRequest) UnmarshalJSON(raw []byte) error {
   215  	r.reset()
   216  
   217  	type req *serverRequest
   218  	// Attention: if do not define a new struct named @req, the json.Unmarshal will invoke
   219  	// (*serverRequest)UnmarshalJSON recursively.
   220  	if err := json.Unmarshal(raw, req(r)); err != nil {
   221  		return perrors.New("bad request")
   222  	}
   223  
   224  	o := make(map[string]*json.RawMessage)
   225  	if err := json.Unmarshal(raw, &o); err != nil {
   226  		return perrors.New("bad request")
   227  	}
   228  	if o["jsonrpc"] == nil || o["method"] == nil {
   229  		return perrors.New("bad request")
   230  	}
   231  	_, okID := o["id"]
   232  	_, okParams := o["params"]
   233  	if len(o) == 3 && !(okID || okParams) || len(o) == 4 && !(okID && okParams) || len(o) > 4 {
   234  		return perrors.New("bad request")
   235  	}
   236  	if r.Version != Version {
   237  		return perrors.New("bad request")
   238  	}
   239  	if okParams {
   240  		if r.Params == nil || len(*r.Params) == 0 {
   241  			return perrors.New("bad request")
   242  		}
   243  		switch []byte(*r.Params)[0] {
   244  		case '[', '{':
   245  		default:
   246  			return perrors.New("bad request")
   247  		}
   248  	}
   249  	if okID && r.ID == nil {
   250  		r.ID = &null
   251  	}
   252  	if okID {
   253  		if len(*r.ID) == 0 {
   254  			return perrors.New("bad request")
   255  		}
   256  		switch []byte(*r.ID)[0] {
   257  		case 't', 'f', '{', '[':
   258  			return perrors.New("bad request")
   259  		}
   260  	}
   261  
   262  	return nil
   263  }
   264  
   265  type serverResponse struct {
   266  	Version string           `json:"jsonrpc"`
   267  	ID      *json.RawMessage `json:"id"`
   268  	Result  interface{}      `json:"result,omitempty"`
   269  	Error   interface{}      `json:"error,omitempty"`
   270  }
   271  
   272  // ServerCodec is codec data for request server.
   273  type ServerCodec struct {
   274  	req serverRequest
   275  }
   276  
   277  var (
   278  	null = json.RawMessage([]byte("null"))
   279  	// Version is json RPC's version
   280  	Version = "2.0"
   281  )
   282  
   283  func newServerCodec() *ServerCodec {
   284  	return &ServerCodec{}
   285  }
   286  
   287  // ReadHeader reads header and unmarshal to server codec
   288  func (c *ServerCodec) ReadHeader(header map[string]string, body []byte) error {
   289  	if header["HttpMethod"] != "POST" {
   290  		return &Error{Code: -32601, Message: "Method not found"}
   291  	}
   292  
   293  	// If return error:
   294  	// - codec will be closed
   295  	// So, try to send error reply to client before returning error.
   296  
   297  	buf := bytes.NewBuffer(body)
   298  	defer buf.Reset()
   299  	dec := json.NewDecoder(buf)
   300  
   301  	var raw json.RawMessage
   302  	c.req.reset()
   303  	if err := dec.Decode(&raw); err != nil {
   304  		// rspError := &Error{Code: -32700, Message: "Parse error"}
   305  		// c.resp = serverResponse{Version: Version, ID: &null, Error: rspError}
   306  		return err
   307  	}
   308  	if err := json.Unmarshal(raw, &c.req); err != nil {
   309  		// if err.Error() == "bad request" {
   310  		// 	rspError := &Error{Code: -32600, Message: "Invalid request"}
   311  		// 	c.resp = serverResponse{Version: Version, ID: &null, Error: rspError}
   312  		// }
   313  		return err
   314  	}
   315  
   316  	return nil
   317  }
   318  
   319  // ReadBody reads @x as request body.
   320  func (c *ServerCodec) ReadBody(x interface{}) error {
   321  	// If x!=nil and return error e:
   322  	// - Write() will be called with e.Error() in r.Error
   323  	if x == nil {
   324  		return nil
   325  	}
   326  	if c.req.Params == nil {
   327  		return nil
   328  	}
   329  
   330  	// the request parameter JSON string is converted to the corresponding struct
   331  	params := []byte(*c.req.Params)
   332  	if err := json.Unmarshal(*c.req.Params, x); err != nil {
   333  		// Note: if c.request.Params is nil it's not an error, it's an optional member.
   334  		// JSON params structured object. Unmarshal to the args object.
   335  
   336  		if 2 < len(params) && params[0] == '[' && params[len(params)-1] == ']' {
   337  			// Clearly JSON params is not a structured object,
   338  			// fallback and attempt an unmarshal with JSON params as
   339  			// array value and RPC params is struct. Unmarshal into
   340  			// array containing the request struct.
   341  			params := [1]interface{}{x}
   342  			if err = json.Unmarshal(*c.req.Params, &params); err != nil {
   343  				return &Error{Code: -32602, Message: "Invalid params, error:" + err.Error()}
   344  			}
   345  		} else {
   346  			return &Error{Code: -32602, Message: "Invalid params, error:" + err.Error()}
   347  		}
   348  	}
   349  
   350  	return nil
   351  }
   352  
   353  // NewError creates a error with @code and @message
   354  func NewError(code int, message string) *Error {
   355  	return &Error{Code: code, Message: message}
   356  }
   357  
   358  func newError(message string) *Error {
   359  	switch {
   360  	case strings.HasPrefix(message, "rpc: service/method request ill-formed"):
   361  		return NewError(-32601, message)
   362  	case strings.HasPrefix(message, "rpc: can't find service"):
   363  		return NewError(-32601, message)
   364  	case strings.HasPrefix(message, "rpc: can't find method"):
   365  		return NewError(-32601, message)
   366  	default:
   367  		return NewError(-32000, message)
   368  	}
   369  }
   370  
   371  // Write responses as byte
   372  func (c *ServerCodec) Write(errMsg string, x interface{}) ([]byte, error) {
   373  	// If return error: nothing happens.
   374  	// In r.Error will be "" or .Error() of error returned by:
   375  	// - ReadBody()
   376  	// - called RPC method
   377  	resp := serverResponse{Version: Version, ID: c.req.ID, Result: x}
   378  	if len(errMsg) == 0 {
   379  		if x == nil {
   380  			resp.Result = &null
   381  		} else {
   382  			resp.Result = x
   383  		}
   384  	} else if errMsg[0] == '{' && errMsg[len(errMsg)-1] == '}' {
   385  		// Well& this check for '{'&'}' isn't too strict, but I
   386  		// suppose we're trusting our own RPC methods (this way they
   387  		// can force sending wrong reply or many replies instead
   388  		// of one) and normal errors won't be formatted this way.
   389  		raw := json.RawMessage(errMsg)
   390  		resp.Error = &raw
   391  	} else {
   392  		raw := json.RawMessage(newError(errMsg).Error())
   393  		resp.Error = &raw
   394  	}
   395  
   396  	buf := bytes.NewBuffer(nil)
   397  	defer buf.Reset()
   398  	enc := json.NewEncoder(buf)
   399  	if err := enc.Encode(resp); err != nil {
   400  		return nil, perrors.WithStack(err)
   401  	}
   402  
   403  	return buf.Bytes(), nil
   404  }