Line data Source code
1 : #include "source/common/protobuf/visitor.h" 2 : 3 : #include <vector> 4 : 5 : #include "source/common/protobuf/utility.h" 6 : #include "source/common/protobuf/visitor_helper.h" 7 : 8 : #include "udpa/type/v1/typed_struct.pb.h" 9 : #include "xds/type/v3/typed_struct.pb.h" 10 : 11 : namespace Envoy { 12 : namespace ProtobufMessage { 13 : namespace { 14 : 15 : void traverseMessageWorker(ConstProtoVisitor& visitor, const Protobuf::Message& message, 16 : std::vector<const Protobuf::Message*>& parents, 17 170664 : bool was_any_or_top_level, bool recurse_into_any) { 18 170664 : visitor.onMessage(message, parents, was_any_or_top_level); 19 : 20 : // If told to recurse into Any messages, do that here and skip the rest of the function. 21 170664 : if (recurse_into_any) { 22 0 : std::unique_ptr<Protobuf::Message> inner_message; 23 0 : absl::string_view target_type_url; 24 : 25 0 : if (message.GetTypeName() == "google.protobuf.Any") { 26 0 : auto* any_message = Protobuf::DynamicCastToGenerated<ProtobufWkt::Any>(&message); 27 0 : inner_message = Helper::typeUrlToMessage(any_message->type_url()); 28 0 : target_type_url = any_message->type_url(); 29 : // inner_message must be valid as parsing would have already failed to load if there was an 30 : // invalid type_url. 31 0 : MessageUtil::unpackTo(*any_message, *inner_message); 32 0 : } else if (message.GetTypeName() == "xds.type.v3.TypedStruct") { 33 0 : std::tie(inner_message, target_type_url) = 34 0 : Helper::convertTypedStruct<xds::type::v3::TypedStruct>(message); 35 0 : } else if (message.GetTypeName() == "udpa.type.v1.TypedStruct") { 36 0 : std::tie(inner_message, target_type_url) = 37 0 : Helper::convertTypedStruct<udpa::type::v1::TypedStruct>(message); 38 0 : } 39 : 40 0 : if (inner_message != nullptr) { 41 : // Push the Any message as a wrapper. 42 0 : Helper::ScopedMessageParents scoped_parents(parents, message); 43 0 : traverseMessageWorker(visitor, *inner_message, parents, true, recurse_into_any); 44 0 : return; 45 0 : } else if (!target_type_url.empty()) { 46 0 : throwEnvoyExceptionOrPanic( 47 0 : fmt::format("Invalid type_url '{}' during traversal", target_type_url)); 48 0 : } 49 0 : } 50 170664 : Protobuf::ReflectableMessage reflectable_message = createReflectableMessage(message); 51 170664 : const Protobuf::Descriptor* descriptor = reflectable_message->GetDescriptor(); 52 170664 : const Protobuf::Reflection* reflection = reflectable_message->GetReflection(); 53 1498268 : for (int i = 0; i < descriptor->field_count(); ++i) { 54 1327604 : const Protobuf::FieldDescriptor* field = descriptor->field(i); 55 1327604 : visitor.onField(message, *field); 56 : 57 : // If this is a message, recurse in to the sub-message. 58 1327604 : if (field->cpp_type() == Protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { 59 847850 : Helper::ScopedMessageParents scoped_parents(parents, message); 60 : 61 847850 : if (field->is_repeated()) { 62 176541 : const int size = reflection->FieldSize(*reflectable_message, field); 63 243302 : for (int j = 0; j < size; ++j) { 64 66761 : traverseMessageWorker(visitor, 65 66761 : reflection->GetRepeatedMessage(*reflectable_message, field, j), 66 66761 : parents, false, recurse_into_any); 67 66761 : } 68 671309 : } else if (reflection->HasField(*reflectable_message, field)) { 69 93080 : traverseMessageWorker(visitor, reflection->GetMessage(*reflectable_message, field), parents, 70 93080 : false, recurse_into_any); 71 93080 : } 72 847850 : } 73 1327604 : } 74 170664 : } 75 : 76 : } // namespace 77 : 78 : void traverseMessage(ConstProtoVisitor& visitor, const Protobuf::Message& message, 79 10823 : bool recurse_into_any) { 80 10823 : std::vector<const Protobuf::Message*> parents; 81 10823 : traverseMessageWorker(visitor, message, parents, true, recurse_into_any); 82 10823 : } 83 : 84 : } // namespace ProtobufMessage 85 : } // namespace Envoy