blob: bf0d79018dd1d27c60a0c8c69c213d9aeec76614 [file] [log] [blame]
Herbie Ong800c9902018-12-06 15:28:53 -08001// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package textpb
6
7import (
8 "fmt"
Herbie Ong0dcfb9a2019-01-14 15:32:26 -08009 "strings"
Herbie Ong800c9902018-12-06 15:28:53 -080010
11 "github.com/golang/protobuf/v2/internal/encoding/text"
12 "github.com/golang/protobuf/v2/internal/errors"
13 "github.com/golang/protobuf/v2/internal/pragma"
14 "github.com/golang/protobuf/v2/internal/set"
15 "github.com/golang/protobuf/v2/proto"
16 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
Herbie Ongc525c972018-12-18 18:04:31 -080017 "github.com/golang/protobuf/v2/reflect/protoregistry"
Herbie Ong800c9902018-12-06 15:28:53 -080018)
19
20// Unmarshal reads the given []byte into the given proto.Message.
21// TODO: may want to describe when Unmarshal returns error.
22func Unmarshal(m proto.Message, b []byte) error {
23 return UnmarshalOptions{}.Unmarshal(m, b)
24}
25
26// UnmarshalOptions is a configurable textproto format parser.
27type UnmarshalOptions struct {
28 pragma.NoUnkeyedLiterals
Herbie Ongc525c972018-12-18 18:04:31 -080029
30 // Resolver is the registry used for type lookups when unmarshaling extensions
31 // and processing Any. If Resolver is not set, unmarshaling will default to
32 // using protoregistry.GlobalTypes.
33 Resolver *protoregistry.Types
Herbie Ong800c9902018-12-06 15:28:53 -080034}
35
36// Unmarshal reads the given []byte and populates the given proto.Message using options in
37// UnmarshalOptions object.
38func (o UnmarshalOptions) Unmarshal(m proto.Message, b []byte) error {
39 var nerr errors.NonFatal
40
41 mr := m.ProtoReflect()
42 // Clear all fields before populating it.
43 // TODO: Determine if this needs to be consistent with jsonpb and binary unmarshal where
44 // behavior is to merge values into existing message. If decision is to not clear the fields
45 // ahead, code will need to be updated properly when merging nested messages.
46 resetMessage(mr)
47
48 // Parse into text.Value of message type.
49 val, err := text.Unmarshal(b)
50 if !nerr.Merge(err) {
51 return err
52 }
53
Herbie Ongc525c972018-12-18 18:04:31 -080054 if o.Resolver == nil {
55 o.Resolver = protoregistry.GlobalTypes
56 }
Herbie Ong800c9902018-12-06 15:28:53 -080057 err = o.unmarshalMessage(val.Message(), mr)
58 if !nerr.Merge(err) {
59 return err
60 }
61
62 return nerr.E
63}
64
65// resetMessage clears all fields of given protoreflect.Message.
66// TODO: This should go into the proto package.
67func resetMessage(m pref.Message) {
68 knownFields := m.KnownFields()
69 knownFields.Range(func(num pref.FieldNumber, _ pref.Value) bool {
70 knownFields.Clear(num)
71 return true
72 })
73 unknownFields := m.UnknownFields()
74 unknownFields.Range(func(num pref.FieldNumber, _ pref.RawFields) bool {
75 unknownFields.Set(num, nil)
76 return true
77 })
Herbie Ong800c9902018-12-06 15:28:53 -080078 extTypes := knownFields.ExtensionTypes()
79 extTypes.Range(func(xt pref.ExtensionType) bool {
80 extTypes.Remove(xt)
81 return true
82 })
83}
84
85// unmarshalMessage unmarshals a [][2]text.Value message into the given protoreflect.Message.
86func (o UnmarshalOptions) unmarshalMessage(tmsg [][2]text.Value, m pref.Message) error {
87 var nerr errors.NonFatal
88
89 msgType := m.Type()
Herbie Ong66c365c2019-01-04 14:08:41 -080090 knownFields := m.KnownFields()
91
92 // Handle expanded Any message.
93 if msgType.FullName() == "google.protobuf.Any" && isExpandedAny(tmsg) {
94 return o.unmarshalAny(tmsg[0], knownFields)
95 }
96
Herbie Ong800c9902018-12-06 15:28:53 -080097 fieldDescs := msgType.Fields()
Herbie Ong7c624e22018-12-13 14:41:22 -080098 reservedNames := msgType.ReservedNames()
Herbie Ongc525c972018-12-18 18:04:31 -080099 xtTypes := knownFields.ExtensionTypes()
Herbie Ong800c9902018-12-06 15:28:53 -0800100 var reqNums set.Ints
101 var seenNums set.Ints
102
103 for _, tfield := range tmsg {
104 tkey := tfield[0]
105 tval := tfield[1]
106
107 var fd pref.FieldDescriptor
Herbie Ongc525c972018-12-18 18:04:31 -0800108 var name pref.Name
109 switch tkey.Type() {
110 case text.Name:
111 name, _ = tkey.Name()
Herbie Ong800c9902018-12-06 15:28:53 -0800112 fd = fieldDescs.ByName(name)
Herbie Ong0dcfb9a2019-01-14 15:32:26 -0800113 if fd == nil {
114 // Check if this is a group field.
115 fd = fieldDescs.ByName(pref.Name(strings.ToLower(string(name))))
116 }
Herbie Ongc525c972018-12-18 18:04:31 -0800117 case text.String:
Herbie Ong66c365c2019-01-04 14:08:41 -0800118 // Handle extensions only. This code path is not for Any.
119 if msgType.FullName() == "google.protobuf.Any" {
120 break
121 }
122 // Extensions have to be registered first in the message's
Herbie Ongc525c972018-12-18 18:04:31 -0800123 // ExtensionTypes before setting a value to it.
124 xtName := pref.FullName(tkey.String())
Herbie Ong66c365c2019-01-04 14:08:41 -0800125 // Check first if it is already registered. This is the case for
126 // repeated fields.
Herbie Ongc525c972018-12-18 18:04:31 -0800127 xt := xtTypes.ByName(xtName)
128 if xt == nil {
129 var err error
Herbie Ong6470ea62019-01-07 18:56:57 -0800130 xt, err = o.findExtension(xtName)
Herbie Ongc525c972018-12-18 18:04:31 -0800131 if err != nil && err != protoregistry.NotFound {
Herbie Ong66c365c2019-01-04 14:08:41 -0800132 return errors.New("unable to resolve [%v]: %v", xtName, err)
Herbie Ongc525c972018-12-18 18:04:31 -0800133 }
134 if xt != nil {
135 xtTypes.Register(xt)
136 }
137 }
138 fd = xt
Herbie Ong800c9902018-12-06 15:28:53 -0800139 }
Herbie Ongc525c972018-12-18 18:04:31 -0800140
Herbie Ong800c9902018-12-06 15:28:53 -0800141 if fd == nil {
Herbie Ong7c624e22018-12-13 14:41:22 -0800142 // Ignore reserved names.
143 if reservedNames.Has(name) {
144 continue
145 }
Herbie Ong800c9902018-12-06 15:28:53 -0800146 // TODO: Can provide option to ignore unknown message fields.
Herbie Ong800c9902018-12-06 15:28:53 -0800147 return errors.New("%v contains unknown field: %v", msgType.FullName(), tkey)
148 }
149
150 if cardinality := fd.Cardinality(); cardinality == pref.Repeated {
151 // Map or list fields have cardinality of repeated.
152 if err := o.unmarshalRepeated(tval, fd, knownFields); !nerr.Merge(err) {
153 return err
154 }
155 } else {
156 // Required or optional fields.
157 num := uint64(fd.Number())
158 if seenNums.Has(num) {
159 return errors.New("non-repeated field %v is repeated", fd.FullName())
160 }
161 if err := o.unmarshalSingular(tval, fd, knownFields); !nerr.Merge(err) {
162 return err
163 }
164 if cardinality == pref.Required {
165 reqNums.Set(num)
166 }
167 seenNums.Set(num)
168 }
169 }
170
171 // Check for any missing required fields.
172 allReqNums := msgType.RequiredNumbers()
173 if reqNums.Len() != allReqNums.Len() {
174 for i := 0; i < allReqNums.Len(); i++ {
175 if num := allReqNums.Get(i); !reqNums.Has(uint64(num)) {
176 nerr.AppendRequiredNotSet(string(fieldDescs.ByNumber(num).FullName()))
177 }
178 }
179 }
180
181 return nerr.E
182}
183
Herbie Ong6470ea62019-01-07 18:56:57 -0800184// findExtension returns protoreflect.ExtensionType from the Resolver if found.
185func (o UnmarshalOptions) findExtension(xtName pref.FullName) (pref.ExtensionType, error) {
186 xt, err := o.Resolver.FindExtensionByName(xtName)
187 if err == nil {
188 return xt, nil
189 }
190
191 // Check if this is a MessageSet extension field.
192 xt, err = o.Resolver.FindExtensionByName(xtName + ".message_set_extension")
193 if err == nil && isMessageSetExtension(xt) {
194 return xt, nil
195 }
196 return nil, protoregistry.NotFound
197}
198
Herbie Ong800c9902018-12-06 15:28:53 -0800199// unmarshalSingular unmarshals given text.Value into the non-repeated field.
200func (o UnmarshalOptions) unmarshalSingular(input text.Value, fd pref.FieldDescriptor, knownFields pref.KnownFields) error {
201 num := fd.Number()
202
203 var nerr errors.NonFatal
204 var val pref.Value
205 switch fd.Kind() {
206 case pref.MessageKind, pref.GroupKind:
207 if input.Type() != text.Message {
208 return errors.New("%v contains invalid message/group value: %v", fd.FullName(), input)
209 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800210 m := knownFields.NewMessage(num)
Herbie Ong800c9902018-12-06 15:28:53 -0800211 if err := o.unmarshalMessage(input.Message(), m); !nerr.Merge(err) {
212 return err
213 }
214 val = pref.ValueOf(m)
215 default:
216 var err error
217 val, err = unmarshalScalar(input, fd)
218 if !nerr.Merge(err) {
219 return err
220 }
221 }
222 knownFields.Set(num, val)
223
224 return nerr.E
225}
226
227// unmarshalRepeated unmarshals given text.Value into a repeated field. Caller should only
228// call this for cardinality=repeated.
229func (o UnmarshalOptions) unmarshalRepeated(input text.Value, fd pref.FieldDescriptor, knownFields pref.KnownFields) error {
230 var items []text.Value
231 // If input is not a list, turn it into a list.
232 if input.Type() != text.List {
233 items = []text.Value{input}
234 } else {
235 items = input.List()
236 }
237
238 var nerr errors.NonFatal
239 num := fd.Number()
240 val := knownFields.Get(num)
241 if !fd.IsMap() {
242 if err := o.unmarshalList(items, fd, val.List()); !nerr.Merge(err) {
243 return err
244 }
245 } else {
246 if err := o.unmarshalMap(items, fd, val.Map()); !nerr.Merge(err) {
247 return err
248 }
249 }
250
251 return nerr.E
252}
253
254// unmarshalScalar converts the given text.Value to a scalar/enum protoreflect.Value specified in
255// the given FieldDescriptor. Caller should not pass in a FieldDescriptor for a message/group kind.
256func unmarshalScalar(input text.Value, fd pref.FieldDescriptor) (pref.Value, error) {
257 const b32 = false
258 const b64 = true
259
260 switch kind := fd.Kind(); kind {
261 case pref.BoolKind:
262 if b, ok := input.Bool(); ok {
263 return pref.ValueOf(bool(b)), nil
264 }
265 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
266 if n, ok := input.Int(b32); ok {
267 return pref.ValueOf(int32(n)), nil
268 }
269 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
270 if n, ok := input.Int(b64); ok {
271 return pref.ValueOf(int64(n)), nil
272 }
273 case pref.Uint32Kind, pref.Fixed32Kind:
274 if n, ok := input.Uint(b32); ok {
275 return pref.ValueOf(uint32(n)), nil
276 }
277 case pref.Uint64Kind, pref.Fixed64Kind:
278 if n, ok := input.Uint(b64); ok {
279 return pref.ValueOf(uint64(n)), nil
280 }
281 case pref.FloatKind:
Herbie Ong250c6ea2019-03-12 20:55:10 -0700282 if n, ok := input.Float(b32); ok {
Herbie Ong800c9902018-12-06 15:28:53 -0800283 return pref.ValueOf(float32(n)), nil
284 }
285 case pref.DoubleKind:
Herbie Ong250c6ea2019-03-12 20:55:10 -0700286 if n, ok := input.Float(b64); ok {
Herbie Ong800c9902018-12-06 15:28:53 -0800287 return pref.ValueOf(float64(n)), nil
288 }
289 case pref.StringKind:
290 if input.Type() == text.String {
291 return pref.ValueOf(string(input.String())), nil
292 }
293 case pref.BytesKind:
294 if input.Type() == text.String {
295 return pref.ValueOf([]byte(input.String())), nil
296 }
297 case pref.EnumKind:
298 // If input is int32, use directly.
299 if n, ok := input.Int(b32); ok {
300 return pref.ValueOf(pref.EnumNumber(n)), nil
Herbie Ong66c365c2019-01-04 14:08:41 -0800301 }
302 if name, ok := input.Name(); ok {
303 // Lookup EnumNumber based on name.
304 if enumVal := fd.EnumType().Values().ByName(name); enumVal != nil {
305 return pref.ValueOf(enumVal.Number()), nil
Herbie Ong800c9902018-12-06 15:28:53 -0800306 }
307 }
308 default:
309 panic(fmt.Sprintf("invalid scalar kind %v", kind))
310 }
311
312 return pref.Value{}, errors.New("%v contains invalid scalar value: %v", fd.FullName(), input)
313}
314
315// unmarshalList unmarshals given []text.Value into given protoreflect.List.
316func (o UnmarshalOptions) unmarshalList(inputList []text.Value, fd pref.FieldDescriptor, list pref.List) error {
317 var nerr errors.NonFatal
318
319 switch fd.Kind() {
320 case pref.MessageKind, pref.GroupKind:
321 for _, input := range inputList {
322 if input.Type() != text.Message {
323 return errors.New("%v contains invalid message/group value: %v", fd.FullName(), input)
324 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800325 m := list.NewMessage()
Herbie Ong800c9902018-12-06 15:28:53 -0800326 if err := o.unmarshalMessage(input.Message(), m); !nerr.Merge(err) {
327 return err
328 }
329 list.Append(pref.ValueOf(m))
330 }
331 default:
332 for _, input := range inputList {
333 val, err := unmarshalScalar(input, fd)
334 if !nerr.Merge(err) {
335 return err
336 }
337 list.Append(val)
338 }
339 }
340
341 return nerr.E
342}
343
344// unmarshalMap unmarshals given []text.Value into given protoreflect.Map.
345func (o UnmarshalOptions) unmarshalMap(input []text.Value, fd pref.FieldDescriptor, mmap pref.Map) error {
346 var nerr errors.NonFatal
347 fields := fd.MessageType().Fields()
348 keyDesc := fields.ByNumber(1)
349 valDesc := fields.ByNumber(2)
350
351 // Determine ahead whether map entry is a scalar type or a message type in order to call the
352 // appropriate unmarshalMapValue func inside the for loop below.
Herbie Ong66c365c2019-01-04 14:08:41 -0800353 unmarshalMapValue := unmarshalMapScalarValue
Herbie Ong800c9902018-12-06 15:28:53 -0800354 switch valDesc.Kind() {
355 case pref.MessageKind, pref.GroupKind:
356 unmarshalMapValue = o.unmarshalMapMessageValue
357 }
358
359 for _, entry := range input {
360 if entry.Type() != text.Message {
361 return errors.New("%v contains invalid map entry: %v", fd.FullName(), entry)
362 }
363 tkey, tval, err := parseMapEntry(entry.Message(), fd.FullName())
364 if !nerr.Merge(err) {
365 return err
366 }
367 pkey, err := unmarshalMapKey(tkey, keyDesc)
368 if !nerr.Merge(err) {
369 return err
370 }
371 err = unmarshalMapValue(tval, pkey, valDesc, mmap)
372 if !nerr.Merge(err) {
373 return err
374 }
375 }
376
377 return nerr.E
378}
379
380// parseMapEntry parses [][2]text.Value for field names key and value, and return corresponding
381// field values. If there are duplicate field names, the value for the last field is returned. If
382// the field name does not exist, it will return the zero value of text.Value. It will return an
383// error if there are unknown field names.
384func parseMapEntry(mapEntry [][2]text.Value, name pref.FullName) (key text.Value, value text.Value, err error) {
385 for _, field := range mapEntry {
386 keyStr, ok := field[0].Name()
387 if ok {
388 switch keyStr {
389 case "key":
390 if key.Type() != 0 {
391 return key, value, errors.New("%v contains duplicate key field", name)
392 }
393 key = field[1]
394 case "value":
395 if value.Type() != 0 {
396 return key, value, errors.New("%v contains duplicate value field", name)
397 }
398 value = field[1]
399 default:
400 ok = false
401 }
402 }
403 if !ok {
404 // TODO: Do not return error if ignore unknown option is added and enabled.
405 return key, value, errors.New("%v contains unknown map entry name: %v", name, field[0])
406 }
407 }
408 return key, value, nil
409}
410
411// unmarshalMapKey converts given text.Value into a protoreflect.MapKey. A map key type is any
412// integral or string type.
413func unmarshalMapKey(input text.Value, fd pref.FieldDescriptor) (pref.MapKey, error) {
414 // If input is not set, use the zero value.
415 if input.Type() == 0 {
416 return fd.Default().MapKey(), nil
417 }
418
419 val, err := unmarshalScalar(input, fd)
420 if err != nil {
421 return pref.MapKey{}, errors.New("%v contains invalid key: %v", fd.FullName(), input)
422 }
423 return val.MapKey(), nil
424}
425
426// unmarshalMapMessageValue unmarshals given message-type text.Value into a protoreflect.Map for
427// the given MapKey.
428func (o UnmarshalOptions) unmarshalMapMessageValue(input text.Value, pkey pref.MapKey, _ pref.FieldDescriptor, mmap pref.Map) error {
429 var nerr errors.NonFatal
430 var value [][2]text.Value
431 if input.Type() != 0 {
432 value = input.Message()
433 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800434 m := mmap.NewMessage()
Herbie Ong800c9902018-12-06 15:28:53 -0800435 if err := o.unmarshalMessage(value, m); !nerr.Merge(err) {
436 return err
437 }
438 mmap.Set(pkey, pref.ValueOf(m))
439 return nerr.E
440}
441
442// unmarshalMapScalarValue unmarshals given scalar-type text.Value into a protoreflect.Map
443// for the given MapKey.
Herbie Ong66c365c2019-01-04 14:08:41 -0800444func unmarshalMapScalarValue(input text.Value, pkey pref.MapKey, fd pref.FieldDescriptor, mmap pref.Map) error {
Herbie Ong800c9902018-12-06 15:28:53 -0800445 var val pref.Value
446 if input.Type() == 0 {
447 val = fd.Default()
448 } else {
449 var err error
450 val, err = unmarshalScalar(input, fd)
451 if err != nil {
452 return err
453 }
454 }
455 mmap.Set(pkey, val)
456 return nil
457}
Herbie Ong66c365c2019-01-04 14:08:41 -0800458
459// isExpandedAny returns true if given [][2]text.Value may be an expanded Any that contains only one
460// field with key type of text.String type and value type of text.Message.
461func isExpandedAny(tmsg [][2]text.Value) bool {
462 if len(tmsg) != 1 {
463 return false
464 }
465
466 field := tmsg[0]
467 return field[0].Type() == text.String && field[1].Type() == text.Message
468}
469
470// unmarshalAny unmarshals an expanded Any textproto. This method assumes that the given
471// tfield has key type of text.String and value type of text.Message.
472func (o UnmarshalOptions) unmarshalAny(tfield [2]text.Value, knownFields pref.KnownFields) error {
473 var nerr errors.NonFatal
474
475 typeURL := tfield[0].String()
476 value := tfield[1].Message()
477
478 mt, err := o.Resolver.FindMessageByURL(typeURL)
479 if !nerr.Merge(err) {
480 return errors.New("unable to resolve message [%v]: %v", typeURL, err)
481 }
482 // Create new message for the embedded message type and unmarshal the
483 // value into it.
484 m := mt.New()
485 if err := o.unmarshalMessage(value, m); !nerr.Merge(err) {
486 return err
487 }
488 // Serialize the embedded message and assign the resulting bytes to the value field.
Herbie Onge0cf15b2019-03-15 19:32:38 -0700489 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m.Interface())
Herbie Ong66c365c2019-01-04 14:08:41 -0800490 if !nerr.Merge(err) {
491 return err
492 }
493
494 knownFields.Set(pref.FieldNumber(1), pref.ValueOf(typeURL))
495 knownFields.Set(pref.FieldNumber(2), pref.ValueOf(b))
496
497 return nerr.E
498}