@@ -411,6 +411,13 @@ extension AnyMessageStorage {
411
411
412
412
// _CustomJSONCodable support for Google_Protobuf_Any
413
413
extension AnyMessageStorage {
414
+ // Spec for Any says this should contain atleast one slash. Looking at upstream languages, most
415
+ // actually look up the value in their runtime registries, but since we do deferred parsing
416
+ // we can't assume the registry is complete, thus just do this minimal validation check.
417
+ fileprivate func isTypeURLValid( ) -> Bool {
418
+ _typeURL. contains ( " / " )
419
+ }
420
+
414
421
// Override the traversal-based JSON encoding
415
422
// This builds an Any JSON representation from one of:
416
423
// * The message we were initialized with,
@@ -423,11 +430,18 @@ extension AnyMessageStorage {
423
430
case . binary( let valueData) :
424
431
// Follow the C++ protostream_objectsource.cc's
425
432
// ProtoStreamObjectSource::RenderAny() special casing of an empty value.
426
- guard !valueData. isEmpty else {
433
+ if valueData. isEmpty && _typeURL. isEmpty {
434
+ return " {} "
435
+ }
436
+ guard isTypeURLValid ( ) else {
427
437
if _typeURL. isEmpty {
428
- return " {} "
438
+ throw SwiftProtobufError . JSONEncoding . emptyAnyTypeURL ( )
429
439
}
440
+ throw SwiftProtobufError . JSONEncoding. invalidAnyTypeURL ( type_url: _typeURL)
441
+ }
442
+ if valueData. isEmpty {
430
443
var jsonEncoder = JSONEncoder ( )
444
+ jsonEncoder. startObject ( )
431
445
jsonEncoder. startField ( name: " @type " )
432
446
jsonEncoder. putStringValue ( value: _typeURL)
433
447
jsonEncoder. endObject ( )
@@ -446,12 +460,21 @@ extension AnyMessageStorage {
446
460
return try serializeAnyJSON ( for: m, typeURL: _typeURL, options: options)
447
461
448
462
case . message( let msg) :
449
- // We should have been initialized with a typeURL, but
450
- // ensure it wasn't cleared.
463
+ // We should have been initialized with a typeURL, make sure it is valid.
464
+ if !_typeURL. isEmpty && !isTypeURLValid( ) {
465
+ throw SwiftProtobufError . JSONEncoding. invalidAnyTypeURL ( type_url: _typeURL)
466
+ }
467
+ // If it was cleared, default it.
451
468
let url = !_typeURL. isEmpty ? _typeURL : buildTypeURL ( forMessage: msg, typePrefix: defaultAnyTypeURLPrefix)
452
469
return try serializeAnyJSON ( for: msg, typeURL: url, options: options)
453
470
454
471
case . contentJSON( let contentJSON, _) :
472
+ guard isTypeURLValid ( ) else {
473
+ if _typeURL. isEmpty {
474
+ throw SwiftProtobufError . JSONEncoding. emptyAnyTypeURL ( )
475
+ }
476
+ throw SwiftProtobufError . JSONEncoding. invalidAnyTypeURL ( type_url: _typeURL)
477
+ }
455
478
var jsonEncoder = JSONEncoder ( )
456
479
jsonEncoder. startObject ( )
457
480
jsonEncoder. startField ( name: " @type " )
@@ -488,11 +511,7 @@ extension AnyMessageStorage {
488
511
try decoder. scanner. skipRequiredColon ( )
489
512
if key == " @type " {
490
513
_typeURL = try decoder. scanner. nextQuotedString ( )
491
- // Spec for Any says this should contain atleast one slash. Looking at
492
- // upstream languages, most actually look up the value in their runtime
493
- // registries, but since we do deferred parsing, just do this minimal
494
- // validation check.
495
- guard _typeURL. contains ( " / " ) else {
514
+ guard isTypeURLValid ( ) else {
496
515
throw SwiftProtobufError . JSONDecoding. invalidAnyTypeURL ( type_url: _typeURL)
497
516
}
498
517
} else {
@@ -501,6 +520,9 @@ extension AnyMessageStorage {
501
520
jsonEncoder. append ( text: keyValueJSON)
502
521
}
503
522
if decoder. scanner. skipOptionalObjectEnd ( ) {
523
+ if _typeURL. isEmpty {
524
+ throw SwiftProtobufError . JSONDecoding. emptyAnyTypeURL ( )
525
+ }
504
526
// Capture the options, but set the messageDepthLimit to be what
505
527
// was left right now, as that is the limit when the JSON is finally
506
528
// parsed.
0 commit comments