Line data Source code
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/strings/string_view.h" 18 : #include "quiche/common/quiche_linked_hash_map.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 0 : OriginData() = default; 40 : OriginData(OptRef<std::vector<AlternateProtocol>> protocols, std::chrono::microseconds srtt, 41 : Http3StatusTrackerPtr&& tracker, uint32_t concurrent_streams) 42 : : protocols(protocols.copy()), srtt(srtt), h3_status_tracker(std::move(tracker)), 43 0 : 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) 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 : 95 : private: 96 : // Time source used to check expiration of entries. 97 : Event::Dispatcher& dispatcher_; 98 : 99 : struct OriginHash { 100 0 : size_t operator()(const Origin& origin) const { 101 : // Multiply the hashes by the magic number 37 to spread the bits around. 102 0 : size_t hash = std::hash<std::string>()(origin.scheme_) + 103 0 : 37 * (std::hash<std::string>()(origin.hostname_) + 104 0 : 37 * std::hash<uint32_t>()(origin.port_)); 105 0 : return hash; 106 0 : } 107 : }; 108 : 109 : using ProtocolsMap = quiche::QuicheLinkedHashMap<Origin, OriginData, OriginHash>; 110 : // Map from origin to list of alternate protocols. 111 : ProtocolsMap protocols_; 112 : 113 : // This allows calling setPropertiesImpl without creating an additional copy 114 : // of the protocols vector. 115 : struct OriginDataWithOptRef { 116 0 : OriginDataWithOptRef() : srtt(std::chrono::milliseconds(0)) {} 117 : OriginDataWithOptRef(OptRef<std::vector<AlternateProtocol>> protocols, 118 : std::chrono::microseconds srtt, Http3StatusTrackerPtr&& h3_status_tracker, 119 : uint32_t concurrent_streams) 120 : : protocols(protocols), srtt(srtt), h3_status_tracker(std::move(h3_status_tracker)), 121 0 : concurrent_streams(concurrent_streams) {} 122 : // The alternate protocols supported if available. 123 : OptRef<std::vector<AlternateProtocol>> protocols; 124 : // The last smoothed round trip time, if available else 0. 125 : std::chrono::microseconds srtt; 126 : // The last connectivity status of HTTP/3, if available else nullptr. 127 : Http3StatusTrackerPtr h3_status_tracker; 128 : // The number of concurrent streams expected to be allowed. 129 : uint32_t concurrent_streams{0}; 130 : }; 131 : 132 : ProtocolsMap::iterator setPropertiesImpl(const Origin& origin, OriginDataWithOptRef& origin_data); 133 : 134 : ProtocolsMap::iterator addOriginData(const Origin& origin, OriginData&& origin_data); 135 : 136 : // Returns the canonical suffix, if any, associated with `hostname`. 137 : absl::string_view getCanonicalSuffix(absl::string_view hostname); 138 : 139 : // Returns the canonical origin, if any, associated with `hostname`. 140 : absl::optional<Origin> getCanonicalOrigin(absl::string_view hostname); 141 : 142 : // If `origin` matches a canonical suffix then updates canonical_alt_svc_map_ accordingly. 143 : void maybeSetCanonicalOrigin(const Origin& origin); 144 : 145 : // The key value store, if flushing to persistent storage. 146 : std::unique_ptr<KeyValueStore> key_value_store_; 147 : 148 : // Contains a map of servers which could share the same alternate protocol. 149 : // Map from a Canonical suffix to an actual origin, which has a plausible alternate 150 : // protocol mapping. 151 : std::map<std::string, Origin> canonical_alt_svc_map_; 152 : 153 : // Contains list of suffixes (for example ".c.youtube.com", 154 : // ".googlevideo.com", ".googleusercontent.com") of canonical hostnames. 155 : std::vector<std::string> canonical_suffixes_; 156 : 157 : const size_t max_entries_; 158 : }; 159 : 160 : } // namespace Http 161 : } // namespace Envoy