trpc.group/trpc-go/trpc-go@v1.0.3/codec.go (about) 1 // 2 // 3 // Tencent is pleased to support the open source community by making tRPC available. 4 // 5 // Copyright (C) 2023 THL A29 Limited, a Tencent company. 6 // All rights reserved. 7 // 8 // If you have downloaded a copy of the tRPC source code from Tencent, 9 // please note that tRPC source code is licensed under the Apache 2.0 License, 10 // A copy of the Apache 2.0 License is included in this file. 11 // 12 // 13 14 package trpc 15 16 import ( 17 "encoding/binary" 18 "errors" 19 "fmt" 20 "io" 21 "math" 22 "os" 23 "path" 24 "sync/atomic" 25 "time" 26 27 "trpc.group/trpc-go/trpc-go/codec" 28 "trpc.group/trpc-go/trpc-go/errs" 29 "trpc.group/trpc-go/trpc-go/internal/attachment" 30 "trpc.group/trpc-go/trpc-go/transport" 31 32 "google.golang.org/protobuf/proto" 33 trpcpb "trpc.group/trpc/trpc-protocol/pb/go/trpc" 34 ) 35 36 func init() { 37 codec.Register(ProtocolName, DefaultServerCodec, DefaultClientCodec) 38 transport.RegisterFramerBuilder(ProtocolName, DefaultFramerBuilder) 39 } 40 41 // default codec 42 var ( 43 DefaultServerCodec = &ServerCodec{ 44 streamCodec: NewServerStreamCodec(), 45 } 46 DefaultClientCodec = &ClientCodec{ 47 streamCodec: NewClientStreamCodec(), 48 defaultCaller: fmt.Sprintf("trpc.client.%s.service", path.Base(os.Args[0])), 49 } 50 DefaultFramerBuilder = &FramerBuilder{} 51 52 // DefaultMaxFrameSize is the default max size of frame including attachment, 53 // which can be modified if size of the packet is bigger than this. 54 DefaultMaxFrameSize = 10 * 1024 * 1024 55 ) 56 57 var ( 58 errHeadOverflowsUint16 = errors.New("head len overflows uint16") 59 errHeadOverflowsUint32 = errors.New("total len overflows uint32") 60 errAttachmentOverflowsUint32 = errors.New("attachment len overflows uint32") 61 ) 62 63 type errFrameTooLarge struct { 64 maxFrameSize int 65 } 66 67 // Error implements the error interface and returns the description of the errFrameTooLarge. 68 func (e *errFrameTooLarge) Error() string { 69 return fmt.Sprintf("frame len is larger than MaxFrameSize(%d)", e.maxFrameSize) 70 } 71 72 // frequently used const variables 73 const ( 74 DyeingKey = "trpc-dyeing-key" // dyeing key 75 UserIP = "trpc-user-ip" // user ip 76 EnvTransfer = "trpc-env" // env info 77 78 ProtocolName = "trpc" // protocol name 79 ) 80 81 // trpc protocol codec 82 const ( 83 // frame head format: 84 // v0: 85 // 2 bytes magic + 1 byte frame type + 1 byte stream frame type + 4 bytes total len 86 // + 2 bytes pb header len + 4 bytes stream id + 2 bytes reserved 87 // v1: 88 // 2 bytes magic + 1 byte frame type + 1 byte stream frame type + 4 bytes total len 89 // + 2 bytes pb header len + 4 bytes stream id + 1 byte protocol version + 1 byte reserved 90 frameHeadLen = uint16(16) // total length of frame head: 16 bytes 91 protocolVersion0 = uint8(0) // v0 92 protocolVersion1 = uint8(1) // v1 93 curProtocolVersion = protocolVersion1 // current protocol version 94 ) 95 96 // FrameHead is head of the trpc frame. 97 type FrameHead struct { 98 FrameType uint8 // type of the frame 99 StreamFrameType uint8 // type of the stream frame 100 TotalLen uint32 // total length 101 HeaderLen uint16 // header's length 102 StreamID uint32 // stream id for streaming rpc, request id for unary rpc 103 ProtocolVersion uint8 // version of protocol 104 FrameReserved uint8 // reserved bits for further development 105 } 106 107 func newDefaultUnaryFrameHead() *FrameHead { 108 return &FrameHead{ 109 FrameType: uint8(trpcpb.TrpcDataFrameType_TRPC_UNARY_FRAME), // default unary 110 ProtocolVersion: curProtocolVersion, 111 } 112 } 113 114 // extract extracts field values of the FrameHead from the buffer. 115 func (h *FrameHead) extract(buf []byte) { 116 h.FrameType = buf[2] 117 h.StreamFrameType = buf[3] 118 h.TotalLen = binary.BigEndian.Uint32(buf[4:8]) 119 h.HeaderLen = binary.BigEndian.Uint16(buf[8:10]) 120 h.StreamID = binary.BigEndian.Uint32(buf[10:14]) 121 h.ProtocolVersion = buf[14] 122 h.FrameReserved = buf[15] 123 } 124 125 // construct constructs bytes data for the whole frame. 126 func (h *FrameHead) construct(header, body, attachment []byte) ([]byte, error) { 127 headerLen := len(header) 128 if headerLen > math.MaxUint16 { 129 return nil, errHeadOverflowsUint16 130 } 131 attachmentLen := int64(len(attachment)) 132 if attachmentLen > math.MaxUint32 { 133 return nil, errAttachmentOverflowsUint32 134 } 135 totalLen := int64(frameHeadLen) + int64(headerLen) + int64(len(body)) + attachmentLen 136 if totalLen > int64(DefaultMaxFrameSize) { 137 return nil, &errFrameTooLarge{maxFrameSize: DefaultMaxFrameSize} 138 } 139 if totalLen > math.MaxUint32 { 140 return nil, errHeadOverflowsUint32 141 } 142 143 // construct the buffer 144 buf := make([]byte, totalLen) 145 binary.BigEndian.PutUint16(buf[:2], uint16(trpcpb.TrpcMagic_TRPC_MAGIC_VALUE)) 146 buf[2] = h.FrameType 147 buf[3] = h.StreamFrameType 148 binary.BigEndian.PutUint32(buf[4:8], uint32(totalLen)) 149 binary.BigEndian.PutUint16(buf[8:10], uint16(headerLen)) 150 binary.BigEndian.PutUint32(buf[10:14], h.StreamID) 151 buf[14] = h.ProtocolVersion 152 buf[15] = h.FrameReserved 153 154 frameHeadLen := int(frameHeadLen) 155 copy(buf[frameHeadLen:frameHeadLen+headerLen], header) 156 copy(buf[frameHeadLen+headerLen:frameHeadLen+headerLen+len(body)], body) 157 copy(buf[frameHeadLen+headerLen+len(body):], attachment) 158 return buf, nil 159 } 160 161 func (h *FrameHead) isStream() bool { 162 return trpcpb.TrpcDataFrameType(h.FrameType) == trpcpb.TrpcDataFrameType_TRPC_STREAM_FRAME 163 } 164 165 func (h *FrameHead) isUnary() bool { 166 return trpcpb.TrpcDataFrameType(h.FrameType) == trpcpb.TrpcDataFrameType_TRPC_UNARY_FRAME 167 } 168 169 // upgradeProtocol upgrades protocol and sets stream id and request id. 170 // For compatibility, server should respond the same protocol version as that of the request. 171 // and client should always send request with the latest protocol version. 172 func (h *FrameHead) upgradeProtocol(protocolVersion uint8, requestID uint32) { 173 h.ProtocolVersion = protocolVersion 174 h.StreamID = requestID 175 } 176 177 // FramerBuilder is an implementation of codec.FramerBuilder. 178 // Used for trpc protocol. 179 type FramerBuilder struct{} 180 181 // New implements codec.FramerBuilder. 182 func (fb *FramerBuilder) New(reader io.Reader) codec.Framer { 183 return &framer{ 184 reader: reader, 185 } 186 } 187 188 // Parse implement multiplexed.FrameParser interface. 189 func (fb *FramerBuilder) Parse(rc io.Reader) (vid uint32, buf []byte, err error) { 190 buf, err = fb.New(rc).ReadFrame() 191 if err != nil { 192 return 0, nil, err 193 } 194 return binary.BigEndian.Uint32(buf[10:14]), buf, nil 195 } 196 197 // framer is an implementation of codec.Framer. 198 // Used for trpc protocol. 199 type framer struct { 200 reader io.Reader 201 header [frameHeadLen]byte 202 } 203 204 // ReadFrame implements codec.Framer. 205 func (f *framer) ReadFrame() ([]byte, error) { 206 num, err := io.ReadFull(f.reader, f.header[:]) 207 if err != nil { 208 return nil, err 209 } 210 if num != int(frameHeadLen) { 211 return nil, fmt.Errorf("trpc framer: read frame header num %d != %d, invalid", num, int(frameHeadLen)) 212 } 213 magic := binary.BigEndian.Uint16(f.header[:2]) 214 if magic != uint16(trpcpb.TrpcMagic_TRPC_MAGIC_VALUE) { 215 return nil, fmt.Errorf( 216 "trpc framer: read framer head magic %d != %d, not match", magic, uint16(trpcpb.TrpcMagic_TRPC_MAGIC_VALUE)) 217 } 218 totalLen := binary.BigEndian.Uint32(f.header[4:8]) 219 if totalLen < uint32(frameHeadLen) { 220 return nil, fmt.Errorf( 221 "trpc framer: read frame header total len %d < %d, invalid", totalLen, uint32(frameHeadLen)) 222 } 223 224 if totalLen > uint32(DefaultMaxFrameSize) { 225 return nil, fmt.Errorf( 226 "trpc framer: read frame header total len %d > %d, too large", totalLen, uint32(DefaultMaxFrameSize)) 227 } 228 229 msg := make([]byte, totalLen) 230 num, err = io.ReadFull(f.reader, msg[frameHeadLen:totalLen]) 231 if err != nil { 232 return nil, err 233 } 234 if num != int(totalLen-uint32(frameHeadLen)) { 235 return nil, fmt.Errorf( 236 "trpc framer: read frame total num %d != %d, invalid", num, int(totalLen-uint32(frameHeadLen))) 237 } 238 copy(msg, f.header[:]) 239 return msg, nil 240 } 241 242 // IsSafe implements codec.SafeFramer. 243 // Used for compatibility. 244 func (f *framer) IsSafe() bool { 245 return true 246 } 247 248 // ServerCodec is an implementation of codec.Codec. 249 // Used for trpc serverside codec. 250 type ServerCodec struct { 251 streamCodec *ServerStreamCodec 252 } 253 254 // Decode implements codec.Codec. 255 // It decodes the reqBuf and updates the msg that already initialized by service handler. 256 func (s *ServerCodec) Decode(msg codec.Msg, reqBuf []byte) ([]byte, error) { 257 if len(reqBuf) < int(frameHeadLen) { 258 return nil, errors.New("server decode req buf len invalid") 259 } 260 frameHead := newDefaultUnaryFrameHead() 261 frameHead.extract(reqBuf) 262 msg.WithFrameHead(frameHead) 263 if frameHead.TotalLen != uint32(len(reqBuf)) { 264 return nil, fmt.Errorf("total len %d is not actual buf len %d", frameHead.TotalLen, len(reqBuf)) 265 } 266 if frameHead.FrameType != uint8(trpcpb.TrpcDataFrameType_TRPC_UNARY_FRAME) { // streaming rpc has its own decoding 267 rspBody, err := s.streamCodec.Decode(msg, reqBuf) 268 if err != nil { 269 // if decoding fails, the Close frame with Reset type will be returned to the client 270 err := errs.NewFrameError(errs.RetServerDecodeFail, err.Error()) 271 s.streamCodec.buildResetFrame(msg, frameHead, err) 272 return nil, err 273 } 274 return rspBody, nil 275 } 276 if frameHead.HeaderLen == 0 { // header not allowed to be empty for unary rpc 277 return nil, errors.New("server decode pb head len empty") 278 } 279 280 requestProtocolBegin := uint32(frameHeadLen) 281 requestProtocolEnd := requestProtocolBegin + uint32(frameHead.HeaderLen) 282 if requestProtocolEnd > uint32(len(reqBuf)) { 283 return nil, errors.New("server decode pb head len invalid") 284 } 285 req := &trpcpb.RequestProtocol{} 286 if err := proto.Unmarshal(reqBuf[requestProtocolBegin:requestProtocolEnd], req); err != nil { 287 return nil, err 288 } 289 290 attachmentBegin := frameHead.TotalLen - req.AttachmentSize 291 if s := uint32(len(reqBuf)) - attachmentBegin; s != req.AttachmentSize { 292 return nil, fmt.Errorf("decoding attachment: len of attachment(%d) "+ 293 "isn't equal to expected AttachmentSize(%d) ", s, req.AttachmentSize) 294 } 295 296 msgWithRequestProtocol(msg, req, reqBuf[attachmentBegin:]) 297 298 requestBodyBegin, requestBodyEnd := requestProtocolEnd, attachmentBegin 299 return reqBuf[requestBodyBegin:requestBodyEnd], nil 300 } 301 302 func msgWithRequestProtocol(msg codec.Msg, req *trpcpb.RequestProtocol, attm []byte) { 303 // set server request head 304 msg.WithServerReqHead(req) 305 // construct response protocol head in advance 306 rsp := newResponseProtocol(req) 307 msg.WithServerRspHead(rsp) 308 309 // ---------the following code is to set the essential info-----------// 310 // set upstream timeout 311 msg.WithRequestTimeout(time.Millisecond * time.Duration(req.GetTimeout())) 312 // set upstream service name 313 msg.WithCallerServiceName(string(req.GetCaller())) 314 msg.WithCalleeServiceName(string(req.GetCallee())) 315 // set server handler method name 316 msg.WithServerRPCName(string(req.GetFunc())) 317 // set body serialization type 318 msg.WithSerializationType(int(req.GetContentType())) 319 // set body compression type 320 msg.WithCompressType(int(req.GetContentEncoding())) 321 // set dyeing mark 322 msg.WithDyeing((req.GetMessageType() & uint32(trpcpb.TrpcMessageType_TRPC_DYEING_MESSAGE)) != 0) 323 // parse tracing MetaData, set MetaData into msg 324 if len(req.TransInfo) > 0 { 325 msg.WithServerMetaData(req.GetTransInfo()) 326 // mark with dyeing key 327 if bs, ok := req.TransInfo[DyeingKey]; ok { 328 msg.WithDyeingKey(string(bs)) 329 } 330 // transmit env info 331 if envs, ok := req.TransInfo[EnvTransfer]; ok { 332 msg.WithEnvTransfer(string(envs)) 333 } 334 } 335 // set call type 336 msg.WithCallType(codec.RequestType(req.GetCallType())) 337 if len(attm) != 0 { 338 attachment.SetServerRequestAttachment(msg, attm) 339 } 340 } 341 342 // Encode implements codec.Codec. 343 // It encodes the rspBody to binary data and returns it to client. 344 func (s *ServerCodec) Encode(msg codec.Msg, rspBody []byte) ([]byte, error) { 345 frameHead := loadOrStoreDefaultUnaryFrameHead(msg) 346 if frameHead.isStream() { 347 return s.streamCodec.Encode(msg, rspBody) 348 } 349 if !frameHead.isUnary() { 350 return nil, errUnknownFrameType 351 } 352 353 rspProtocol := getAndInitResponseProtocol(msg) 354 355 var attm []byte 356 if a, ok := attachment.ServerResponseAttachment(msg); ok { 357 var err error 358 if attm, err = io.ReadAll(a); err != nil { 359 return nil, fmt.Errorf("encoding attachment: %w", err) 360 } 361 } 362 rspProtocol.AttachmentSize = uint32(len(attm)) 363 364 rspHead, err := proto.Marshal(rspProtocol) 365 if err != nil { 366 return nil, err 367 } 368 369 rspBuf, err := frameHead.construct(rspHead, rspBody, attm) 370 if errors.Is(err, errHeadOverflowsUint16) { 371 return handleEncodeErr(rspProtocol, frameHead, rspBody, err) 372 } 373 var frameTooLargeErr *errFrameTooLarge 374 if errors.As(err, &frameTooLargeErr) || errors.Is(err, errHeadOverflowsUint32) { 375 // If frame len is larger than DefaultMaxFrameSize or overflows uint32, set rspBody nil. 376 return handleEncodeErr(rspProtocol, frameHead, nil, err) 377 } 378 return rspBuf, err 379 } 380 381 // getAndInitResponseProtocol returns rsp head from msg and initialize the rsp with msg. 382 // If rsp head is not found from msg, a new rsp head will be created and initialized. 383 func getAndInitResponseProtocol(msg codec.Msg) *trpcpb.ResponseProtocol { 384 rsp, ok := msg.ServerRspHead().(*trpcpb.ResponseProtocol) 385 if !ok { 386 if req, ok := msg.ServerReqHead().(*trpcpb.RequestProtocol); ok { 387 rsp = newResponseProtocol(req) 388 } else { 389 rsp = &trpcpb.ResponseProtocol{} 390 } 391 } 392 393 // update serialization and compression type 394 rsp.ContentType = uint32(msg.SerializationType()) 395 rsp.ContentEncoding = uint32(msg.CompressType()) 396 397 // convert error returned by server handler to ret code in response protocol head 398 if err := msg.ServerRspErr(); err != nil { 399 rsp.ErrorMsg = []byte(err.Msg) 400 if err.Type == errs.ErrorTypeFramework { 401 rsp.Ret = int32(err.Code) 402 } else { 403 rsp.FuncRet = int32(err.Code) 404 } 405 } 406 407 if len(msg.ServerMetaData()) > 0 { 408 if rsp.TransInfo == nil { 409 rsp.TransInfo = make(map[string][]byte) 410 } 411 for k, v := range msg.ServerMetaData() { 412 rsp.TransInfo[k] = v 413 } 414 } 415 416 return rsp 417 } 418 419 func newResponseProtocol(req *trpcpb.RequestProtocol) *trpcpb.ResponseProtocol { 420 return &trpcpb.ResponseProtocol{ 421 Version: uint32(trpcpb.TrpcProtoVersion_TRPC_PROTO_V1), 422 CallType: req.CallType, 423 RequestId: req.RequestId, 424 MessageType: req.MessageType, 425 ContentType: req.ContentType, 426 ContentEncoding: req.ContentEncoding, 427 } 428 } 429 430 // handleEncodeErr handles encode err and returns RetServerEncodeFail. 431 func handleEncodeErr( 432 rsp *trpcpb.ResponseProtocol, 433 frameHead *FrameHead, 434 rspBody []byte, 435 encodeErr error, 436 ) ([]byte, error) { 437 // discard all TransInfo and return RetServerEncodeFail 438 // cover the original no matter what 439 rsp.TransInfo = nil 440 rsp.Ret = int32(errs.RetServerEncodeFail) 441 rsp.ErrorMsg = []byte(encodeErr.Error()) 442 rspHead, err := proto.Marshal(rsp) 443 if err != nil { 444 return nil, err 445 } 446 // if error still occurs, response will be discarded. 447 // client will be notified as conn closed 448 return frameHead.construct(rspHead, rspBody, nil) 449 } 450 451 // ClientCodec is an implementation of codec.Codec. 452 // Used for trpc clientside codec. 453 type ClientCodec struct { 454 streamCodec *ClientStreamCodec 455 defaultCaller string // trpc.app.server.service 456 requestID uint32 // global unique request id 457 } 458 459 // Encode implements codec.Codec. 460 // It encodes reqBody into binary data. New msg will be cloned by client stub. 461 func (c *ClientCodec) Encode(msg codec.Msg, reqBody []byte) (reqBuf []byte, err error) { 462 frameHead := loadOrStoreDefaultUnaryFrameHead(msg) 463 if frameHead.isStream() { 464 return c.streamCodec.Encode(msg, reqBody) 465 } 466 if !frameHead.isUnary() { 467 return nil, errUnknownFrameType 468 } 469 470 // create a new framehead without modifying the original one 471 // to avoid overwriting the requestID of the original framehead. 472 frameHead = newDefaultUnaryFrameHead() 473 req, err := loadOrStoreDefaultRequestProtocol(msg) 474 if err != nil { 475 return nil, err 476 } 477 478 // request id atomically increases by 1, ensuring that each request id is unique. 479 requestID := atomic.AddUint32(&c.requestID, 1) 480 frameHead.upgradeProtocol(curProtocolVersion, requestID) 481 msg.WithRequestID(requestID) 482 483 var attm []byte 484 if a, ok := attachment.ClientRequestAttachment(msg); ok { 485 if attm, err = io.ReadAll(a); err != nil { 486 return nil, fmt.Errorf("encoding attachment: %w", err) 487 } 488 } 489 req.AttachmentSize = uint32(len(attm)) 490 491 updateRequestProtocol(req, updateCallerServiceName(msg, c.defaultCaller)) 492 493 reqHead, err := proto.Marshal(req) 494 if err != nil { 495 return nil, err 496 } 497 return frameHead.construct(reqHead, reqBody, attm) 498 } 499 500 // loadOrStoreDefaultRequestProtocol loads the existing RequestProtocol from msg if present. 501 // Otherwise, it stores default UnaryRequestProtocol created to msg and returns the default RequestProtocol. 502 func loadOrStoreDefaultRequestProtocol(msg codec.Msg) (*trpcpb.RequestProtocol, error) { 503 if req := msg.ClientReqHead(); req != nil { 504 // client req head not being nil means it's created on purpose and set to 505 // record request protocol head 506 req, ok := req.(*trpcpb.RequestProtocol) 507 if !ok { 508 return nil, errors.New("client encode req head type invalid, must be trpc request protocol head") 509 } 510 return req, nil 511 } 512 513 req := newDefaultUnaryRequestProtocol() 514 msg.WithClientReqHead(req) 515 return req, nil 516 } 517 518 func newDefaultUnaryRequestProtocol() *trpcpb.RequestProtocol { 519 return &trpcpb.RequestProtocol{ 520 Version: uint32(trpcpb.TrpcProtoVersion_TRPC_PROTO_V1), 521 CallType: uint32(trpcpb.TrpcCallType_TRPC_UNARY_CALL), 522 } 523 } 524 525 // update updates CallerServiceName of msg with name 526 func updateCallerServiceName(msg codec.Msg, name string) codec.Msg { 527 if msg.CallerServiceName() == "" { 528 msg.WithCallerServiceName(name) 529 } 530 return msg 531 } 532 533 // update updates req with requestID and msg. 534 func updateRequestProtocol(req *trpcpb.RequestProtocol, msg codec.Msg) { 535 req.RequestId = msg.RequestID() 536 req.Caller = []byte(msg.CallerServiceName()) 537 // set callee service name 538 req.Callee = []byte(msg.CalleeServiceName()) 539 // set backend rpc name 540 req.Func = []byte(msg.ClientRPCName()) 541 // set backend serialization type 542 req.ContentType = uint32(msg.SerializationType()) 543 // set backend compression type 544 req.ContentEncoding = uint32(msg.CompressType()) 545 // set rest timeout for downstream 546 req.Timeout = uint32(msg.RequestTimeout() / time.Millisecond) 547 // set dyeing info 548 if msg.Dyeing() { 549 req.MessageType = req.MessageType | uint32(trpcpb.TrpcMessageType_TRPC_DYEING_MESSAGE) 550 } 551 // set client transinfo 552 req.TransInfo = setClientTransInfo(msg, req.TransInfo) 553 // set call type 554 req.CallType = uint32(msg.CallType()) 555 } 556 557 // setClientTransInfo sets client TransInfo. 558 func setClientTransInfo(msg codec.Msg, trans map[string][]byte) map[string][]byte { 559 // set MetaData 560 if len(msg.ClientMetaData()) > 0 { 561 if trans == nil { 562 trans = make(map[string][]byte) 563 } 564 for k, v := range msg.ClientMetaData() { 565 trans[k] = v 566 } 567 } 568 if len(msg.DyeingKey()) > 0 { 569 if trans == nil { 570 trans = make(map[string][]byte) 571 } 572 trans[DyeingKey] = []byte(msg.DyeingKey()) 573 } 574 if len(msg.EnvTransfer()) > 0 { 575 if trans == nil { 576 trans = make(map[string][]byte) 577 } 578 trans[EnvTransfer] = []byte(msg.EnvTransfer()) 579 } else { 580 // if msg.EnvTransfer() empty, transmitted env info in req.TransInfo should be cleared 581 if _, ok := trans[EnvTransfer]; ok { 582 trans[EnvTransfer] = nil 583 } 584 } 585 return trans 586 } 587 588 // Decode implements codec.Codec. 589 // It decodes rspBuf into rspBody. 590 func (c *ClientCodec) Decode(msg codec.Msg, rspBuf []byte) (rspBody []byte, err error) { 591 if len(rspBuf) < int(frameHeadLen) { 592 return nil, errors.New("client decode rsp buf len invalid") 593 } 594 frameHead := newDefaultUnaryFrameHead() 595 frameHead.extract(rspBuf) 596 msg.WithFrameHead(frameHead) 597 if frameHead.TotalLen != uint32(len(rspBuf)) { 598 return nil, fmt.Errorf("total len %d is not actual buf len %d", frameHead.TotalLen, len(rspBuf)) 599 } 600 if trpcpb.TrpcDataFrameType(frameHead.FrameType) != trpcpb.TrpcDataFrameType_TRPC_UNARY_FRAME { 601 return c.streamCodec.Decode(msg, rspBuf) 602 } 603 if frameHead.HeaderLen == 0 { 604 return nil, errors.New("client decode pb head len empty") 605 } 606 607 responseProtocolBegin := uint32(frameHeadLen) 608 responseProtocolEnd := responseProtocolBegin + uint32(frameHead.HeaderLen) 609 if responseProtocolEnd > uint32(len(rspBuf)) { 610 return nil, errors.New("client decode pb head len invalid") 611 } 612 rsp, err := loadOrStoreResponseHead(msg) 613 if err != nil { 614 return nil, err 615 } 616 if err := proto.Unmarshal(rspBuf[responseProtocolBegin:responseProtocolEnd], rsp); err != nil { 617 return nil, err 618 } 619 620 attachmentBegin := frameHead.TotalLen - rsp.AttachmentSize 621 if s := uint32(len(rspBuf)) - attachmentBegin; rsp.AttachmentSize != s { 622 return nil, fmt.Errorf("decoding attachment:(%d) len of attachment"+ 623 "isn't equal to expected AttachmentSize(%d)", s, rsp.AttachmentSize) 624 } 625 if err := updateMsg(msg, frameHead, rsp, rspBuf[attachmentBegin:]); err != nil { 626 return nil, err 627 } 628 629 bodyBegin, bodyEnd := responseProtocolEnd, attachmentBegin 630 return rspBuf[bodyBegin:bodyEnd], nil 631 } 632 633 func loadOrStoreResponseHead(msg codec.Msg) (*trpcpb.ResponseProtocol, error) { 634 // client rsp head being nil means no need to record backend response protocol head 635 // most of the time, response head is not set and should be created here. 636 rsp := msg.ClientRspHead() 637 if rsp == nil { 638 rsp := &trpcpb.ResponseProtocol{} 639 msg.WithClientRspHead(rsp) 640 return rsp, nil 641 } 642 643 // client rsp head not being nil means it's created on purpose and set to 644 // record response protocol head 645 { 646 rsp, ok := rsp.(*trpcpb.ResponseProtocol) 647 if !ok { 648 return nil, errors.New("client decode rsp head type invalid, must be trpc response protocol head") 649 } 650 return rsp, nil 651 } 652 } 653 654 // loadOrStoreDefaultUnaryFrameHead loads the existing frameHead from msg if present. 655 // Otherwise, it stores default Unary FrameHead to msg, and returns the default Unary FrameHead. 656 func loadOrStoreDefaultUnaryFrameHead(msg codec.Msg) *FrameHead { 657 frameHead, ok := msg.FrameHead().(*FrameHead) 658 if !ok { 659 frameHead = newDefaultUnaryFrameHead() 660 msg.WithFrameHead(frameHead) 661 } 662 return frameHead 663 } 664 665 func updateMsg(msg codec.Msg, frameHead *FrameHead, rsp *trpcpb.ResponseProtocol, attm []byte) error { 666 msg.WithFrameHead(frameHead) 667 msg.WithCompressType(int(rsp.GetContentEncoding())) 668 msg.WithSerializationType(int(rsp.GetContentType())) 669 670 // reset client metadata if new transinfo is returned with response 671 if len(rsp.TransInfo) > 0 { 672 md := msg.ClientMetaData() 673 if len(md) == 0 { 674 md = codec.MetaData{} 675 } 676 for k, v := range rsp.TransInfo { 677 md[k] = v 678 } 679 msg.WithClientMetaData(md) 680 } 681 682 // if retcode is not 0, a converted error should be returned 683 if rsp.GetRet() != 0 { 684 err := &errs.Error{ 685 Type: errs.ErrorTypeCalleeFramework, 686 Code: trpcpb.TrpcRetCode(rsp.GetRet()), 687 Desc: ProtocolName, 688 Msg: string(rsp.GetErrorMsg()), 689 } 690 msg.WithClientRspErr(err) 691 } else if rsp.GetFuncRet() != 0 { 692 msg.WithClientRspErr(errs.New(int(rsp.GetFuncRet()), string(rsp.GetErrorMsg()))) 693 } 694 695 // error should be returned immediately for request id mismatch 696 req, err := loadOrStoreDefaultRequestProtocol(msg) 697 if err == nil && rsp.RequestId != req.RequestId { 698 return fmt.Errorf("rsp request_id %d different from req request_id %d", rsp.RequestId, req.RequestId) 699 } 700 701 // handle protocol upgrading 702 frameHead.upgradeProtocol(curProtocolVersion, rsp.RequestId) 703 msg.WithRequestID(rsp.RequestId) 704 705 if len(attm) != 0 { 706 attachment.SetClientResponseAttachment(msg, attm) 707 } 708 return nil 709 }