Haio 0.2.X
Homebrew Asset IO/CDN
Loading...
Searching...
No Matches
quota.cpp
Go to the documentation of this file.
1#include <cache/cache.hpp>
2
3#include <algorithm>
4
5namespace Haio::Cdn::Detail {
6
7ClientQuota::ClientQuota(size_t perWindow, std::chrono::seconds window)
8 : perWindow_(perWindow), window_(window) {}
9
10/**
11 * the quota counts entries created, not requests served, and it refills every window.
12 * going over does not fail anything: the answer is produced and returned, it is only
13 * not stored, so an address that asks for ten thousand different sizes pays for them
14 * itself instead of evicting everybody else.
15 */
16bool ClientQuota::mayStore(const std::string& client) {
17 if (perWindow_ == 0 || client.empty()) return true;
18
19 const auto now = std::chrono::steady_clock::now();
20
21 /**
22 * the table is keyed by address, so a caller with many addresses grows it. expired
23 * rows are dropped on the way past, and if it still runs away the whole table is
24 * cleared: everyone gets a fresh quota, which is far better than an allocation
25 * nobody bounds.
26 *
27 * @todo a fixed size counting sketch would hold the limit without the table, and
28 * without handing an attacker a reset by flooding it.
29 */
30 if (seen_.size() > clientsBeforePrune) {
31 std::erase_if(seen_, [now](const auto& row) { return now >= row.second.resets; });
32 if (seen_.size() > clientsBeforePrune) seen_.clear();
33 }
34
35 auto& window = seen_[client];
36 if (now >= window.resets) {
37 window.created = 0;
38 window.resets = now + window_;
39 }
40 if (window.created >= perWindow_) return false;
41
42 window.created++;
43 return true;
44}
45
46}
bool mayStore(const std::string &client)
Definition quota.cpp:16
ClientQuota(size_t perWindow, std::chrono::seconds window)
Definition quota.cpp:7