Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/source/common/router/scoped_config_impl.cc
Line
Count
Source (jump to first uncovered line)
1
#include "source/common/router/scoped_config_impl.h"
2
3
#include "envoy/config/route/v3/scoped_route.pb.h"
4
#include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.h"
5
6
#include "source/common/protobuf/utility.h"
7
8
namespace Envoy {
9
namespace Router {
10
11
0
bool ScopeKey::operator!=(const ScopeKey& other) const { return !(*this == other); }
12
13
0
bool ScopeKey::operator==(const ScopeKey& other) const {
14
0
  if (fragments_.empty() || other.fragments_.empty()) {
15
    // An empty key equals to nothing, "NULL" != "NULL".
16
0
    return false;
17
0
  }
18
0
  return this->hash() == other.hash();
19
0
}
20
21
6
void throwProtoValidationExceptionOrPanic(std::string message) {
22
6
  throwExceptionOrPanic(ProtoValidationException, message);
23
6
}
24
25
HeaderValueExtractorImpl::HeaderValueExtractorImpl(
26
    ScopedRoutes::ScopeKeyBuilder::FragmentBuilder&& config)
27
    : FragmentBuilderBase(std::move(config)),
28
132
      header_value_extractor_config_(config_.header_value_extractor()) {
29
132
  ASSERT(config_.type_case() ==
30
132
             ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::kHeaderValueExtractor,
31
132
         "header_value_extractor is not set.");
32
132
  if (header_value_extractor_config_.extract_type_case() ==
33
132
      ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::HeaderValueExtractor::kIndex) {
34
126
    if (header_value_extractor_config_.index() != 0 &&
35
126
        header_value_extractor_config_.element_separator().empty()) {
36
0
      throwProtoValidationExceptionOrPanic("Index > 0 for empty string element separator.");
37
0
    }
38
126
  }
39
132
  if (header_value_extractor_config_.extract_type_case() ==
40
132
      ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::HeaderValueExtractor::EXTRACT_TYPE_NOT_SET) {
41
6
    throwProtoValidationExceptionOrPanic("HeaderValueExtractor extract_type not set.");
42
6
  }
43
132
}
44
45
std::unique_ptr<ScopeKeyFragmentBase>
46
14
HeaderValueExtractorImpl::computeFragment(const Http::HeaderMap& headers) const {
47
14
  const auto header_entry =
48
14
      headers.get(Envoy::Http::LowerCaseString(header_value_extractor_config_.name()));
49
14
  if (header_entry.empty()) {
50
14
    return nullptr;
51
14
  }
52
53
  // This is an implicitly untrusted header, so per the API documentation only the first
54
  // value is used.
55
0
  std::vector<absl::string_view> elements{header_entry[0]->value().getStringView()};
56
0
  if (header_value_extractor_config_.element_separator().length() > 0) {
57
0
    elements = absl::StrSplit(header_entry[0]->value().getStringView(),
58
0
                              header_value_extractor_config_.element_separator());
59
0
  }
60
0
  switch (header_value_extractor_config_.extract_type_case()) {
61
0
  case ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::HeaderValueExtractor::kElement:
62
0
    for (const auto& element : elements) {
63
0
      std::pair<absl::string_view, absl::string_view> key_value = absl::StrSplit(
64
0
          element, absl::MaxSplits(header_value_extractor_config_.element().separator(), 1));
65
0
      if (key_value.first == header_value_extractor_config_.element().key()) {
66
0
        return std::make_unique<StringKeyFragment>(key_value.second);
67
0
      }
68
0
    }
69
0
    break;
70
0
  case ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::HeaderValueExtractor::kIndex:
71
0
    if (header_value_extractor_config_.index() < elements.size()) {
72
0
      return std::make_unique<StringKeyFragment>(elements[header_value_extractor_config_.index()]);
73
0
    }
74
0
    break;
75
0
  case ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::HeaderValueExtractor::EXTRACT_TYPE_NOT_SET:
76
0
    PANIC("not reached");
77
0
  }
78
79
0
  return nullptr;
80
0
}
81
82
ScopedRouteInfo::ScopedRouteInfo(envoy::config::route::v3::ScopedRouteConfiguration config_proto,
83
                                 ConfigConstSharedPtr route_config)
84
    : config_proto_(config_proto), route_config_(route_config),
85
994
      config_hash_(MessageUtil::hash(config_proto)) {
86
  // TODO(stevenzzzz): Maybe worth a KeyBuilder abstraction when there are more than one type of
87
  // Fragment.
88
1.79k
  for (const auto& fragment : config_proto_.key().fragments()) {
89
1.79k
    switch (fragment.type_case()) {
90
1.79k
    case envoy::config::route::v3::ScopedRouteConfiguration::Key::Fragment::TypeCase::kStringKey:
91
1.79k
      scope_key_.addFragment(std::make_unique<StringKeyFragment>(fragment.string_key()));
92
1.79k
      break;
93
0
    case envoy::config::route::v3::ScopedRouteConfiguration::Key::Fragment::TypeCase::TYPE_NOT_SET:
94
0
      PANIC("not implemented");
95
1.79k
    }
96
1.79k
  }
97
994
}
98
99
ScopeKeyBuilderImpl::ScopeKeyBuilderImpl(ScopedRoutes::ScopeKeyBuilder&& config)
100
81
    : ScopeKeyBuilderBase(std::move(config)) {
101
132
  for (const auto& fragment_builder : config_.fragments()) {
102
132
    switch (fragment_builder.type_case()) {
103
132
    case ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::kHeaderValueExtractor:
104
132
      fragment_builders_.emplace_back(std::make_unique<HeaderValueExtractorImpl>(
105
132
          ScopedRoutes::ScopeKeyBuilder::FragmentBuilder(fragment_builder)));
106
132
      break;
107
0
    case ScopedRoutes::ScopeKeyBuilder::FragmentBuilder::TYPE_NOT_SET:
108
0
      PANIC("not implemented");
109
132
    }
110
132
  }
111
81
}
112
113
14
ScopeKeyPtr ScopeKeyBuilderImpl::computeScopeKey(const Http::HeaderMap& headers) const {
114
14
  ScopeKey key;
115
14
  for (const auto& builder : fragment_builders_) {
116
    // returns nullopt if a null fragment is found.
117
14
    std::unique_ptr<ScopeKeyFragmentBase> fragment = builder->computeFragment(headers);
118
14
    if (fragment == nullptr) {
119
14
      return nullptr;
120
14
    }
121
0
    key.addFragment(std::move(fragment));
122
0
  }
123
0
  return std::make_unique<ScopeKey>(std::move(key));
124
14
}
125
126
void ScopedConfigImpl::addOrUpdateRoutingScopes(
127
73
    const std::vector<ScopedRouteInfoConstSharedPtr>& scoped_route_infos) {
128
865
  for (auto& scoped_route_info : scoped_route_infos) {
129
865
    const auto iter = scoped_route_info_by_name_.find(scoped_route_info->scopeName());
130
865
    if (iter != scoped_route_info_by_name_.end()) {
131
121
      ASSERT(scoped_route_info_by_key_.contains(iter->second->scopeKey().hash()));
132
121
      scoped_route_info_by_key_.erase(iter->second->scopeKey().hash());
133
121
    }
134
865
    scoped_route_info_by_name_[scoped_route_info->scopeName()] = scoped_route_info;
135
865
    scoped_route_info_by_key_[scoped_route_info->scopeKey().hash()] = scoped_route_info;
136
865
  }
137
73
}
138
139
0
void ScopedConfigImpl::removeRoutingScopes(const std::vector<std::string>& scope_names) {
140
0
  for (std::string const& scope_name : scope_names) {
141
0
    const auto iter = scoped_route_info_by_name_.find(scope_name);
142
0
    if (iter != scoped_route_info_by_name_.end()) {
143
0
      ASSERT(scoped_route_info_by_key_.contains(iter->second->scopeKey().hash()));
144
0
      scoped_route_info_by_key_.erase(iter->second->scopeKey().hash());
145
0
      scoped_route_info_by_name_.erase(iter);
146
0
    }
147
0
  }
148
0
}
149
150
14
Router::ConfigConstSharedPtr ScopedConfigImpl::getRouteConfig(const ScopeKeyPtr& scope_key) const {
151
14
  if (scope_key == nullptr) {
152
14
    return nullptr;
153
14
  }
154
0
  auto iter = scoped_route_info_by_key_.find(scope_key->hash());
155
0
  if (iter != scoped_route_info_by_key_.end()) {
156
0
    return iter->second->routeConfig();
157
0
  }
158
0
  return nullptr;
159
0
}
160
161
} // namespace Router
162
} // namespace Envoy