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  }