blob: aef9d403ad91313a951e383441de8b739a7d6d4d [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
Herbie Ong66c365c2019-01-04 14:08:41 -080011 protoV1 "github.com/golang/protobuf/proto"
Herbie Ong800c9902018-12-06 15:28:53 -080012 "github.com/golang/protobuf/v2/internal/encoding/text"
13 "github.com/golang/protobuf/v2/internal/errors"
14 "github.com/golang/protobuf/v2/internal/pragma"
15 "github.com/golang/protobuf/v2/internal/set"
Herbie Ong66c365c2019-01-04 14:08:41 -080016 pvalue "github.com/golang/protobuf/v2/internal/value"
Herbie Ong800c9902018-12-06 15:28:53 -080017 "github.com/golang/protobuf/v2/proto"
18 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
Herbie Ongc525c972018-12-18 18:04:31 -080019 "github.com/golang/protobuf/v2/reflect/protoregistry"
Herbie Ong800c9902018-12-06 15:28:53 -080020)
21
22// Unmarshal reads the given []byte into the given proto.Message.
23// TODO: may want to describe when Unmarshal returns error.
24func Unmarshal(m proto.Message, b []byte) error {
25 return UnmarshalOptions{}.Unmarshal(m, b)
26}
27
28// UnmarshalOptions is a configurable textproto format parser.
29type UnmarshalOptions struct {
30 pragma.NoUnkeyedLiterals
Herbie Ongc525c972018-12-18 18:04:31 -080031
32 // Resolver is the registry used for type lookups when unmarshaling extensions
33 // and processing Any. If Resolver is not set, unmarshaling will default to
34 // using protoregistry.GlobalTypes.
35 Resolver *protoregistry.Types
Herbie Ong800c9902018-12-06 15:28:53 -080036}
37
38// Unmarshal reads the given []byte and populates the given proto.Message using options in
39// UnmarshalOptions object.
40func (o UnmarshalOptions) Unmarshal(m proto.Message, b []byte) error {
41 var nerr errors.NonFatal
42
43 mr := m.ProtoReflect()
44 // Clear all fields before populating it.
45 // TODO: Determine if this needs to be consistent with jsonpb and binary unmarshal where
46 // behavior is to merge values into existing message. If decision is to not clear the fields
47 // ahead, code will need to be updated properly when merging nested messages.
48 resetMessage(mr)
49
50 // Parse into text.Value of message type.
51 val, err := text.Unmarshal(b)
52 if !nerr.Merge(err) {
53 return err
54 }
55
Herbie Ongc525c972018-12-18 18:04:31 -080056 if o.Resolver == nil {
57 o.Resolver = protoregistry.GlobalTypes
58 }
Herbie Ong800c9902018-12-06 15:28:53 -080059 err = o.unmarshalMessage(val.Message(), mr)
60 if !nerr.Merge(err) {
61 return err
62 }
63
64 return nerr.E
65}
66
67// resetMessage clears all fields of given protoreflect.Message.
68// TODO: This should go into the proto package.
69func resetMessage(m pref.Message) {
70 knownFields := m.KnownFields()
71 knownFields.Range(func(num pref.FieldNumber, _ pref.Value) bool {
72 knownFields.Clear(num)
73 return true
74 })
75 unknownFields := m.UnknownFields()
76 unknownFields.Range(func(num pref.FieldNumber, _ pref.RawFields) bool {
77 unknownFields.Set(num, nil)
78 return true
79 })
Herbie Ong800c9902018-12-06 15:28:53 -080080 extTypes := knownFields.ExtensionTypes()
81 extTypes.Range(func(xt pref.ExtensionType) bool {
82 extTypes.Remove(xt)
83 return true
84 })
85}
86
87// unmarshalMessage unmarshals a [][2]text.Value message into the given protoreflect.Message.
88func (o UnmarshalOptions) unmarshalMessage(tmsg [][2]text.Value, m pref.Message) error {
89 var nerr errors.NonFatal
90
91 msgType := m.Type()
Herbie Ong66c365c2019-01-04 14:08:41 -080092 knownFields := m.KnownFields()
93
94 // Handle expanded Any message.
95 if msgType.FullName() == "google.protobuf.Any" && isExpandedAny(tmsg) {
96 return o.unmarshalAny(tmsg[0], knownFields)
97 }
98
Herbie Ong800c9902018-12-06 15:28:53 -080099 fieldDescs := msgType.Fields()
Herbie Ong7c624e22018-12-13 14:41:22 -0800100 reservedNames := msgType.ReservedNames()
Herbie Ongc525c972018-12-18 18:04:31 -0800101 xtTypes := knownFields.ExtensionTypes()
Herbie Ong800c9902018-12-06 15:28:53 -0800102 var reqNums set.Ints
103 var seenNums set.Ints
104
105 for _, tfield := range tmsg {
106 tkey := tfield[0]
107 tval := tfield[1]
108
109 var fd pref.FieldDescriptor
Herbie Ongc525c972018-12-18 18:04:31 -0800110 var name pref.Name
111 switch tkey.Type() {
112 case text.Name:
113 name, _ = tkey.Name()
Herbie Ong800c9902018-12-06 15:28:53 -0800114 fd = fieldDescs.ByName(name)
Herbie Ong0dcfb9a2019-01-14 15:32:26 -0800115 if fd == nil {
116 // Check if this is a group field.
117 fd = fieldDescs.ByName(pref.Name(strings.ToLower(string(name))))
118 }
Herbie Ongc525c972018-12-18 18:04:31 -0800119 case text.String:
Herbie Ong66c365c2019-01-04 14:08:41 -0800120 // Handle extensions only. This code path is not for Any.
121 if msgType.FullName() == "google.protobuf.Any" {
122 break
123 }
124 // Extensions have to be registered first in the message's
Herbie Ongc525c972018-12-18 18:04:31 -0800125 // ExtensionTypes before setting a value to it.
126 xtName := pref.FullName(tkey.String())
Herbie Ong66c365c2019-01-04 14:08:41 -0800127 // Check first if it is already registered. This is the case for
128 // repeated fields.
Herbie Ongc525c972018-12-18 18:04:31 -0800129 xt := xtTypes.ByName(xtName)
130 if xt == nil {
131 var err error
Herbie Ong6470ea62019-01-07 18:56:57 -0800132 xt, err = o.findExtension(xtName)
Herbie Ongc525c972018-12-18 18:04:31 -0800133 if err != nil && err != protoregistry.NotFound {
Herbie Ong66c365c2019-01-04 14:08:41 -0800134 return errors.New("unable to resolve [%v]: %v", xtName, err)
Herbie Ongc525c972018-12-18 18:04:31 -0800135 }
136 if xt != nil {
137 xtTypes.Register(xt)
138 }
139 }
140 fd = xt
Herbie Ong800c9902018-12-06 15:28:53 -0800141 }
Herbie Ongc525c972018-12-18 18:04:31 -0800142
Herbie Ong800c9902018-12-06 15:28:53 -0800143 if fd == nil {
Herbie Ong7c624e22018-12-13 14:41:22 -0800144 // Ignore reserved names.
145 if reservedNames.Has(name) {
146 continue
147 }
Herbie Ong800c9902018-12-06 15:28:53 -0800148 // TODO: Can provide option to ignore unknown message fields.
Herbie Ong800c9902018-12-06 15:28:53 -0800149 return errors.New("%v contains unknown field: %v", msgType.FullName(), tkey)
150 }
151
152 if cardinality := fd.Cardinality(); cardinality == pref.Repeated {
153 // Map or list fields have cardinality of repeated.
154 if err := o.unmarshalRepeated(tval, fd, knownFields); !nerr.Merge(err) {
155 return err
156 }
157 } else {
158 // Required or optional fields.
159 num := uint64(fd.Number())
160 if seenNums.Has(num) {
161 return errors.New("non-repeated field %v is repeated", fd.FullName())
162 }
163 if err := o.unmarshalSingular(tval, fd, knownFields); !nerr.Merge(err) {
164 return err
165 }
166 if cardinality == pref.Required {
167 reqNums.Set(num)
168 }
169 seenNums.Set(num)
170 }
171 }
172
173 // Check for any missing required fields.
174 allReqNums := msgType.RequiredNumbers()
175 if reqNums.Len() != allReqNums.Len() {
176 for i := 0; i < allReqNums.Len(); i++ {
177 if num := allReqNums.Get(i); !reqNums.Has(uint64(num)) {
178 nerr.AppendRequiredNotSet(string(fieldDescs.ByNumber(num).FullName()))
179 }
180 }
181 }
182
183 return nerr.E
184}
185
Herbie Ong6470ea62019-01-07 18:56:57 -0800186// findExtension returns protoreflect.ExtensionType from the Resolver if found.
187func (o UnmarshalOptions) findExtension(xtName pref.FullName) (pref.ExtensionType, error) {
188 xt, err := o.Resolver.FindExtensionByName(xtName)
189 if err == nil {
190 return xt, nil
191 }
192
193 // Check if this is a MessageSet extension field.
194 xt, err = o.Resolver.FindExtensionByName(xtName + ".message_set_extension")
195 if err == nil && isMessageSetExtension(xt) {
196 return xt, nil
197 }
198 return nil, protoregistry.NotFound
199}
200
Herbie Ong800c9902018-12-06 15:28:53 -0800201// unmarshalSingular unmarshals given text.Value into the non-repeated field.
202func (o UnmarshalOptions) unmarshalSingular(input text.Value, fd pref.FieldDescriptor, knownFields pref.KnownFields) error {
203 num := fd.Number()
204
205 var nerr errors.NonFatal
206 var val pref.Value
207 switch fd.Kind() {
208 case pref.MessageKind, pref.GroupKind:
209 if input.Type() != text.Message {
210 return errors.New("%v contains invalid message/group value: %v", fd.FullName(), input)
211 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800212 m := knownFields.NewMessage(num)
Herbie Ong800c9902018-12-06 15:28:53 -0800213 if err := o.unmarshalMessage(input.Message(), m); !nerr.Merge(err) {
214 return err
215 }
216 val = pref.ValueOf(m)
217 default:
218 var err error
219 val, err = unmarshalScalar(input, fd)
220 if !nerr.Merge(err) {
221 return err
222 }
223 }
224 knownFields.Set(num, val)
225
226 return nerr.E
227}
228
229// unmarshalRepeated unmarshals given text.Value into a repeated field. Caller should only
230// call this for cardinality=repeated.
231func (o UnmarshalOptions) unmarshalRepeated(input text.Value, fd pref.FieldDescriptor, knownFields pref.KnownFields) error {
232 var items []text.Value
233 // If input is not a list, turn it into a list.
234 if input.Type() != text.List {
235 items = []text.Value{input}
236 } else {
237 items = input.List()
238 }
239
240 var nerr errors.NonFatal
241 num := fd.Number()
242 val := knownFields.Get(num)
243 if !fd.IsMap() {
244 if err := o.unmarshalList(items, fd, val.List()); !nerr.Merge(err) {
245 return err
246 }
247 } else {
248 if err := o.unmarshalMap(items, fd, val.Map()); !nerr.Merge(err) {
249 return err
250 }
251 }
252
253 return nerr.E
254}
255
256// unmarshalScalar converts the given text.Value to a scalar/enum protoreflect.Value specified in
257// the given FieldDescriptor. Caller should not pass in a FieldDescriptor for a message/group kind.
258func unmarshalScalar(input text.Value, fd pref.FieldDescriptor) (pref.Value, error) {
259 const b32 = false
260 const b64 = true
261
262 switch kind := fd.Kind(); kind {
263 case pref.BoolKind:
264 if b, ok := input.Bool(); ok {
265 return pref.ValueOf(bool(b)), nil
266 }
267 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
268 if n, ok := input.Int(b32); ok {
269 return pref.ValueOf(int32(n)), nil
270 }
271 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
272 if n, ok := input.Int(b64); ok {
273 return pref.ValueOf(int64(n)), nil
274 }
275 case pref.Uint32Kind, pref.Fixed32Kind:
276 if n, ok := input.Uint(b32); ok {
277 return pref.ValueOf(uint32(n)), nil
278 }
279 case pref.Uint64Kind, pref.Fixed64Kind:
280 if n, ok := input.Uint(b64); ok {
281 return pref.ValueOf(uint64(n)), nil
282 }
283 case pref.FloatKind:
Herbie Ong84f09602019-01-17 19:31:47 -0800284 if n, ok := input.Float32(); ok {
Herbie Ong800c9902018-12-06 15:28:53 -0800285 return pref.ValueOf(float32(n)), nil
286 }
287 case pref.DoubleKind:
Herbie Ong84f09602019-01-17 19:31:47 -0800288 if n, ok := input.Float64(); ok {
Herbie Ong800c9902018-12-06 15:28:53 -0800289 return pref.ValueOf(float64(n)), nil
290 }
291 case pref.StringKind:
292 if input.Type() == text.String {
293 return pref.ValueOf(string(input.String())), nil
294 }
295 case pref.BytesKind:
296 if input.Type() == text.String {
297 return pref.ValueOf([]byte(input.String())), nil
298 }
299 case pref.EnumKind:
300 // If input is int32, use directly.
301 if n, ok := input.Int(b32); ok {
302 return pref.ValueOf(pref.EnumNumber(n)), nil
Herbie Ong66c365c2019-01-04 14:08:41 -0800303 }
304 if name, ok := input.Name(); ok {
305 // Lookup EnumNumber based on name.
306 if enumVal := fd.EnumType().Values().ByName(name); enumVal != nil {
307 return pref.ValueOf(enumVal.Number()), nil
Herbie Ong800c9902018-12-06 15:28:53 -0800308 }
309 }
310 default:
311 panic(fmt.Sprintf("invalid scalar kind %v", kind))
312 }
313
314 return pref.Value{}, errors.New("%v contains invalid scalar value: %v", fd.FullName(), input)
315}
316
317// unmarshalList unmarshals given []text.Value into given protoreflect.List.
318func (o UnmarshalOptions) unmarshalList(inputList []text.Value, fd pref.FieldDescriptor, list pref.List) error {
319 var nerr errors.NonFatal
320
321 switch fd.Kind() {
322 case pref.MessageKind, pref.GroupKind:
323 for _, input := range inputList {
324 if input.Type() != text.Message {
325 return errors.New("%v contains invalid message/group value: %v", fd.FullName(), input)
326 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800327 m := list.NewMessage()
Herbie Ong800c9902018-12-06 15:28:53 -0800328 if err := o.unmarshalMessage(input.Message(), m); !nerr.Merge(err) {
329 return err
330 }
331 list.Append(pref.ValueOf(m))
332 }
333 default:
334 for _, input := range inputList {
335 val, err := unmarshalScalar(input, fd)
336 if !nerr.Merge(err) {
337 return err
338 }
339 list.Append(val)
340 }
341 }
342
343 return nerr.E
344}
345
346// unmarshalMap unmarshals given []text.Value into given protoreflect.Map.
347func (o UnmarshalOptions) unmarshalMap(input []text.Value, fd pref.FieldDescriptor, mmap pref.Map) error {
348 var nerr errors.NonFatal
349 fields := fd.MessageType().Fields()
350 keyDesc := fields.ByNumber(1)
351 valDesc := fields.ByNumber(2)
352
353 // Determine ahead whether map entry is a scalar type or a message type in order to call the
354 // appropriate unmarshalMapValue func inside the for loop below.
Herbie Ong66c365c2019-01-04 14:08:41 -0800355 unmarshalMapValue := unmarshalMapScalarValue
Herbie Ong800c9902018-12-06 15:28:53 -0800356 switch valDesc.Kind() {
357 case pref.MessageKind, pref.GroupKind:
358 unmarshalMapValue = o.unmarshalMapMessageValue
359 }
360
361 for _, entry := range input {
362 if entry.Type() != text.Message {
363 return errors.New("%v contains invalid map entry: %v", fd.FullName(), entry)
364 }
365 tkey, tval, err := parseMapEntry(entry.Message(), fd.FullName())
366 if !nerr.Merge(err) {
367 return err
368 }
369 pkey, err := unmarshalMapKey(tkey, keyDesc)
370 if !nerr.Merge(err) {
371 return err
372 }
373 err = unmarshalMapValue(tval, pkey, valDesc, mmap)
374 if !nerr.Merge(err) {
375 return err
376 }
377 }
378
379 return nerr.E
380}
381
382// parseMapEntry parses [][2]text.Value for field names key and value, and return corresponding
383// field values. If there are duplicate field names, the value for the last field is returned. If
384// the field name does not exist, it will return the zero value of text.Value. It will return an
385// error if there are unknown field names.
386func parseMapEntry(mapEntry [][2]text.Value, name pref.FullName) (key text.Value, value text.Value, err error) {
387 for _, field := range mapEntry {
388 keyStr, ok := field[0].Name()
389 if ok {
390 switch keyStr {
391 case "key":
392 if key.Type() != 0 {
393 return key, value, errors.New("%v contains duplicate key field", name)
394 }
395 key = field[1]
396 case "value":
397 if value.Type() != 0 {
398 return key, value, errors.New("%v contains duplicate value field", name)
399 }
400 value = field[1]
401 default:
402 ok = false
403 }
404 }
405 if !ok {
406 // TODO: Do not return error if ignore unknown option is added and enabled.
407 return key, value, errors.New("%v contains unknown map entry name: %v", name, field[0])
408 }
409 }
410 return key, value, nil
411}
412
413// unmarshalMapKey converts given text.Value into a protoreflect.MapKey. A map key type is any
414// integral or string type.
415func unmarshalMapKey(input text.Value, fd pref.FieldDescriptor) (pref.MapKey, error) {
416 // If input is not set, use the zero value.
417 if input.Type() == 0 {
418 return fd.Default().MapKey(), nil
419 }
420
421 val, err := unmarshalScalar(input, fd)
422 if err != nil {
423 return pref.MapKey{}, errors.New("%v contains invalid key: %v", fd.FullName(), input)
424 }
425 return val.MapKey(), nil
426}
427
428// unmarshalMapMessageValue unmarshals given message-type text.Value into a protoreflect.Map for
429// the given MapKey.
430func (o UnmarshalOptions) unmarshalMapMessageValue(input text.Value, pkey pref.MapKey, _ pref.FieldDescriptor, mmap pref.Map) error {
431 var nerr errors.NonFatal
432 var value [][2]text.Value
433 if input.Type() != 0 {
434 value = input.Message()
435 }
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800436 m := mmap.NewMessage()
Herbie Ong800c9902018-12-06 15:28:53 -0800437 if err := o.unmarshalMessage(value, m); !nerr.Merge(err) {
438 return err
439 }
440 mmap.Set(pkey, pref.ValueOf(m))
441 return nerr.E
442}
443
444// unmarshalMapScalarValue unmarshals given scalar-type text.Value into a protoreflect.Map
445// for the given MapKey.
Herbie Ong66c365c2019-01-04 14:08:41 -0800446func unmarshalMapScalarValue(input text.Value, pkey pref.MapKey, fd pref.FieldDescriptor, mmap pref.Map) error {
Herbie Ong800c9902018-12-06 15:28:53 -0800447 var val pref.Value
448 if input.Type() == 0 {
449 val = fd.Default()
450 } else {
451 var err error
452 val, err = unmarshalScalar(input, fd)
453 if err != nil {
454 return err
455 }
456 }
457 mmap.Set(pkey, val)
458 return nil
459}
Herbie Ong66c365c2019-01-04 14:08:41 -0800460
461// isExpandedAny returns true if given [][2]text.Value may be an expanded Any that contains only one
462// field with key type of text.String type and value type of text.Message.
463func isExpandedAny(tmsg [][2]text.Value) bool {
464 if len(tmsg) != 1 {
465 return false
466 }
467
468 field := tmsg[0]
469 return field[0].Type() == text.String && field[1].Type() == text.Message
470}
471
472// unmarshalAny unmarshals an expanded Any textproto. This method assumes that the given
473// tfield has key type of text.String and value type of text.Message.
474func (o UnmarshalOptions) unmarshalAny(tfield [2]text.Value, knownFields pref.KnownFields) error {
475 var nerr errors.NonFatal
476
477 typeURL := tfield[0].String()
478 value := tfield[1].Message()
479
480 mt, err := o.Resolver.FindMessageByURL(typeURL)
481 if !nerr.Merge(err) {
482 return errors.New("unable to resolve message [%v]: %v", typeURL, err)
483 }
484 // Create new message for the embedded message type and unmarshal the
485 // value into it.
486 m := mt.New()
487 if err := o.unmarshalMessage(value, m); !nerr.Merge(err) {
488 return err
489 }
490 // Serialize the embedded message and assign the resulting bytes to the value field.
491 // TODO: Switch to V2 marshal and enable deterministic option when ready.
492 var mv1 protoV1.Message
493 if mtmp, ok := m.(pvalue.Unwrapper); ok {
494 mv1 = mtmp.ProtoUnwrap().(protoV1.Message)
495 } else {
496 mv1 = m.Interface().(protoV1.Message)
497 }
498 b, err := protoV1.Marshal(mv1)
499 if !nerr.Merge(err) {
500 return err
501 }
502
503 knownFields.Set(pref.FieldNumber(1), pref.ValueOf(typeURL))
504 knownFields.Set(pref.FieldNumber(2), pref.ValueOf(b))
505
506 return nerr.E
507}