/proc/self/cwd/source/common/protobuf/visitor.cc
Line | Count | Source (jump to first uncovered line) |
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 | | absl::Status traverseMessageWorker(ConstProtoVisitor& visitor, const Protobuf::Message& message, |
16 | | std::vector<const Protobuf::Message*>& parents, |
17 | 28.2M | bool was_any_or_top_level, bool recurse_into_any) { |
18 | 28.2M | 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 | 28.2M | 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 | RETURN_IF_NOT_OK(MessageUtil::unpackTo(*any_message, *inner_message)); |
32 | 0 | } else if (message.GetTypeName() == "xds.type.v3.TypedStruct") { |
33 | 0 | auto output_or_error = Helper::convertTypedStruct<xds::type::v3::TypedStruct>(message); |
34 | 0 | RETURN_IF_NOT_OK_REF(output_or_error.status()); |
35 | 0 | std::tie(inner_message, target_type_url) = std::move(output_or_error.value()); |
36 | 0 | } else if (message.GetTypeName() == "udpa.type.v1.TypedStruct") { |
37 | 0 | auto output_or_error = Helper::convertTypedStruct<udpa::type::v1::TypedStruct>(message); |
38 | 0 | RETURN_IF_NOT_OK_REF(output_or_error.status()); |
39 | 0 | std::tie(inner_message, target_type_url) = std::move(output_or_error.value()); |
40 | 0 | } |
41 | | |
42 | 0 | if (inner_message != nullptr) { |
43 | | // Push the Any message as a wrapper. |
44 | 0 | Helper::ScopedMessageParents scoped_parents(parents, message); |
45 | 0 | return traverseMessageWorker(visitor, *inner_message, parents, true, recurse_into_any); |
46 | 0 | } else if (!target_type_url.empty()) { |
47 | 0 | return absl::InvalidArgumentError( |
48 | 0 | fmt::format("Invalid type_url '{}' during traversal", target_type_url)); |
49 | 0 | } |
50 | 0 | } |
51 | 28.2M | Protobuf::ReflectableMessage reflectable_message = createReflectableMessage(message); |
52 | 28.2M | const Protobuf::Descriptor* descriptor = reflectable_message->GetDescriptor(); |
53 | 28.2M | const Protobuf::Reflection* reflection = reflectable_message->GetReflection(); |
54 | 161M | for (int i = 0; i < descriptor->field_count(); ++i) { |
55 | 133M | const Protobuf::FieldDescriptor* field = descriptor->field(i); |
56 | 133M | visitor.onField(message, *field); |
57 | | |
58 | | // If this is a message, recurse in to the sub-message. |
59 | 133M | if (field->cpp_type() == Protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { |
60 | 81.0M | Helper::ScopedMessageParents scoped_parents(parents, message); |
61 | | |
62 | 81.0M | if (field->is_repeated()) { |
63 | 7.55M | const int size = reflection->FieldSize(*reflectable_message, field); |
64 | 20.5M | for (int j = 0; j < size; ++j) { |
65 | 13.0M | RETURN_IF_NOT_OK(traverseMessageWorker( |
66 | 13.0M | visitor, reflection->GetRepeatedMessage(*reflectable_message, field, j), parents, |
67 | 13.0M | false, recurse_into_any)); |
68 | 13.0M | } |
69 | 73.5M | } else if (reflection->HasField(*reflectable_message, field)) { |
70 | 14.5M | RETURN_IF_NOT_OK(traverseMessageWorker(visitor, |
71 | 14.5M | reflection->GetMessage(*reflectable_message, field), |
72 | 14.5M | parents, false, recurse_into_any)); |
73 | 14.5M | } |
74 | 81.0M | } |
75 | 133M | } |
76 | 28.2M | return absl::OkStatus(); |
77 | 28.2M | } |
78 | | |
79 | | } // namespace |
80 | | |
81 | | absl::Status traverseMessage(ConstProtoVisitor& visitor, const Protobuf::Message& message, |
82 | 603k | bool recurse_into_any) { |
83 | 603k | std::vector<const Protobuf::Message*> parents; |
84 | 603k | return traverseMessageWorker(visitor, message, parents, true, recurse_into_any); |
85 | 603k | } |
86 | | |
87 | | } // namespace ProtobufMessage |
88 | | } // namespace Envoy |