1
#include "source/common/http/http_server_properties_cache_manager_impl.h"
2

            
3
#include "envoy/common/key_value_store.h"
4
#include "envoy/config/common/key_value/v3/config.pb.h"
5
#include "envoy/config/common/key_value/v3/config.pb.validate.h"
6

            
7
#include "source/common/config/utility.h"
8
#include "source/common/http/http_server_properties_cache_impl.h"
9
#include "source/common/protobuf/protobuf.h"
10

            
11
#include "absl/container/flat_hash_map.h"
12

            
13
namespace Envoy {
14
namespace Http {
15

            
16
HttpServerPropertiesCacheManagerImpl::HttpServerPropertiesCacheManagerImpl(
17
    Server::Configuration::ServerFactoryContext& context,
18
    ProtobufMessage::ValidationVisitor& validation_visitor, ThreadLocal::SlotAllocator& tls)
19
10723
    : data_(context, validation_visitor), slot_(tls) {
20
21359
  slot_.set([](Event::Dispatcher& /*dispatcher*/) { return std::make_shared<State>(); });
21
10723
}
22

            
23
HttpServerPropertiesCacheSharedPtr HttpServerPropertiesCacheManagerImpl::getCache(
24
    const envoy::config::core::v3::AlternateProtocolsCacheOptions& options,
25
6022
    Event::Dispatcher& dispatcher) {
26
6022
  const auto& existing_cache = (*slot_).caches_.find(options.name());
27
6022
  if (existing_cache != (*slot_).caches_.end()) {
28
755
    if (!Protobuf::util::MessageDifferencer::Equivalent(options, existing_cache->second.options_)) {
29
1
      IS_ENVOY_BUG(fmt::format(
30
1
          "options specified alternate protocols cache '{}' with different settings"
31
1
          " first '{}' second '{}'",
32
1
          options.name(), existing_cache->second.options_.DebugString(), options.DebugString()));
33
1
    }
34
755
    return existing_cache->second.cache_;
35
755
  }
36

            
37
5267
  std::unique_ptr<KeyValueStore> store;
38
5267
  if (options.has_key_value_store_config()) {
39
29
    envoy::config::common::key_value::v3::KeyValueStoreConfig kv_config;
40
29
    MessageUtil::anyConvertAndValidate(options.key_value_store_config().typed_config(), kv_config,
41
29
                                       data_.validation_visitor_);
42
29
    auto& factory = Config::Utility::getAndCheckFactory<KeyValueStoreFactory>(kv_config.config());
43
29
    store =
44
29
        factory.createStore(kv_config, data_.validation_visitor_, dispatcher, data_.file_system_);
45
29
  }
46

            
47
5267
  std::vector<std::string> canonical_suffixes;
48
5267
  for (const std::string& suffix : options.canonical_suffixes()) {
49
4
    if (!absl::StartsWith(suffix, ".")) {
50
1
      IS_ENVOY_BUG(absl::StrCat("Suffix does not start with a leading '.': ", suffix));
51
1
      continue;
52
1
    }
53
3
    canonical_suffixes.push_back(suffix);
54
3
  }
55

            
56
5267
  auto new_cache = std::make_shared<HttpServerPropertiesCacheImpl>(
57
5267
      dispatcher, std::move(canonical_suffixes), std::move(store), options.max_entries().value());
58

            
59
5267
  for (const envoy::config::core::v3::AlternateProtocolsCacheOptions::AlternateProtocolsCacheEntry&
60
5267
           entry : options.prepopulated_entries()) {
61
4
    const HttpServerPropertiesCacheImpl::Origin origin = {"https", entry.hostname(), entry.port()};
62
4
    std::vector<HttpServerPropertiesCacheImpl::AlternateProtocol> protocol = {
63
4
        {"h3", "", entry.port(),
64
4
         dispatcher.timeSource().monotonicTime() + std::chrono::hours(168)}};
65
4
    OptRef<const std::vector<HttpServerPropertiesCacheImpl::AlternateProtocol>> existing_protocols =
66
4
        new_cache->findAlternatives(origin);
67
4
    if (!existing_protocols.has_value()) {
68
4
      new_cache->setAlternatives(origin, protocol);
69
4
    }
70
4
  }
71

            
72
5267
  (*slot_).caches_.emplace(options.name(), CacheWithOptions{options, new_cache});
73
5267
  return new_cache;
74
6022
}
75

            
76
1
void HttpServerPropertiesCacheManagerImpl::forEachThreadLocalCache(CacheFn cache_fn) {
77
2
  for (auto& entry : (*slot_).caches_) {
78
2
    HttpServerPropertiesCache& cache = *entry.second.cache_;
79
2
    cache_fn(cache);
80
2
  }
81
1
}
82

            
83
} // namespace Http
84
} // namespace Envoy