1
#pragma once
2

            
3
#include <memory>
4

            
5
#include "envoy/config/config_provider.h"
6
#include "envoy/router/router.h"
7

            
8
namespace Envoy {
9
namespace Router {
10

            
11
/**
12
 * Scope key fragment base class.
13
 */
14
class ScopeKeyFragmentBase {
15
public:
16
4
  bool operator!=(const ScopeKeyFragmentBase& other) const { return !(*this == other); }
17

            
18
14
  bool operator==(const ScopeKeyFragmentBase& other) const {
19
14
    if (typeid(*this) == typeid(other)) {
20
13
      return hash() == other.hash();
21
13
    }
22
1
    return false;
23
14
  }
24
1211
  virtual ~ScopeKeyFragmentBase() = default;
25

            
26
  // Hash of the fragment.
27
  virtual uint64_t hash() const PURE;
28
};
29

            
30
/**
31
 *  Scope Key is composed of non-null fragments.
32
 **/
33
class ScopeKey {
34
public:
35
1061
  ScopeKey() = default;
36
519
  ScopeKey(ScopeKey&& other) = default;
37

            
38
  // Scopekey is not copy-assignable and copy-constructible as it contains unique_ptr inside itself.
39
  ScopeKey(const ScopeKey&) = delete;
40
  ScopeKey operator=(const ScopeKey&) = delete;
41

            
42
  // Caller should guarantee the fragment is not nullptr.
43
1088
  void addFragment(std::unique_ptr<ScopeKeyFragmentBase>&& fragment) {
44
1088
    ASSERT(fragment != nullptr, "null fragment not allowed in ScopeKey.");
45
1088
    updateHash(*fragment);
46
1088
    fragments_.emplace_back(std::move(fragment));
47
1088
  }
48

            
49
1736
  uint64_t hash() const { return hash_; }
50
  bool operator!=(const ScopeKey& other) const;
51
  bool operator==(const ScopeKey& other) const;
52

            
53
private:
54
  // Update the key's hash with the new fragment hash.
55
1088
  void updateHash(const ScopeKeyFragmentBase& fragment) {
56
1088
    std::stringbuf buffer;
57
1088
    buffer.sputn(reinterpret_cast<const char*>(&hash_), sizeof(hash_));
58
1088
    const auto& fragment_hash = fragment.hash();
59
1088
    buffer.sputn(reinterpret_cast<const char*>(&fragment_hash), sizeof(fragment_hash));
60
1088
    hash_ = HashUtil::xxHash64(buffer.str());
61
1088
  }
62

            
63
  uint64_t hash_{0};
64
  std::vector<std::unique_ptr<ScopeKeyFragmentBase>> fragments_;
65
};
66

            
67
using ScopeKeyPtr = std::unique_ptr<ScopeKey>;
68

            
69
// String fragment.
70
class StringKeyFragment : public ScopeKeyFragmentBase {
71
public:
72
  explicit StringKeyFragment(absl::string_view value)
73
1211
      : value_(value), hash_(HashUtil::xxHash64(value_)) {}
74

            
75
1317
  uint64_t hash() const override { return hash_; }
76

            
77
private:
78
  const std::string value_;
79
  const uint64_t hash_;
80
};
81

            
82
/**
83
 * The scoped key builder.
84
 */
85
class ScopeKeyBuilder {
86
public:
87
11093
  virtual ~ScopeKeyBuilder() = default;
88

            
89
  /**
90
   * Based on the incoming HTTP request headers, returns the hash value of its scope key.
91
   * @param headers the request headers to match the scoped routing configuration against.
92
   * @return unique_ptr of the scope key computed from header.
93
   */
94
  virtual ScopeKeyPtr computeScopeKey(const Http::HeaderMap&) const PURE;
95
};
96

            
97
/**
98
 * The scoped routing configuration.
99
 */
100
class ScopedConfig : public Envoy::Config::ConfigProvider::Config {
101
public:
102
11166
  ~ScopedConfig() override = default;
103

            
104
  /**
105
   * Based on the scope key, returns the configuration to use for selecting a target route.
106
   * The scope key can be got via ScopeKeyBuilder.
107
   *
108
   * @param scope_key the scope key. null config will be returned when null.
109
   * @return ConfigConstSharedPtr the router's Config matching the request headers.
110
   */
111
  virtual ConfigConstSharedPtr getRouteConfig(const ScopeKeyPtr& scope_key) const PURE;
112
};
113

            
114
using ScopedConfigConstSharedPtr = std::shared_ptr<const ScopedConfig>;
115
using ScopeKeyBuilderPtr = std::unique_ptr<const ScopeKeyBuilder>;
116

            
117
} // namespace Router
118
} // namespace Envoy