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, ¶ms); 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 }