1
#pragma once
2

            
3
#include <map>
4
#include <memory>
5
#include <string>
6
#include <tuple>
7
#include <vector>
8

            
9
#include "envoy/common/key_value_store.h"
10
#include "envoy/common/optref.h"
11
#include "envoy/common/time.h"
12
#include "envoy/http/http_server_properties_cache.h"
13

            
14
#include "source/common/common/logger.h"
15
#include "source/common/http/http3_status_tracker_impl.h"
16

            
17
#include "absl/container/linked_hash_map.h"
18
#include "absl/strings/string_view.h"
19

            
20
namespace Envoy {
21
namespace Http {
22

            
23
// A cache of HTTP server properties.
24
// This caches
25
//   - Alternate protocol entries as documented here: source/docs/http3_upstream.md.
26
//   - QUIC round trip time used for TCP failover.
27
//   - The last connectivity status of HTTP/3, if available.
28
//   - Expected concurrent streams allowed.
29
class HttpServerPropertiesCacheImpl : public HttpServerPropertiesCache,
30
                                      Logger::Loggable<Logger::Id::alternate_protocols_cache> {
31
public:
32
  HttpServerPropertiesCacheImpl(Event::Dispatcher& dispatcher,
33
                                std::vector<std::string>&& canonical_suffixes,
34
                                std::unique_ptr<KeyValueStore>&& store, size_t max_entries);
35
  ~HttpServerPropertiesCacheImpl() override;
36

            
37
  // Captures the data tracked per origin;,
38
  struct OriginData {
39
284
    OriginData() = default;
40
    OriginData(OptRef<std::vector<AlternateProtocol>> protocols, std::chrono::microseconds srtt,
41
               Http3StatusTrackerPtr&& tracker, uint32_t concurrent_streams)
42
250
        : protocols(protocols.copy()), srtt(srtt), h3_status_tracker(std::move(tracker)),
43
250
          concurrent_streams(concurrent_streams) {}
44

            
45
    // The alternate protocols supported if available.
46
    absl::optional<std::vector<AlternateProtocol>> protocols;
47
    // The last smoothed round trip time, if available else 0.
48
    std::chrono::microseconds srtt;
49
    // The last connectivity status of HTTP/3, if available else nullptr.
50
    Http3StatusTrackerPtr h3_status_tracker;
51
    // The number of concurrent streams expected to be allowed.
52
    uint32_t concurrent_streams;
53
  };
54

            
55
  // Converts an Origin to a string which can be parsed by stringToOrigin.
56
  static std::string originToString(const HttpServerPropertiesCache::Origin& origin);
57
  // Converts a string from originToString back to structured format.
58
  static absl::optional<HttpServerPropertiesCache::Origin> stringToOrigin(const std::string& str);
59

            
60
  // Convert origin data to a string to cache to the key value
61
  // store. Note that in order to determine the lifetime of entries, this
62
  // function will serialize ma= as absolute time from the epoch rather than
63
  // relative time.
64
  // This function also does not do standards-required normalization. Entries requiring
65
  // normalization will simply not be read from cache.
66
  // The string format is:
67
  // protocols|rtt
68
  static std::string originDataToStringForCache(const OriginData& data);
69
  // Parse an origin data into structured data, or absl::nullopt
70
  // if it is empty or invalid.
71
  // If from_cache is true, it is assumed the string was serialized using
72
  // protocolsToStringForCache and the the ma fields will be parsed as absolute times
73
  // rather than relative time.
74
  static absl::optional<OriginData> originDataFromString(absl::string_view origin_data,
75
                                                         TimeSource& time_source, bool from_cache);
76
  // Parse an alt-svc string into a vector of structured data.
77
  // If from_cache is true, it is assumed the string was serialized using
78
  // protocolsToStringForCache and the the ma fields will be parsed as absolute times
79
  // rather than relative time.
80
  static std::vector<Http::HttpServerPropertiesCache::AlternateProtocol>
81
  alternateProtocolsFromString(absl::string_view altsvc_str, TimeSource& time_source,
82
                               bool from_cache);
83

            
84
  // HttpServerPropertiesCache
85
  void setAlternatives(const Origin& origin, std::vector<AlternateProtocol>& protocols) override;
86
  void setSrtt(const Origin& origin, std::chrono::microseconds srtt) override;
87
  std::chrono::microseconds getSrtt(const Origin& origin, bool use_canonical_suffix) const override;
88
  void setConcurrentStreams(const Origin& origin, uint32_t concurrent_streams) override;
89
  uint32_t getConcurrentStreams(const Origin& origin) const override;
90
  OptRef<const std::vector<AlternateProtocol>> findAlternatives(const Origin& origin) override;
91
  size_t size() const override;
92
  HttpServerPropertiesCache::Http3StatusTracker&
93
  getOrCreateHttp3StatusTracker(const Origin& origin) override;
94
  void markHttp3Broken(const Origin& origin) override;
95
  bool isHttp3Broken(const Origin& origin) override;
96
  void resetBrokenness() override;
97
  void resetStatus() override;
98

            
99
private:
100
  // Time source used to check expiration of entries.
101
  Event::Dispatcher& dispatcher_;
102

            
103
  struct OriginHash {
104
126
    size_t operator()(const Origin& origin) const {
105
      // Multiply the hashes by the magic number 37 to spread the bits around.
106
126
      size_t hash = std::hash<std::string>()(origin.scheme_) +
107
126
                    37 * (std::hash<std::string>()(origin.hostname_) +
108
126
                          37 * std::hash<uint32_t>()(origin.port_));
109
126
      return hash;
110
126
    }
111
  };
112

            
113
  using ProtocolsMap = absl::linked_hash_map<Origin, OriginData, OriginHash>;
114
  // Map from origin to list of alternate protocols.
115
  ProtocolsMap protocols_;
116

            
117
  // This allows calling setPropertiesImpl without creating an additional copy
118
  // of the protocols vector.
119
  struct OriginDataWithOptRef {
120
282
    OriginDataWithOptRef() : srtt(std::chrono::milliseconds(0)) {}
121
    OriginDataWithOptRef(OptRef<std::vector<AlternateProtocol>> protocols,
122
                         std::chrono::microseconds srtt, Http3StatusTrackerPtr&& h3_status_tracker,
123
                         uint32_t concurrent_streams)
124
17
        : protocols(protocols), srtt(srtt), h3_status_tracker(std::move(h3_status_tracker)),
125
17
          concurrent_streams(concurrent_streams) {}
126
    // The alternate protocols supported if available.
127
    OptRef<std::vector<AlternateProtocol>> protocols;
128
    // The last smoothed round trip time, if available else 0.
129
    std::chrono::microseconds srtt;
130
    // The last connectivity status of HTTP/3, if available else nullptr.
131
    Http3StatusTrackerPtr h3_status_tracker;
132
    // The number of concurrent streams expected to be allowed.
133
    uint32_t concurrent_streams{0};
134
  };
135

            
136
  ProtocolsMap::iterator setPropertiesImpl(const Origin& origin, OriginDataWithOptRef& origin_data);
137

            
138
  ProtocolsMap::iterator addOriginData(const Origin& origin, OriginData&& origin_data);
139

            
140
  // Returns the canonical suffix, if any, associated with `hostname`.
141
  absl::string_view getCanonicalSuffix(absl::string_view hostname) const;
142

            
143
  // Returns the canonical origin from the canonical_h3_broken_map, if any, associated with
144
  // `hostname`.
145
  absl::optional<Origin> getCanonicalOriginForHttp3Brokenness(absl::string_view hostname);
146

            
147
  // Updates the canonical origin for http3 brokenness book keeping.
148
  void maybeSetCanonicalOriginForHttp3Brokenness(const Origin& origin);
149

            
150
  // Returns the canonical origin, if any, associated with `hostname`.
151
  absl::optional<Origin> getCanonicalOrigin(absl::string_view hostname) const;
152

            
153
  // If `origin` matches a canonical suffix then updates canonical_alt_svc_map_ accordingly.
154
  void maybeSetCanonicalOrigin(const Origin& origin);
155

            
156
  // The key value store, if flushing to persistent storage.
157
  std::unique_ptr<KeyValueStore> key_value_store_;
158

            
159
  // Contains a map of servers which could share the same alternate protocol.
160
  // Map from a Canonical suffix to an actual origin, which has a plausible alternate
161
  // protocol mapping.
162
  absl::flat_hash_map<std::string, Origin> canonical_alt_svc_map_;
163

            
164
  // Contains a map of origins whose http3 status are known.
165
  // Map from a canonical suffix to an actual origin that can provide http3 brokenness info.
166
  absl::flat_hash_map<std::string, Origin> canonical_h3_brokenness_map_;
167

            
168
  // Contains list of suffixes (for example ".c.youtube.com",
169
  // ".googlevideo.com", ".googleusercontent.com") of canonical hostnames.
170
  std::vector<std::string> canonical_suffixes_;
171

            
172
  const size_t max_entries_;
173
};
174

            
175
} // namespace Http
176
} // namespace Envoy