Coverage Report

Created: 2024-09-19 09:45

/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