dubbo.apache.org/dubbo-go/v3@v3.1.1/protocol/dubbo/hessian2/hessian_response.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 "math" 23 "reflect" 24 "strconv" 25 "strings" 26 ) 27 28 import ( 29 hessian "github.com/apache/dubbo-go-hessian2" 30 "github.com/apache/dubbo-go-hessian2/java_exception" 31 32 "github.com/dubbogo/gost/log/logger" 33 34 perrors "github.com/pkg/errors" 35 ) 36 37 // DubboResponse dubbo response 38 type DubboResponse struct { 39 RspObj interface{} 40 Exception error 41 Attachments map[string]interface{} 42 } 43 44 // NewResponse create a new DubboResponse 45 func NewResponse(rspObj interface{}, exception error, attachments map[string]interface{}) *DubboResponse { 46 if attachments == nil { 47 attachments = make(map[string]interface{}, 8) 48 } 49 return &DubboResponse{ 50 RspObj: rspObj, 51 Exception: exception, 52 Attachments: attachments, 53 } 54 } 55 56 // EnsureResponse check body type, make sure it's a DubboResponse or package it as a DubboResponse 57 func EnsureResponse(body interface{}) *DubboResponse { 58 if res, ok := body.(*DubboResponse); ok { 59 return res 60 } 61 if exp, ok := body.(error); ok { 62 return NewResponse(nil, exp, nil) 63 } 64 return NewResponse(body, nil, nil) 65 } 66 67 // https://github.com/apache/dubbo/blob/dubbo-2.7.1/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/codec/ExchangeCodec.java#L256 68 // hessian encode response 69 func packResponse(header DubboHeader, ret interface{}) ([]byte, error) { 70 var byteArray []byte 71 72 response := EnsureResponse(ret) 73 74 hb := header.Type == PackageHeartbeat 75 76 // magic 77 if hb { 78 byteArray = append(byteArray, DubboResponseHeartbeatHeader[:]...) 79 } else { 80 byteArray = append(byteArray, DubboResponseHeaderBytes[:]...) 81 } 82 // set serialID, identify serialization types, eg: fastjson->6, hessian2->2 83 byteArray[2] |= header.SerialID & SERIAL_MASK 84 // response status 85 if header.ResponseStatus != 0 { 86 byteArray[3] = header.ResponseStatus 87 } 88 89 // request id 90 binary.BigEndian.PutUint64(byteArray[4:], uint64(header.ID)) 91 92 // body 93 encoder := hessian.NewEncoder() 94 encoder.Append(byteArray[:HEADER_LENGTH]) 95 96 if header.ResponseStatus == Response_OK { 97 if hb { 98 if err := encoder.Encode(nil); err != nil { 99 logger.Warnf("Encode(nil) = %v", err) 100 } 101 } else { 102 atta := isSupportResponseAttachment(response.Attachments[DUBBO_VERSION_KEY]) 103 104 var resWithException, resValue, resNullValue int32 105 if atta { 106 resWithException = RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS 107 resValue = RESPONSE_VALUE_WITH_ATTACHMENTS 108 resNullValue = RESPONSE_NULL_VALUE_WITH_ATTACHMENTS 109 } else { 110 resWithException = RESPONSE_WITH_EXCEPTION 111 resValue = RESPONSE_VALUE 112 resNullValue = RESPONSE_NULL_VALUE 113 } 114 115 if response.Exception != nil { // throw error 116 err := encoder.Encode(resWithException) 117 if err != nil { 118 return nil, perrors.Errorf("encoding response failed: %v", err) 119 } 120 if t, ok := response.Exception.(java_exception.Throwabler); ok { 121 err = encoder.Encode(t) 122 } else { 123 err = encoder.Encode(java_exception.NewThrowable(response.Exception.Error())) 124 } 125 if err != nil { 126 return nil, perrors.Errorf("encoding exception failed: %v", err) 127 } 128 } else { 129 if response.RspObj == nil { 130 if err := encoder.Encode(resNullValue); err != nil { 131 return nil, perrors.Errorf("encoding null value failed: %v", err) 132 } 133 } else { 134 if err := encoder.Encode(resValue); err != nil { 135 return nil, perrors.Errorf("encoding response value failed: %v", err) 136 } 137 if err := encoder.Encode(response.RspObj); err != nil { 138 return nil, perrors.Errorf("encoding response failed: %v", err) 139 } 140 } 141 } 142 143 // attachments 144 if atta { 145 if err := encoder.Encode(response.Attachments); err != nil { 146 return nil, perrors.Errorf("encoding response attachements failed: %v", err) 147 } 148 } 149 } 150 } else { 151 var err error 152 if response.Exception != nil { // throw error 153 err = encoder.Encode(response.Exception.Error()) 154 } else { 155 err = encoder.Encode(response.RspObj) 156 } 157 if err != nil { 158 return nil, perrors.Errorf("encoding error failed: %v", err) 159 } 160 } 161 162 byteArray = encoder.Buffer() 163 byteArray = hessian.EncNull(byteArray) // if not, "java client" will throw exception "unexpected end of file" 164 pkgLen := len(byteArray) 165 if pkgLen > int(DEFAULT_LEN) { // recommand 8M 166 logger.Warnf("Data length %d too large, recommand max payload %d. "+ 167 "Dubbo java can't handle the package whose size greater than %d!!!", pkgLen, DEFAULT_LEN, DEFAULT_LEN) 168 } 169 // byteArray{body length} 170 binary.BigEndian.PutUint32(byteArray[12:], uint32(pkgLen-HEADER_LENGTH)) 171 return byteArray, nil 172 } 173 174 // hessian decode response body 175 func unpackResponseBody(decoder *hessian.Decoder, resp interface{}) error { 176 // body 177 if decoder == nil { 178 return perrors.Errorf("@decoder is nil") 179 } 180 rspType, err := decoder.Decode() 181 if err != nil { 182 return perrors.WithStack(err) 183 } 184 185 response := EnsureResponse(resp) 186 187 switch rspType { 188 case RESPONSE_WITH_EXCEPTION, RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS: 189 expt, err := decoder.Decode() 190 if err != nil { 191 return perrors.WithStack(err) 192 } 193 if rspType == RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS { 194 attachments, err := decoder.Decode() 195 if err != nil { 196 return perrors.WithStack(err) 197 } 198 if v, ok := attachments.(map[interface{}]interface{}); ok { 199 atta := ToMapStringInterface(v) 200 response.Attachments = atta 201 } else { 202 return perrors.Errorf("get wrong attachments: %+v", attachments) 203 } 204 } 205 206 if e, ok := expt.(error); ok { 207 response.Exception = e 208 } else { 209 response.Exception = perrors.Errorf("got exception: %+v", expt) 210 } 211 return nil 212 213 case RESPONSE_VALUE, RESPONSE_VALUE_WITH_ATTACHMENTS: 214 rsp, err := decoder.Decode() 215 if err != nil { 216 return perrors.WithStack(err) 217 } 218 if rspType == RESPONSE_VALUE_WITH_ATTACHMENTS { 219 attachments, err := decoder.Decode() 220 if err != nil { 221 return perrors.WithStack(err) 222 } 223 if v, ok := attachments.(map[interface{}]interface{}); ok { 224 response.Attachments = ToMapStringInterface(v) 225 } else { 226 return perrors.Errorf("get wrong attachments: %+v", attachments) 227 } 228 } 229 230 response.RspObj = rsp 231 232 return nil 233 234 case RESPONSE_NULL_VALUE, RESPONSE_NULL_VALUE_WITH_ATTACHMENTS: 235 if rspType == RESPONSE_NULL_VALUE_WITH_ATTACHMENTS { 236 attachments, err := decoder.Decode() 237 if err != nil { 238 return perrors.WithStack(err) 239 } 240 if v, ok := attachments.(map[interface{}]interface{}); ok { 241 atta := ToMapStringInterface(v) 242 response.Attachments = atta 243 } else { 244 return perrors.Errorf("get wrong attachments: %+v", attachments) 245 } 246 } 247 return nil 248 } 249 250 return nil 251 } 252 253 // CopySlice copy from inSlice to outSlice 254 func CopySlice(inSlice, outSlice reflect.Value) error { 255 if inSlice.IsNil() { 256 return perrors.New("@in is nil") 257 } 258 if inSlice.Kind() != reflect.Slice { 259 return perrors.Errorf("@in is not slice, but %v", inSlice.Kind()) 260 } 261 262 for outSlice.Kind() == reflect.Ptr { 263 outSlice = outSlice.Elem() 264 } 265 266 size := inSlice.Len() 267 outSlice.Set(reflect.MakeSlice(outSlice.Type(), size, size)) 268 269 for i := 0; i < size; i++ { 270 inSliceValue := inSlice.Index(i) 271 if !inSliceValue.Type().AssignableTo(outSlice.Index(i).Type()) { 272 return perrors.Errorf("in element type [%s] can not assign to out element type [%s]", 273 inSliceValue.Type().String(), outSlice.Type().String()) 274 } 275 outSlice.Index(i).Set(inSliceValue) 276 } 277 278 return nil 279 } 280 281 // CopyMap copy from in map to out map 282 func CopyMap(inMapValue, outMapValue reflect.Value) error { 283 if inMapValue.IsNil() { 284 return perrors.New("@in is nil") 285 } 286 if !inMapValue.CanInterface() { 287 return perrors.New("@in's Interface can not be used.") 288 } 289 if inMapValue.Kind() != reflect.Map { 290 return perrors.Errorf("@in is not map, but %v", inMapValue.Kind()) 291 } 292 293 outMapType := hessian.UnpackPtrType(outMapValue.Type()) 294 hessian.SetValue(outMapValue, reflect.MakeMap(outMapType)) 295 296 outKeyType := outMapType.Key() 297 298 outMapValue = hessian.UnpackPtrValue(outMapValue) 299 outValueType := outMapValue.Type().Elem() 300 301 for _, inKey := range inMapValue.MapKeys() { 302 inValue := inMapValue.MapIndex(inKey) 303 304 if !inKey.Type().AssignableTo(outKeyType) { 305 return perrors.Errorf("in Key:{type:%s, value:%#v} can not assign to out Key:{type:%s} ", 306 inKey.Type().String(), inKey, outKeyType.String()) 307 } 308 if !inValue.Type().AssignableTo(outValueType) { 309 return perrors.Errorf("in Value:{type:%s, value:%#v} can not assign to out value:{type:%s}", 310 inValue.Type().String(), inValue, outValueType.String()) 311 } 312 outMapValue.SetMapIndex(inKey, inValue) 313 } 314 315 return nil 316 } 317 318 // ReflectResponse reflect return value 319 // TODO response object should not be copied again to another object, it should be the exact type of the object 320 func ReflectResponse(in interface{}, out interface{}) error { 321 if in == nil { 322 return perrors.Errorf("@in is nil") 323 } 324 325 if out == nil { 326 return perrors.Errorf("@out is nil") 327 } 328 if reflect.TypeOf(out).Kind() != reflect.Ptr { 329 return perrors.Errorf("@out should be a pointer") 330 } 331 332 inValue := hessian.EnsurePackValue(in) 333 outValue := hessian.EnsurePackValue(out) 334 335 outType := outValue.Type().String() 336 if outType == "interface {}" || outType == "*interface {}" { 337 hessian.SetValue(outValue, inValue) 338 return nil 339 } 340 341 switch inValue.Type().Kind() { 342 case reflect.Slice, reflect.Array: 343 return CopySlice(inValue, outValue) 344 case reflect.Map: 345 return CopyMap(inValue, outValue) 346 default: 347 hessian.SetValue(outValue, inValue) 348 } 349 350 return nil 351 } 352 353 var versionInt = make(map[string]int) 354 355 // https://github.com/apache/dubbo/blob/dubbo-2.7.1/dubbo-common/src/main/java/org/apache/dubbo/common/Version.java#L96 356 // isSupportResponseAttachment is for compatibility among some dubbo version 357 func isSupportResponseAttachment(ver interface{}) bool { 358 version, ok := ver.(string) 359 if !ok || len(version) == 0 { 360 return false 361 } 362 363 v, ok := versionInt[version] 364 if !ok { 365 v = version2Int(version) 366 if v == -1 { 367 return false 368 } 369 } 370 371 if v >= 2001000 && v <= 2060200 { // 2.0.10 ~ 2.6.2 372 return false 373 } 374 return v >= LOWEST_VERSION_FOR_RESPONSE_ATTACHMENT 375 } 376 377 func version2Int(ver interface{}) int { 378 version, ok := ver.(string) 379 if !ok || len(version) == 0 { 380 return 0 381 } 382 v := 0 383 varr := strings.Split(version, ".") 384 length := len(varr) 385 for key, value := range varr { 386 v0, err := strconv.Atoi(value) 387 if err != nil { 388 return -1 389 } 390 v += v0 * int(math.Pow10((length-key-1)*2)) 391 } 392 if length == 3 { 393 return v * 100 394 } 395 return v 396 }