dubbo.apache.org/dubbo-go/v3@v3.1.1/protocol/dubbo/hessian2/hessian_request.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 hessian2 19 20 import ( 21 "encoding/binary" 22 "strconv" 23 "strings" 24 "time" 25 ) 26 27 import ( 28 hessian "github.com/apache/dubbo-go-hessian2" 29 30 "github.com/dubbogo/gost/log/logger" 31 32 perrors "github.com/pkg/errors" 33 ) 34 35 func getArgType(v interface{}) string { 36 return GetClassDesc(v) 37 } 38 39 func getArgsTypeList(args []interface{}) (string, error) { 40 var ( 41 typ string 42 types string 43 ) 44 45 for i := range args { 46 typ = getArgType(args[i]) 47 if typ == "" { 48 return types, perrors.Errorf("cat not get arg %#v type", args[i]) 49 } 50 if !strings.Contains(typ, ".") { 51 types += typ 52 } else if strings.Index(typ, "[") == 0 { 53 types += strings.Replace(typ, ".", "/", -1) 54 } else { 55 // java.util.List -> Ljava/util/List; 56 types += "L" + strings.Replace(typ, ".", "/", -1) + ";" 57 } 58 } 59 60 return types, nil 61 } 62 63 type DubboRequest struct { 64 Params interface{} 65 Attachments map[string]interface{} 66 } 67 68 // NewRequest create a new DubboRequest 69 func NewRequest(params interface{}, atta map[string]interface{}) *DubboRequest { 70 if atta == nil { 71 atta = make(map[string]interface{}) 72 } 73 return &DubboRequest{ 74 Params: params, 75 Attachments: atta, 76 } 77 } 78 79 func EnsureRequest(body interface{}) *DubboRequest { 80 if req, ok := body.(*DubboRequest); ok { 81 return req 82 } 83 return NewRequest(body, nil) 84 } 85 86 func packRequest(service Service, header DubboHeader, req interface{}) ([]byte, error) { 87 var ( 88 err error 89 types string 90 byteArray []byte 91 pkgLen int 92 ) 93 94 request := EnsureRequest(req) 95 96 args, ok := request.Params.([]interface{}) 97 if !ok { 98 return nil, perrors.Errorf("@params is not of type: []interface{}") 99 } 100 101 hb := header.Type == PackageHeartbeat 102 103 ////////////////////////////////////////// 104 // byteArray 105 ////////////////////////////////////////// 106 // magic 107 switch header.Type { 108 case PackageHeartbeat: 109 byteArray = append(byteArray, DubboRequestHeartbeatHeader[:]...) 110 case PackageRequest_TwoWay: 111 byteArray = append(byteArray, DubboRequestHeaderBytesTwoWay[:]...) 112 default: 113 byteArray = append(byteArray, DubboRequestHeaderBytes[:]...) 114 } 115 116 // serialization id, two way flag, event, request/response flag 117 // SerialID is id of serialization approach in java dubbo 118 byteArray[2] |= header.SerialID & SERIAL_MASK 119 // request id 120 binary.BigEndian.PutUint64(byteArray[4:], uint64(header.ID)) 121 122 encoder := hessian.NewEncoder() 123 encoder.Append(byteArray[:HEADER_LENGTH]) 124 125 ////////////////////////////////////////// 126 // body 127 ////////////////////////////////////////// 128 if hb { 129 _ = encoder.Encode(nil) 130 goto END 131 } 132 133 // dubbo version + path + version + method 134 if err = encoder.Encode(DEFAULT_DUBBO_PROTOCOL_VERSION); err != nil { 135 logger.Warnf("Encode(DEFAULT_DUBBO_PROTOCOL_VERSION) = error: %v", err) 136 } 137 if err = encoder.Encode(service.Path); err != nil { 138 logger.Warnf("Encode(service.Path) = error: %v", err) 139 } 140 if err = encoder.Encode(service.Version); err != nil { 141 logger.Warnf("Encode(service.Version) = error: %v", err) 142 } 143 if err = encoder.Encode(service.Method); err != nil { 144 logger.Warnf("Encode(service.Method) = error: %v", err) 145 } 146 147 // args = args type list + args value list 148 if types, err = getArgsTypeList(args); err != nil { 149 return nil, perrors.Wrapf(err, " PackRequest(args:%+v)", args) 150 } 151 _ = encoder.Encode(types) 152 for _, v := range args { 153 _ = encoder.Encode(v) 154 } 155 156 request.Attachments[PATH_KEY] = service.Path 157 request.Attachments[VERSION_KEY] = service.Version 158 if len(service.Group) > 0 { 159 request.Attachments[GROUP_KEY] = service.Group 160 } 161 if len(service.Interface) > 0 { 162 request.Attachments[INTERFACE_KEY] = service.Interface 163 } 164 if service.Timeout != 0 { 165 request.Attachments[TIMEOUT_KEY] = strconv.Itoa(int(service.Timeout / time.Millisecond)) 166 } 167 168 _ = encoder.Encode(request.Attachments) 169 170 END: 171 byteArray = encoder.Buffer() 172 pkgLen = len(byteArray) 173 if pkgLen > int(DEFAULT_LEN) { // recommand 8M 174 logger.Warnf("Data length %d too large, recommand max payload %d. "+ 175 "Dubbo java can't handle the package whose size is greater than %d!!!", pkgLen, DEFAULT_LEN, DEFAULT_LEN) 176 } 177 // byteArray{body length} 178 binary.BigEndian.PutUint32(byteArray[12:], uint32(pkgLen-HEADER_LENGTH)) 179 return byteArray, nil 180 } 181 182 // hessian decode request body 183 func unpackRequestBody(decoder *hessian.Decoder, reqObj interface{}) error { 184 if decoder == nil { 185 return perrors.Errorf("@decoder is nil") 186 } 187 188 req, ok := reqObj.([]interface{}) 189 if !ok { 190 return perrors.Errorf("@reqObj is not of type: []interface{}") 191 } 192 if len(req) < 7 { 193 return perrors.New("length of @reqObj should be 7") 194 } 195 196 var ( 197 err error 198 dubboVersion, target, serviceVersion, method, argsTypes interface{} 199 args []interface{} 200 ) 201 202 dubboVersion, err = decoder.Decode() 203 if err != nil { 204 return perrors.WithStack(err) 205 } 206 req[0] = dubboVersion 207 208 target, err = decoder.Decode() 209 if err != nil { 210 return perrors.WithStack(err) 211 } 212 req[1] = target 213 214 serviceVersion, err = decoder.Decode() 215 if err != nil { 216 return perrors.WithStack(err) 217 } 218 req[2] = serviceVersion 219 220 method, err = decoder.Decode() 221 if err != nil { 222 return perrors.WithStack(err) 223 } 224 req[3] = method 225 226 argsTypes, err = decoder.Decode() 227 if err != nil { 228 return perrors.WithStack(err) 229 } 230 req[4] = argsTypes 231 232 ats := DescRegex.FindAllString(argsTypes.(string), -1) 233 var arg interface{} 234 for i := 0; i < len(ats); i++ { 235 arg, err = decoder.Decode() 236 if err != nil { 237 return perrors.WithStack(err) 238 } 239 args = append(args, arg) 240 } 241 req[5] = args 242 243 attachments, err := decoder.Decode() 244 if err != nil { 245 return perrors.WithStack(err) 246 } 247 if v, ok := attachments.(map[interface{}]interface{}); ok { 248 v[DUBBO_VERSION_KEY] = dubboVersion 249 req[6] = ToMapStringInterface(v) 250 return nil 251 } 252 253 return perrors.Errorf("get wrong attachments: %+v", attachments) 254 } 255 256 func ToMapStringInterface(origin map[interface{}]interface{}) map[string]interface{} { 257 dest := make(map[string]interface{}, len(origin)) 258 for k, v := range origin { 259 if kv, ok := k.(string); ok { 260 if v == nil { 261 dest[kv] = "" 262 continue 263 } 264 dest[kv] = v 265 } 266 } 267 return dest 268 }