github.com/cloudwego/dynamicgo@v0.2.6-0.20240519101509-707f41b6b834/conv/j2t/error.go (about)

     1  /**
     2   * Copyright 2023 CloudWeGo Authors.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package j2t
    18  
    19  import (
    20  	"context"
    21  	"encoding/base64"
    22  	"fmt"
    23  	"unsafe"
    24  
    25  	"github.com/cloudwego/dynamicgo/http"
    26  	"github.com/cloudwego/dynamicgo/internal/json"
    27  	"github.com/cloudwego/dynamicgo/internal/native/types"
    28  	"github.com/cloudwego/dynamicgo/internal/rt"
    29  	"github.com/cloudwego/dynamicgo/meta"
    30  	"github.com/cloudwego/dynamicgo/thrift"
    31  )
    32  
    33  //go:noinline
    34  func newError(code meta.ErrCode, msg string, err error) error {
    35  	return meta.NewError(meta.NewErrorCode(code, meta.JSON2THRIFT), msg, err)
    36  	// panic(meta.NewError(meta.NewErrorCode(code, meta.JSON2THRIFT), msg, err).Error())
    37  }
    38  
    39  type _J2TExtra_STRUCT struct {
    40  	desc unsafe.Pointer
    41  	reqs string
    42  }
    43  
    44  //go:nocheckptr
    45  func getJ2TExtraStruct(fsm *types.J2TStateMachine, offset int) (td *thrift.TypeDescriptor, reqs thrift.RequiresBitmap) {
    46  	state := fsm.At(offset - 1)
    47  	if state == nil {
    48  		return nil, thrift.RequiresBitmap{}
    49  	}
    50  	td = (*thrift.TypeDescriptor)(unsafe.Pointer(state.TdPointer()))
    51  	je := (*_J2TExtra_STRUCT)(unsafe.Pointer(&state.Extra))
    52  	v := rt.Str2Mem(je.reqs)
    53  	reqs = *(*thrift.RequiresBitmap)(unsafe.Pointer(&v))
    54  	return
    55  }
    56  
    57  func (self BinaryConv) handleError(ctx context.Context, fsm *types.J2TStateMachine, buf *[]byte, src []byte, req http.RequestGetter, ret uint64, top bool) (cont bool, err error) {
    58  	e := types.ParsingError(ret & ((1 << types.ERR_WRAP_SHIFT_CODE) - 1))
    59  	p := int(ret >> types.ERR_WRAP_SHIFT_CODE)
    60  
    61  	switch e {
    62  	case types.ERR_HTTP_MAPPING:
    63  		{
    64  			desc, reqs := getJ2TExtraStruct(fsm, fsm.SP)
    65  			if desc == nil {
    66  				return false, newError(meta.ErrConvert, "invalid json input", nil)
    67  			}
    68  			if desc.Type() != thrift.STRUCT {
    69  				return false, newError(meta.ErrConvert, "invalid descriptor while http mapping", nil)
    70  			}
    71  			return true, self.writeHttpRequestToThrift(ctx, req, desc.Struct(), reqs, buf, false, top)
    72  		}
    73  	case types.ERR_HTTP_MAPPING_END:
    74  		{
    75  			desc, _ := getJ2TExtraStruct(fsm, fsm.SP)
    76  			if desc == nil {
    77  				return false, newError(meta.ErrConvert, "invalid json input", nil)
    78  			}
    79  			if desc.Type() != thrift.STRUCT {
    80  				return false, newError(meta.ErrConvert, "invalid descriptor while http mapping", nil)
    81  			}
    82  			if len(fsm.FieldCache) == 0 {
    83  				return false, newError(meta.ErrConvert, "invalid FSM field-cache length", nil)
    84  			}
    85  			return self.handleUnmatchedFields(ctx, fsm, desc.Struct(), buf, p, req, top)
    86  		}
    87  	case types.ERR_OOM_BM:
    88  		{
    89  			fsm.GrowReqCache(p)
    90  			return true, nil
    91  		}
    92  	case types.ERR_OOM_KEY:
    93  		{
    94  			fsm.GrowKeyCache(p)
    95  			return true, nil
    96  		}
    97  	case types.ERR_OOM_BUF:
    98  		{
    99  			c := cap(*buf)
   100  			c += c >> 1
   101  			if c < cap(*buf)+p {
   102  				c = cap(*buf) + p*2
   103  			}
   104  			tmp := make([]byte, len(*buf), c)
   105  			copy(tmp, *buf)
   106  			*buf = tmp
   107  			return true, nil
   108  		}
   109  	case types.ERR_OOM_FIELD:
   110  		{
   111  			fsm.GrowFieldCache(types.J2T_FIELD_CACHE_SIZE)
   112  			fsm.SetPos(p)
   113  			return true, nil
   114  		}
   115  	// case types.ERR_OOM_FVAL:
   116  	// 	{
   117  	// 		fsm.GrowFieldValueCache(types.J2T_FIELD_CACHE_SIZE)
   118  	// 		fsm.SetPos(p)
   119  	// 		return true, nil
   120  	// 	}
   121  	case types.ERR_VALUE_MAPPING_END:
   122  		{
   123  			desc, _ := getJ2TExtraStruct(fsm, fsm.SP-1)
   124  			if desc == nil {
   125  				return false, newError(meta.ErrConvert, "invalid json input", nil)
   126  			}
   127  			if desc.Type() != thrift.STRUCT {
   128  				return false, newError(meta.ErrConvert, "invalid descriptor while value mapping", nil)
   129  			}
   130  			return self.handleValueMapping(ctx, fsm, desc.Struct(), buf, p, src)
   131  		}
   132  	}
   133  
   134  	return false, explainNativeError(e, src, p)
   135  }
   136  
   137  func explainNativeError(e types.ParsingError, in []byte, v int) error {
   138  	ip := v & ((1 << types.ERR_WRAP_SHIFT_POS) - 1)
   139  	v = v >> types.ERR_WRAP_SHIFT_POS
   140  	switch e {
   141  	case types.ERR_INVALID_CHAR:
   142  		ch, st := v>>types.ERR_WRAP_SHIFT_CODE, v&((1<<types.ERR_WRAP_SHIFT_CODE)-1)
   143  		return newError(meta.ErrRead, fmt.Sprintf("invalid char '%c' for state %s, near %d of %s", byte(ch), types.J2T_STATE(st), ip, locateInput(in, ip)), e)
   144  	case types.ERR_INVALID_NUMBER_FMT:
   145  		return newError(meta.ErrConvert, fmt.Sprintf("unexpected number type %d, near %d of %s", types.ValueType(v), ip, locateInput(in, ip)), e)
   146  	case types.ERR_UNSUPPORT_THRIFT_TYPE:
   147  		t := thrift.Type(v)
   148  		return newError(meta.ErrUnsupportedType, fmt.Sprintf("unsupported thrift type %s, near %d of %s", t, ip, locateInput(in, ip)), nil)
   149  	case types.ERR_UNSUPPORT_VM_TYPE:
   150  		t := thrift.AnnoID(v)
   151  		return newError(meta.ErrUnsupportedType, fmt.Sprintf("unsupported value-mapping type %d, near %d of %q", t, ip, locateInput(in, ip)), nil)
   152  	case types.ERR_DISMATCH_TYPE:
   153  		exp, act := v>>types.ERR_WRAP_SHIFT_CODE, v&((1<<types.ERR_WRAP_SHIFT_CODE)-1)
   154  		return newError(meta.ErrDismatchType, fmt.Sprintf("expect type %s but got type %d, near %d of %s", thrift.Type(exp), act, ip, locateInput(in, ip)), nil)
   155  	case types.ERR_NULL_REQUIRED:
   156  		id := thrift.FieldID(v)
   157  		return newError(meta.ErrMissRequiredField, fmt.Sprintf("missing required field %d, near %d of %s", id, ip, locateInput(in, ip)), nil)
   158  	case types.ERR_UNKNOWN_FIELD:
   159  		n := ip - v - 1
   160  		if n < 0 {
   161  			n = 0
   162  		}
   163  		key := in[n : ip-1]
   164  		return newError(meta.ErrUnknownField, fmt.Sprintf("unknown field '%s', near %d of %s", string(key), ip, locateInput(in, ip)), nil)
   165  	case types.ERR_RECURSE_EXCEED_MAX:
   166  		return newError(meta.ErrStackOverflow, fmt.Sprintf("stack %d overflow, near %d of %s", v, ip, locateInput(in, ip)), nil)
   167  	case types.ERR_DECODE_BASE64:
   168  		berr := base64.CorruptInputError(v)
   169  		return newError(meta.ErrRead, fmt.Sprintf("decode base64 error: %v, near %d of %s", berr, ip, locateInput(in, ip)), nil)
   170  	default:
   171  		return newError(meta.ErrConvert, fmt.Sprintf("native error %q, value %d, near %d of %s", types.ParsingError(e).Message(), v, ip, locateInput(in, ip)), nil)
   172  	}
   173  }
   174  
   175  func locateInput(in []byte, ip int) string {
   176  	je := json.SyntaxError{
   177  		Pos: (ip),
   178  		Src: string(in),
   179  	}
   180  	return je.Locate()
   181  }