1*1c12ee1eSDan Willemsen// Copyright 2019 The Go Authors. All rights reserved. 2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style 3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file. 4*1c12ee1eSDan Willemsen 5*1c12ee1eSDan Willemsenpackage impl 6*1c12ee1eSDan Willemsen 7*1c12ee1eSDan Willemsenimport ( 8*1c12ee1eSDan Willemsen "fmt" 9*1c12ee1eSDan Willemsen "math" 10*1c12ee1eSDan Willemsen "math/bits" 11*1c12ee1eSDan Willemsen "reflect" 12*1c12ee1eSDan Willemsen "unicode/utf8" 13*1c12ee1eSDan Willemsen 14*1c12ee1eSDan Willemsen "google.golang.org/protobuf/encoding/protowire" 15*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/encoding/messageset" 16*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/flags" 17*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/genid" 18*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/strs" 19*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 20*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoregistry" 21*1c12ee1eSDan Willemsen "google.golang.org/protobuf/runtime/protoiface" 22*1c12ee1eSDan Willemsen) 23*1c12ee1eSDan Willemsen 24*1c12ee1eSDan Willemsen// ValidationStatus is the result of validating the wire-format encoding of a message. 25*1c12ee1eSDan Willemsentype ValidationStatus int 26*1c12ee1eSDan Willemsen 27*1c12ee1eSDan Willemsenconst ( 28*1c12ee1eSDan Willemsen // ValidationUnknown indicates that unmarshaling the message might succeed or fail. 29*1c12ee1eSDan Willemsen // The validator was unable to render a judgement. 30*1c12ee1eSDan Willemsen // 31*1c12ee1eSDan Willemsen // The only causes of this status are an aberrant message type appearing somewhere 32*1c12ee1eSDan Willemsen // in the message or a failure in the extension resolver. 33*1c12ee1eSDan Willemsen ValidationUnknown ValidationStatus = iota + 1 34*1c12ee1eSDan Willemsen 35*1c12ee1eSDan Willemsen // ValidationInvalid indicates that unmarshaling the message will fail. 36*1c12ee1eSDan Willemsen ValidationInvalid 37*1c12ee1eSDan Willemsen 38*1c12ee1eSDan Willemsen // ValidationValid indicates that unmarshaling the message will succeed. 39*1c12ee1eSDan Willemsen ValidationValid 40*1c12ee1eSDan Willemsen) 41*1c12ee1eSDan Willemsen 42*1c12ee1eSDan Willemsenfunc (v ValidationStatus) String() string { 43*1c12ee1eSDan Willemsen switch v { 44*1c12ee1eSDan Willemsen case ValidationUnknown: 45*1c12ee1eSDan Willemsen return "ValidationUnknown" 46*1c12ee1eSDan Willemsen case ValidationInvalid: 47*1c12ee1eSDan Willemsen return "ValidationInvalid" 48*1c12ee1eSDan Willemsen case ValidationValid: 49*1c12ee1eSDan Willemsen return "ValidationValid" 50*1c12ee1eSDan Willemsen default: 51*1c12ee1eSDan Willemsen return fmt.Sprintf("ValidationStatus(%d)", int(v)) 52*1c12ee1eSDan Willemsen } 53*1c12ee1eSDan Willemsen} 54*1c12ee1eSDan Willemsen 55*1c12ee1eSDan Willemsen// Validate determines whether the contents of the buffer are a valid wire encoding 56*1c12ee1eSDan Willemsen// of the message type. 57*1c12ee1eSDan Willemsen// 58*1c12ee1eSDan Willemsen// This function is exposed for testing. 59*1c12ee1eSDan Willemsenfunc Validate(mt protoreflect.MessageType, in protoiface.UnmarshalInput) (out protoiface.UnmarshalOutput, _ ValidationStatus) { 60*1c12ee1eSDan Willemsen mi, ok := mt.(*MessageInfo) 61*1c12ee1eSDan Willemsen if !ok { 62*1c12ee1eSDan Willemsen return out, ValidationUnknown 63*1c12ee1eSDan Willemsen } 64*1c12ee1eSDan Willemsen if in.Resolver == nil { 65*1c12ee1eSDan Willemsen in.Resolver = protoregistry.GlobalTypes 66*1c12ee1eSDan Willemsen } 67*1c12ee1eSDan Willemsen o, st := mi.validate(in.Buf, 0, unmarshalOptions{ 68*1c12ee1eSDan Willemsen flags: in.Flags, 69*1c12ee1eSDan Willemsen resolver: in.Resolver, 70*1c12ee1eSDan Willemsen }) 71*1c12ee1eSDan Willemsen if o.initialized { 72*1c12ee1eSDan Willemsen out.Flags |= protoiface.UnmarshalInitialized 73*1c12ee1eSDan Willemsen } 74*1c12ee1eSDan Willemsen return out, st 75*1c12ee1eSDan Willemsen} 76*1c12ee1eSDan Willemsen 77*1c12ee1eSDan Willemsentype validationInfo struct { 78*1c12ee1eSDan Willemsen mi *MessageInfo 79*1c12ee1eSDan Willemsen typ validationType 80*1c12ee1eSDan Willemsen keyType, valType validationType 81*1c12ee1eSDan Willemsen 82*1c12ee1eSDan Willemsen // For non-required fields, requiredBit is 0. 83*1c12ee1eSDan Willemsen // 84*1c12ee1eSDan Willemsen // For required fields, requiredBit's nth bit is set, where n is a 85*1c12ee1eSDan Willemsen // unique index in the range [0, MessageInfo.numRequiredFields). 86*1c12ee1eSDan Willemsen // 87*1c12ee1eSDan Willemsen // If there are more than 64 required fields, requiredBit is 0. 88*1c12ee1eSDan Willemsen requiredBit uint64 89*1c12ee1eSDan Willemsen} 90*1c12ee1eSDan Willemsen 91*1c12ee1eSDan Willemsentype validationType uint8 92*1c12ee1eSDan Willemsen 93*1c12ee1eSDan Willemsenconst ( 94*1c12ee1eSDan Willemsen validationTypeOther validationType = iota 95*1c12ee1eSDan Willemsen validationTypeMessage 96*1c12ee1eSDan Willemsen validationTypeGroup 97*1c12ee1eSDan Willemsen validationTypeMap 98*1c12ee1eSDan Willemsen validationTypeRepeatedVarint 99*1c12ee1eSDan Willemsen validationTypeRepeatedFixed32 100*1c12ee1eSDan Willemsen validationTypeRepeatedFixed64 101*1c12ee1eSDan Willemsen validationTypeVarint 102*1c12ee1eSDan Willemsen validationTypeFixed32 103*1c12ee1eSDan Willemsen validationTypeFixed64 104*1c12ee1eSDan Willemsen validationTypeBytes 105*1c12ee1eSDan Willemsen validationTypeUTF8String 106*1c12ee1eSDan Willemsen validationTypeMessageSetItem 107*1c12ee1eSDan Willemsen) 108*1c12ee1eSDan Willemsen 109*1c12ee1eSDan Willemsenfunc newFieldValidationInfo(mi *MessageInfo, si structInfo, fd protoreflect.FieldDescriptor, ft reflect.Type) validationInfo { 110*1c12ee1eSDan Willemsen var vi validationInfo 111*1c12ee1eSDan Willemsen switch { 112*1c12ee1eSDan Willemsen case fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic(): 113*1c12ee1eSDan Willemsen switch fd.Kind() { 114*1c12ee1eSDan Willemsen case protoreflect.MessageKind: 115*1c12ee1eSDan Willemsen vi.typ = validationTypeMessage 116*1c12ee1eSDan Willemsen if ot, ok := si.oneofWrappersByNumber[fd.Number()]; ok { 117*1c12ee1eSDan Willemsen vi.mi = getMessageInfo(ot.Field(0).Type) 118*1c12ee1eSDan Willemsen } 119*1c12ee1eSDan Willemsen case protoreflect.GroupKind: 120*1c12ee1eSDan Willemsen vi.typ = validationTypeGroup 121*1c12ee1eSDan Willemsen if ot, ok := si.oneofWrappersByNumber[fd.Number()]; ok { 122*1c12ee1eSDan Willemsen vi.mi = getMessageInfo(ot.Field(0).Type) 123*1c12ee1eSDan Willemsen } 124*1c12ee1eSDan Willemsen case protoreflect.StringKind: 125*1c12ee1eSDan Willemsen if strs.EnforceUTF8(fd) { 126*1c12ee1eSDan Willemsen vi.typ = validationTypeUTF8String 127*1c12ee1eSDan Willemsen } 128*1c12ee1eSDan Willemsen } 129*1c12ee1eSDan Willemsen default: 130*1c12ee1eSDan Willemsen vi = newValidationInfo(fd, ft) 131*1c12ee1eSDan Willemsen } 132*1c12ee1eSDan Willemsen if fd.Cardinality() == protoreflect.Required { 133*1c12ee1eSDan Willemsen // Avoid overflow. The required field check is done with a 64-bit mask, with 134*1c12ee1eSDan Willemsen // any message containing more than 64 required fields always reported as 135*1c12ee1eSDan Willemsen // potentially uninitialized, so it is not important to get a precise count 136*1c12ee1eSDan Willemsen // of the required fields past 64. 137*1c12ee1eSDan Willemsen if mi.numRequiredFields < math.MaxUint8 { 138*1c12ee1eSDan Willemsen mi.numRequiredFields++ 139*1c12ee1eSDan Willemsen vi.requiredBit = 1 << (mi.numRequiredFields - 1) 140*1c12ee1eSDan Willemsen } 141*1c12ee1eSDan Willemsen } 142*1c12ee1eSDan Willemsen return vi 143*1c12ee1eSDan Willemsen} 144*1c12ee1eSDan Willemsen 145*1c12ee1eSDan Willemsenfunc newValidationInfo(fd protoreflect.FieldDescriptor, ft reflect.Type) validationInfo { 146*1c12ee1eSDan Willemsen var vi validationInfo 147*1c12ee1eSDan Willemsen switch { 148*1c12ee1eSDan Willemsen case fd.IsList(): 149*1c12ee1eSDan Willemsen switch fd.Kind() { 150*1c12ee1eSDan Willemsen case protoreflect.MessageKind: 151*1c12ee1eSDan Willemsen vi.typ = validationTypeMessage 152*1c12ee1eSDan Willemsen if ft.Kind() == reflect.Slice { 153*1c12ee1eSDan Willemsen vi.mi = getMessageInfo(ft.Elem()) 154*1c12ee1eSDan Willemsen } 155*1c12ee1eSDan Willemsen case protoreflect.GroupKind: 156*1c12ee1eSDan Willemsen vi.typ = validationTypeGroup 157*1c12ee1eSDan Willemsen if ft.Kind() == reflect.Slice { 158*1c12ee1eSDan Willemsen vi.mi = getMessageInfo(ft.Elem()) 159*1c12ee1eSDan Willemsen } 160*1c12ee1eSDan Willemsen case protoreflect.StringKind: 161*1c12ee1eSDan Willemsen vi.typ = validationTypeBytes 162*1c12ee1eSDan Willemsen if strs.EnforceUTF8(fd) { 163*1c12ee1eSDan Willemsen vi.typ = validationTypeUTF8String 164*1c12ee1eSDan Willemsen } 165*1c12ee1eSDan Willemsen default: 166*1c12ee1eSDan Willemsen switch wireTypes[fd.Kind()] { 167*1c12ee1eSDan Willemsen case protowire.VarintType: 168*1c12ee1eSDan Willemsen vi.typ = validationTypeRepeatedVarint 169*1c12ee1eSDan Willemsen case protowire.Fixed32Type: 170*1c12ee1eSDan Willemsen vi.typ = validationTypeRepeatedFixed32 171*1c12ee1eSDan Willemsen case protowire.Fixed64Type: 172*1c12ee1eSDan Willemsen vi.typ = validationTypeRepeatedFixed64 173*1c12ee1eSDan Willemsen } 174*1c12ee1eSDan Willemsen } 175*1c12ee1eSDan Willemsen case fd.IsMap(): 176*1c12ee1eSDan Willemsen vi.typ = validationTypeMap 177*1c12ee1eSDan Willemsen switch fd.MapKey().Kind() { 178*1c12ee1eSDan Willemsen case protoreflect.StringKind: 179*1c12ee1eSDan Willemsen if strs.EnforceUTF8(fd) { 180*1c12ee1eSDan Willemsen vi.keyType = validationTypeUTF8String 181*1c12ee1eSDan Willemsen } 182*1c12ee1eSDan Willemsen } 183*1c12ee1eSDan Willemsen switch fd.MapValue().Kind() { 184*1c12ee1eSDan Willemsen case protoreflect.MessageKind: 185*1c12ee1eSDan Willemsen vi.valType = validationTypeMessage 186*1c12ee1eSDan Willemsen if ft.Kind() == reflect.Map { 187*1c12ee1eSDan Willemsen vi.mi = getMessageInfo(ft.Elem()) 188*1c12ee1eSDan Willemsen } 189*1c12ee1eSDan Willemsen case protoreflect.StringKind: 190*1c12ee1eSDan Willemsen if strs.EnforceUTF8(fd) { 191*1c12ee1eSDan Willemsen vi.valType = validationTypeUTF8String 192*1c12ee1eSDan Willemsen } 193*1c12ee1eSDan Willemsen } 194*1c12ee1eSDan Willemsen default: 195*1c12ee1eSDan Willemsen switch fd.Kind() { 196*1c12ee1eSDan Willemsen case protoreflect.MessageKind: 197*1c12ee1eSDan Willemsen vi.typ = validationTypeMessage 198*1c12ee1eSDan Willemsen if !fd.IsWeak() { 199*1c12ee1eSDan Willemsen vi.mi = getMessageInfo(ft) 200*1c12ee1eSDan Willemsen } 201*1c12ee1eSDan Willemsen case protoreflect.GroupKind: 202*1c12ee1eSDan Willemsen vi.typ = validationTypeGroup 203*1c12ee1eSDan Willemsen vi.mi = getMessageInfo(ft) 204*1c12ee1eSDan Willemsen case protoreflect.StringKind: 205*1c12ee1eSDan Willemsen vi.typ = validationTypeBytes 206*1c12ee1eSDan Willemsen if strs.EnforceUTF8(fd) { 207*1c12ee1eSDan Willemsen vi.typ = validationTypeUTF8String 208*1c12ee1eSDan Willemsen } 209*1c12ee1eSDan Willemsen default: 210*1c12ee1eSDan Willemsen switch wireTypes[fd.Kind()] { 211*1c12ee1eSDan Willemsen case protowire.VarintType: 212*1c12ee1eSDan Willemsen vi.typ = validationTypeVarint 213*1c12ee1eSDan Willemsen case protowire.Fixed32Type: 214*1c12ee1eSDan Willemsen vi.typ = validationTypeFixed32 215*1c12ee1eSDan Willemsen case protowire.Fixed64Type: 216*1c12ee1eSDan Willemsen vi.typ = validationTypeFixed64 217*1c12ee1eSDan Willemsen case protowire.BytesType: 218*1c12ee1eSDan Willemsen vi.typ = validationTypeBytes 219*1c12ee1eSDan Willemsen } 220*1c12ee1eSDan Willemsen } 221*1c12ee1eSDan Willemsen } 222*1c12ee1eSDan Willemsen return vi 223*1c12ee1eSDan Willemsen} 224*1c12ee1eSDan Willemsen 225*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) validate(b []byte, groupTag protowire.Number, opts unmarshalOptions) (out unmarshalOutput, result ValidationStatus) { 226*1c12ee1eSDan Willemsen mi.init() 227*1c12ee1eSDan Willemsen type validationState struct { 228*1c12ee1eSDan Willemsen typ validationType 229*1c12ee1eSDan Willemsen keyType, valType validationType 230*1c12ee1eSDan Willemsen endGroup protowire.Number 231*1c12ee1eSDan Willemsen mi *MessageInfo 232*1c12ee1eSDan Willemsen tail []byte 233*1c12ee1eSDan Willemsen requiredMask uint64 234*1c12ee1eSDan Willemsen } 235*1c12ee1eSDan Willemsen 236*1c12ee1eSDan Willemsen // Pre-allocate some slots to avoid repeated slice reallocation. 237*1c12ee1eSDan Willemsen states := make([]validationState, 0, 16) 238*1c12ee1eSDan Willemsen states = append(states, validationState{ 239*1c12ee1eSDan Willemsen typ: validationTypeMessage, 240*1c12ee1eSDan Willemsen mi: mi, 241*1c12ee1eSDan Willemsen }) 242*1c12ee1eSDan Willemsen if groupTag > 0 { 243*1c12ee1eSDan Willemsen states[0].typ = validationTypeGroup 244*1c12ee1eSDan Willemsen states[0].endGroup = groupTag 245*1c12ee1eSDan Willemsen } 246*1c12ee1eSDan Willemsen initialized := true 247*1c12ee1eSDan Willemsen start := len(b) 248*1c12ee1eSDan WillemsenState: 249*1c12ee1eSDan Willemsen for len(states) > 0 { 250*1c12ee1eSDan Willemsen st := &states[len(states)-1] 251*1c12ee1eSDan Willemsen for len(b) > 0 { 252*1c12ee1eSDan Willemsen // Parse the tag (field number and wire type). 253*1c12ee1eSDan Willemsen var tag uint64 254*1c12ee1eSDan Willemsen if b[0] < 0x80 { 255*1c12ee1eSDan Willemsen tag = uint64(b[0]) 256*1c12ee1eSDan Willemsen b = b[1:] 257*1c12ee1eSDan Willemsen } else if len(b) >= 2 && b[1] < 128 { 258*1c12ee1eSDan Willemsen tag = uint64(b[0]&0x7f) + uint64(b[1])<<7 259*1c12ee1eSDan Willemsen b = b[2:] 260*1c12ee1eSDan Willemsen } else { 261*1c12ee1eSDan Willemsen var n int 262*1c12ee1eSDan Willemsen tag, n = protowire.ConsumeVarint(b) 263*1c12ee1eSDan Willemsen if n < 0 { 264*1c12ee1eSDan Willemsen return out, ValidationInvalid 265*1c12ee1eSDan Willemsen } 266*1c12ee1eSDan Willemsen b = b[n:] 267*1c12ee1eSDan Willemsen } 268*1c12ee1eSDan Willemsen var num protowire.Number 269*1c12ee1eSDan Willemsen if n := tag >> 3; n < uint64(protowire.MinValidNumber) || n > uint64(protowire.MaxValidNumber) { 270*1c12ee1eSDan Willemsen return out, ValidationInvalid 271*1c12ee1eSDan Willemsen } else { 272*1c12ee1eSDan Willemsen num = protowire.Number(n) 273*1c12ee1eSDan Willemsen } 274*1c12ee1eSDan Willemsen wtyp := protowire.Type(tag & 7) 275*1c12ee1eSDan Willemsen 276*1c12ee1eSDan Willemsen if wtyp == protowire.EndGroupType { 277*1c12ee1eSDan Willemsen if st.endGroup == num { 278*1c12ee1eSDan Willemsen goto PopState 279*1c12ee1eSDan Willemsen } 280*1c12ee1eSDan Willemsen return out, ValidationInvalid 281*1c12ee1eSDan Willemsen } 282*1c12ee1eSDan Willemsen var vi validationInfo 283*1c12ee1eSDan Willemsen switch { 284*1c12ee1eSDan Willemsen case st.typ == validationTypeMap: 285*1c12ee1eSDan Willemsen switch num { 286*1c12ee1eSDan Willemsen case genid.MapEntry_Key_field_number: 287*1c12ee1eSDan Willemsen vi.typ = st.keyType 288*1c12ee1eSDan Willemsen case genid.MapEntry_Value_field_number: 289*1c12ee1eSDan Willemsen vi.typ = st.valType 290*1c12ee1eSDan Willemsen vi.mi = st.mi 291*1c12ee1eSDan Willemsen vi.requiredBit = 1 292*1c12ee1eSDan Willemsen } 293*1c12ee1eSDan Willemsen case flags.ProtoLegacy && st.mi.isMessageSet: 294*1c12ee1eSDan Willemsen switch num { 295*1c12ee1eSDan Willemsen case messageset.FieldItem: 296*1c12ee1eSDan Willemsen vi.typ = validationTypeMessageSetItem 297*1c12ee1eSDan Willemsen } 298*1c12ee1eSDan Willemsen default: 299*1c12ee1eSDan Willemsen var f *coderFieldInfo 300*1c12ee1eSDan Willemsen if int(num) < len(st.mi.denseCoderFields) { 301*1c12ee1eSDan Willemsen f = st.mi.denseCoderFields[num] 302*1c12ee1eSDan Willemsen } else { 303*1c12ee1eSDan Willemsen f = st.mi.coderFields[num] 304*1c12ee1eSDan Willemsen } 305*1c12ee1eSDan Willemsen if f != nil { 306*1c12ee1eSDan Willemsen vi = f.validation 307*1c12ee1eSDan Willemsen if vi.typ == validationTypeMessage && vi.mi == nil { 308*1c12ee1eSDan Willemsen // Probable weak field. 309*1c12ee1eSDan Willemsen // 310*1c12ee1eSDan Willemsen // TODO: Consider storing the results of this lookup somewhere 311*1c12ee1eSDan Willemsen // rather than recomputing it on every validation. 312*1c12ee1eSDan Willemsen fd := st.mi.Desc.Fields().ByNumber(num) 313*1c12ee1eSDan Willemsen if fd == nil || !fd.IsWeak() { 314*1c12ee1eSDan Willemsen break 315*1c12ee1eSDan Willemsen } 316*1c12ee1eSDan Willemsen messageName := fd.Message().FullName() 317*1c12ee1eSDan Willemsen messageType, err := protoregistry.GlobalTypes.FindMessageByName(messageName) 318*1c12ee1eSDan Willemsen switch err { 319*1c12ee1eSDan Willemsen case nil: 320*1c12ee1eSDan Willemsen vi.mi, _ = messageType.(*MessageInfo) 321*1c12ee1eSDan Willemsen case protoregistry.NotFound: 322*1c12ee1eSDan Willemsen vi.typ = validationTypeBytes 323*1c12ee1eSDan Willemsen default: 324*1c12ee1eSDan Willemsen return out, ValidationUnknown 325*1c12ee1eSDan Willemsen } 326*1c12ee1eSDan Willemsen } 327*1c12ee1eSDan Willemsen break 328*1c12ee1eSDan Willemsen } 329*1c12ee1eSDan Willemsen // Possible extension field. 330*1c12ee1eSDan Willemsen // 331*1c12ee1eSDan Willemsen // TODO: We should return ValidationUnknown when: 332*1c12ee1eSDan Willemsen // 1. The resolver is not frozen. (More extensions may be added to it.) 333*1c12ee1eSDan Willemsen // 2. The resolver returns preg.NotFound. 334*1c12ee1eSDan Willemsen // In this case, a type added to the resolver in the future could cause 335*1c12ee1eSDan Willemsen // unmarshaling to begin failing. Supporting this requires some way to 336*1c12ee1eSDan Willemsen // determine if the resolver is frozen. 337*1c12ee1eSDan Willemsen xt, err := opts.resolver.FindExtensionByNumber(st.mi.Desc.FullName(), num) 338*1c12ee1eSDan Willemsen if err != nil && err != protoregistry.NotFound { 339*1c12ee1eSDan Willemsen return out, ValidationUnknown 340*1c12ee1eSDan Willemsen } 341*1c12ee1eSDan Willemsen if err == nil { 342*1c12ee1eSDan Willemsen vi = getExtensionFieldInfo(xt).validation 343*1c12ee1eSDan Willemsen } 344*1c12ee1eSDan Willemsen } 345*1c12ee1eSDan Willemsen if vi.requiredBit != 0 { 346*1c12ee1eSDan Willemsen // Check that the field has a compatible wire type. 347*1c12ee1eSDan Willemsen // We only need to consider non-repeated field types, 348*1c12ee1eSDan Willemsen // since repeated fields (and maps) can never be required. 349*1c12ee1eSDan Willemsen ok := false 350*1c12ee1eSDan Willemsen switch vi.typ { 351*1c12ee1eSDan Willemsen case validationTypeVarint: 352*1c12ee1eSDan Willemsen ok = wtyp == protowire.VarintType 353*1c12ee1eSDan Willemsen case validationTypeFixed32: 354*1c12ee1eSDan Willemsen ok = wtyp == protowire.Fixed32Type 355*1c12ee1eSDan Willemsen case validationTypeFixed64: 356*1c12ee1eSDan Willemsen ok = wtyp == protowire.Fixed64Type 357*1c12ee1eSDan Willemsen case validationTypeBytes, validationTypeUTF8String, validationTypeMessage: 358*1c12ee1eSDan Willemsen ok = wtyp == protowire.BytesType 359*1c12ee1eSDan Willemsen case validationTypeGroup: 360*1c12ee1eSDan Willemsen ok = wtyp == protowire.StartGroupType 361*1c12ee1eSDan Willemsen } 362*1c12ee1eSDan Willemsen if ok { 363*1c12ee1eSDan Willemsen st.requiredMask |= vi.requiredBit 364*1c12ee1eSDan Willemsen } 365*1c12ee1eSDan Willemsen } 366*1c12ee1eSDan Willemsen 367*1c12ee1eSDan Willemsen switch wtyp { 368*1c12ee1eSDan Willemsen case protowire.VarintType: 369*1c12ee1eSDan Willemsen if len(b) >= 10 { 370*1c12ee1eSDan Willemsen switch { 371*1c12ee1eSDan Willemsen case b[0] < 0x80: 372*1c12ee1eSDan Willemsen b = b[1:] 373*1c12ee1eSDan Willemsen case b[1] < 0x80: 374*1c12ee1eSDan Willemsen b = b[2:] 375*1c12ee1eSDan Willemsen case b[2] < 0x80: 376*1c12ee1eSDan Willemsen b = b[3:] 377*1c12ee1eSDan Willemsen case b[3] < 0x80: 378*1c12ee1eSDan Willemsen b = b[4:] 379*1c12ee1eSDan Willemsen case b[4] < 0x80: 380*1c12ee1eSDan Willemsen b = b[5:] 381*1c12ee1eSDan Willemsen case b[5] < 0x80: 382*1c12ee1eSDan Willemsen b = b[6:] 383*1c12ee1eSDan Willemsen case b[6] < 0x80: 384*1c12ee1eSDan Willemsen b = b[7:] 385*1c12ee1eSDan Willemsen case b[7] < 0x80: 386*1c12ee1eSDan Willemsen b = b[8:] 387*1c12ee1eSDan Willemsen case b[8] < 0x80: 388*1c12ee1eSDan Willemsen b = b[9:] 389*1c12ee1eSDan Willemsen case b[9] < 0x80 && b[9] < 2: 390*1c12ee1eSDan Willemsen b = b[10:] 391*1c12ee1eSDan Willemsen default: 392*1c12ee1eSDan Willemsen return out, ValidationInvalid 393*1c12ee1eSDan Willemsen } 394*1c12ee1eSDan Willemsen } else { 395*1c12ee1eSDan Willemsen switch { 396*1c12ee1eSDan Willemsen case len(b) > 0 && b[0] < 0x80: 397*1c12ee1eSDan Willemsen b = b[1:] 398*1c12ee1eSDan Willemsen case len(b) > 1 && b[1] < 0x80: 399*1c12ee1eSDan Willemsen b = b[2:] 400*1c12ee1eSDan Willemsen case len(b) > 2 && b[2] < 0x80: 401*1c12ee1eSDan Willemsen b = b[3:] 402*1c12ee1eSDan Willemsen case len(b) > 3 && b[3] < 0x80: 403*1c12ee1eSDan Willemsen b = b[4:] 404*1c12ee1eSDan Willemsen case len(b) > 4 && b[4] < 0x80: 405*1c12ee1eSDan Willemsen b = b[5:] 406*1c12ee1eSDan Willemsen case len(b) > 5 && b[5] < 0x80: 407*1c12ee1eSDan Willemsen b = b[6:] 408*1c12ee1eSDan Willemsen case len(b) > 6 && b[6] < 0x80: 409*1c12ee1eSDan Willemsen b = b[7:] 410*1c12ee1eSDan Willemsen case len(b) > 7 && b[7] < 0x80: 411*1c12ee1eSDan Willemsen b = b[8:] 412*1c12ee1eSDan Willemsen case len(b) > 8 && b[8] < 0x80: 413*1c12ee1eSDan Willemsen b = b[9:] 414*1c12ee1eSDan Willemsen case len(b) > 9 && b[9] < 2: 415*1c12ee1eSDan Willemsen b = b[10:] 416*1c12ee1eSDan Willemsen default: 417*1c12ee1eSDan Willemsen return out, ValidationInvalid 418*1c12ee1eSDan Willemsen } 419*1c12ee1eSDan Willemsen } 420*1c12ee1eSDan Willemsen continue State 421*1c12ee1eSDan Willemsen case protowire.BytesType: 422*1c12ee1eSDan Willemsen var size uint64 423*1c12ee1eSDan Willemsen if len(b) >= 1 && b[0] < 0x80 { 424*1c12ee1eSDan Willemsen size = uint64(b[0]) 425*1c12ee1eSDan Willemsen b = b[1:] 426*1c12ee1eSDan Willemsen } else if len(b) >= 2 && b[1] < 128 { 427*1c12ee1eSDan Willemsen size = uint64(b[0]&0x7f) + uint64(b[1])<<7 428*1c12ee1eSDan Willemsen b = b[2:] 429*1c12ee1eSDan Willemsen } else { 430*1c12ee1eSDan Willemsen var n int 431*1c12ee1eSDan Willemsen size, n = protowire.ConsumeVarint(b) 432*1c12ee1eSDan Willemsen if n < 0 { 433*1c12ee1eSDan Willemsen return out, ValidationInvalid 434*1c12ee1eSDan Willemsen } 435*1c12ee1eSDan Willemsen b = b[n:] 436*1c12ee1eSDan Willemsen } 437*1c12ee1eSDan Willemsen if size > uint64(len(b)) { 438*1c12ee1eSDan Willemsen return out, ValidationInvalid 439*1c12ee1eSDan Willemsen } 440*1c12ee1eSDan Willemsen v := b[:size] 441*1c12ee1eSDan Willemsen b = b[size:] 442*1c12ee1eSDan Willemsen switch vi.typ { 443*1c12ee1eSDan Willemsen case validationTypeMessage: 444*1c12ee1eSDan Willemsen if vi.mi == nil { 445*1c12ee1eSDan Willemsen return out, ValidationUnknown 446*1c12ee1eSDan Willemsen } 447*1c12ee1eSDan Willemsen vi.mi.init() 448*1c12ee1eSDan Willemsen fallthrough 449*1c12ee1eSDan Willemsen case validationTypeMap: 450*1c12ee1eSDan Willemsen if vi.mi != nil { 451*1c12ee1eSDan Willemsen vi.mi.init() 452*1c12ee1eSDan Willemsen } 453*1c12ee1eSDan Willemsen states = append(states, validationState{ 454*1c12ee1eSDan Willemsen typ: vi.typ, 455*1c12ee1eSDan Willemsen keyType: vi.keyType, 456*1c12ee1eSDan Willemsen valType: vi.valType, 457*1c12ee1eSDan Willemsen mi: vi.mi, 458*1c12ee1eSDan Willemsen tail: b, 459*1c12ee1eSDan Willemsen }) 460*1c12ee1eSDan Willemsen b = v 461*1c12ee1eSDan Willemsen continue State 462*1c12ee1eSDan Willemsen case validationTypeRepeatedVarint: 463*1c12ee1eSDan Willemsen // Packed field. 464*1c12ee1eSDan Willemsen for len(v) > 0 { 465*1c12ee1eSDan Willemsen _, n := protowire.ConsumeVarint(v) 466*1c12ee1eSDan Willemsen if n < 0 { 467*1c12ee1eSDan Willemsen return out, ValidationInvalid 468*1c12ee1eSDan Willemsen } 469*1c12ee1eSDan Willemsen v = v[n:] 470*1c12ee1eSDan Willemsen } 471*1c12ee1eSDan Willemsen case validationTypeRepeatedFixed32: 472*1c12ee1eSDan Willemsen // Packed field. 473*1c12ee1eSDan Willemsen if len(v)%4 != 0 { 474*1c12ee1eSDan Willemsen return out, ValidationInvalid 475*1c12ee1eSDan Willemsen } 476*1c12ee1eSDan Willemsen case validationTypeRepeatedFixed64: 477*1c12ee1eSDan Willemsen // Packed field. 478*1c12ee1eSDan Willemsen if len(v)%8 != 0 { 479*1c12ee1eSDan Willemsen return out, ValidationInvalid 480*1c12ee1eSDan Willemsen } 481*1c12ee1eSDan Willemsen case validationTypeUTF8String: 482*1c12ee1eSDan Willemsen if !utf8.Valid(v) { 483*1c12ee1eSDan Willemsen return out, ValidationInvalid 484*1c12ee1eSDan Willemsen } 485*1c12ee1eSDan Willemsen } 486*1c12ee1eSDan Willemsen case protowire.Fixed32Type: 487*1c12ee1eSDan Willemsen if len(b) < 4 { 488*1c12ee1eSDan Willemsen return out, ValidationInvalid 489*1c12ee1eSDan Willemsen } 490*1c12ee1eSDan Willemsen b = b[4:] 491*1c12ee1eSDan Willemsen case protowire.Fixed64Type: 492*1c12ee1eSDan Willemsen if len(b) < 8 { 493*1c12ee1eSDan Willemsen return out, ValidationInvalid 494*1c12ee1eSDan Willemsen } 495*1c12ee1eSDan Willemsen b = b[8:] 496*1c12ee1eSDan Willemsen case protowire.StartGroupType: 497*1c12ee1eSDan Willemsen switch { 498*1c12ee1eSDan Willemsen case vi.typ == validationTypeGroup: 499*1c12ee1eSDan Willemsen if vi.mi == nil { 500*1c12ee1eSDan Willemsen return out, ValidationUnknown 501*1c12ee1eSDan Willemsen } 502*1c12ee1eSDan Willemsen vi.mi.init() 503*1c12ee1eSDan Willemsen states = append(states, validationState{ 504*1c12ee1eSDan Willemsen typ: validationTypeGroup, 505*1c12ee1eSDan Willemsen mi: vi.mi, 506*1c12ee1eSDan Willemsen endGroup: num, 507*1c12ee1eSDan Willemsen }) 508*1c12ee1eSDan Willemsen continue State 509*1c12ee1eSDan Willemsen case flags.ProtoLegacy && vi.typ == validationTypeMessageSetItem: 510*1c12ee1eSDan Willemsen typeid, v, n, err := messageset.ConsumeFieldValue(b, false) 511*1c12ee1eSDan Willemsen if err != nil { 512*1c12ee1eSDan Willemsen return out, ValidationInvalid 513*1c12ee1eSDan Willemsen } 514*1c12ee1eSDan Willemsen xt, err := opts.resolver.FindExtensionByNumber(st.mi.Desc.FullName(), typeid) 515*1c12ee1eSDan Willemsen switch { 516*1c12ee1eSDan Willemsen case err == protoregistry.NotFound: 517*1c12ee1eSDan Willemsen b = b[n:] 518*1c12ee1eSDan Willemsen case err != nil: 519*1c12ee1eSDan Willemsen return out, ValidationUnknown 520*1c12ee1eSDan Willemsen default: 521*1c12ee1eSDan Willemsen xvi := getExtensionFieldInfo(xt).validation 522*1c12ee1eSDan Willemsen if xvi.mi != nil { 523*1c12ee1eSDan Willemsen xvi.mi.init() 524*1c12ee1eSDan Willemsen } 525*1c12ee1eSDan Willemsen states = append(states, validationState{ 526*1c12ee1eSDan Willemsen typ: xvi.typ, 527*1c12ee1eSDan Willemsen mi: xvi.mi, 528*1c12ee1eSDan Willemsen tail: b[n:], 529*1c12ee1eSDan Willemsen }) 530*1c12ee1eSDan Willemsen b = v 531*1c12ee1eSDan Willemsen continue State 532*1c12ee1eSDan Willemsen } 533*1c12ee1eSDan Willemsen default: 534*1c12ee1eSDan Willemsen n := protowire.ConsumeFieldValue(num, wtyp, b) 535*1c12ee1eSDan Willemsen if n < 0 { 536*1c12ee1eSDan Willemsen return out, ValidationInvalid 537*1c12ee1eSDan Willemsen } 538*1c12ee1eSDan Willemsen b = b[n:] 539*1c12ee1eSDan Willemsen } 540*1c12ee1eSDan Willemsen default: 541*1c12ee1eSDan Willemsen return out, ValidationInvalid 542*1c12ee1eSDan Willemsen } 543*1c12ee1eSDan Willemsen } 544*1c12ee1eSDan Willemsen if st.endGroup != 0 { 545*1c12ee1eSDan Willemsen return out, ValidationInvalid 546*1c12ee1eSDan Willemsen } 547*1c12ee1eSDan Willemsen if len(b) != 0 { 548*1c12ee1eSDan Willemsen return out, ValidationInvalid 549*1c12ee1eSDan Willemsen } 550*1c12ee1eSDan Willemsen b = st.tail 551*1c12ee1eSDan Willemsen PopState: 552*1c12ee1eSDan Willemsen numRequiredFields := 0 553*1c12ee1eSDan Willemsen switch st.typ { 554*1c12ee1eSDan Willemsen case validationTypeMessage, validationTypeGroup: 555*1c12ee1eSDan Willemsen numRequiredFields = int(st.mi.numRequiredFields) 556*1c12ee1eSDan Willemsen case validationTypeMap: 557*1c12ee1eSDan Willemsen // If this is a map field with a message value that contains 558*1c12ee1eSDan Willemsen // required fields, require that the value be present. 559*1c12ee1eSDan Willemsen if st.mi != nil && st.mi.numRequiredFields > 0 { 560*1c12ee1eSDan Willemsen numRequiredFields = 1 561*1c12ee1eSDan Willemsen } 562*1c12ee1eSDan Willemsen } 563*1c12ee1eSDan Willemsen // If there are more than 64 required fields, this check will 564*1c12ee1eSDan Willemsen // always fail and we will report that the message is potentially 565*1c12ee1eSDan Willemsen // uninitialized. 566*1c12ee1eSDan Willemsen if numRequiredFields > 0 && bits.OnesCount64(st.requiredMask) != numRequiredFields { 567*1c12ee1eSDan Willemsen initialized = false 568*1c12ee1eSDan Willemsen } 569*1c12ee1eSDan Willemsen states = states[:len(states)-1] 570*1c12ee1eSDan Willemsen } 571*1c12ee1eSDan Willemsen out.n = start - len(b) 572*1c12ee1eSDan Willemsen if initialized { 573*1c12ee1eSDan Willemsen out.initialized = true 574*1c12ee1eSDan Willemsen } 575*1c12ee1eSDan Willemsen return out, ValidationValid 576*1c12ee1eSDan Willemsen} 577