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  }