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 }