54 return static_cast<unsigned>(m_verbs) &
static_cast<unsigned>(verb);
72 void Put(
const std::string &url,
const HttpVerbs &verbs,
const std::chrono::steady_clock::time_point &now=std::chrono::steady_clock::now())
const {
73 std::string modified_url;
76 const std::unique_lock sentry(m_mutex);
79 auto lifetime = isKnown ? g_expiry_duration : g_negative_expiry_duration;
82#if __cplusplus >= 202002L
83 auto iter = m_verbs_map.find(key);
85 auto iter = m_verbs_map.find(std::string(key));
87 if (iter == m_verbs_map.end()) {
88 m_verbs_map.emplace(key, VerbEntry{now + lifetime, verbs});
91 iter->second = {now + lifetime, verbs};
95 HttpVerbs Get(
const std::string &url,
const std::chrono::steady_clock::time_point &now=std::chrono::steady_clock::now())
const {
96 std::string modified_url;
99 const std::shared_lock sentry(m_mutex);
100#if __cplusplus >= 202002L
101 auto iter = m_verbs_map.find(key);
103 auto iter = m_verbs_map.find(std::string(key));
105 if (iter == m_verbs_map.end()) {
109 if (iter->second.m_expiry < now) {
114 return iter->second.m_verbs;
120 static std::string_view
GetUrlKey(
const std::string &url, std::string &modified_url) {
121 auto authority_loc = url.find(
"://");
122 if (authority_loc == std::string::npos) {
123 return std::string_view();
125 auto path_loc = url.find(
'/', authority_loc + 3);
126 if (path_loc == std::string::npos) {
127 path_loc = url.length();
130 std::string_view url_view{url};
131 auto host_loc = url_view.substr(authority_loc + 3, path_loc - authority_loc - 3).find(
'@');
132 if (host_loc == std::string::npos) {
133 return url_view.substr(0, path_loc);
135 host_loc += authority_loc + 3;
136 modified_url = url.substr(0, authority_loc + 3) + std::string(url_view.substr(host_loc + 1, path_loc - host_loc - 1));
144 void Expire(std::chrono::steady_clock::time_point now);
155 static void ExpireThread();
159 static void Shutdown();
161 mutable std::atomic<uint64_t> m_cache_hit{0};
162 mutable std::atomic<uint64_t> m_cache_miss{0};
164 template<
typename ... Bases>
165 struct overload : Bases ...
167 using is_transparent = void;
168 using Bases::operator() ... ;
170 using transparent_string_hash = overload<
171 std::hash<std::string>,
172 std::hash<std::string_view>
176 std::chrono::steady_clock::time_point m_expiry;
180 mutable std::shared_mutex m_mutex;
181 mutable std::unordered_map<std::string, VerbEntry, VerbsCache::transparent_string_hash, std::equal_to<>> m_verbs_map;
183 static std::once_flag m_expiry_launch;
184 static VerbsCache g_cache;
185 static constexpr std::chrono::steady_clock::duration g_expiry_duration = std::chrono::hours(6);
186 static constexpr std::chrono::steady_clock::duration g_negative_expiry_duration = std::chrono::minutes(15);
189 static std::mutex m_shutdown_lock;
191 static std::condition_variable m_shutdown_requested_cv;
193 static bool m_shutdown_requested;
195 static std::thread m_expire_tid;
197 static struct shutdown_s {
198 ~shutdown_s() { Shutdown(); }