Full C++23 framework tree: runtime, observability, security, data, app, realtime, supervisor, clients, CLI, example plus enterprise tenancy, audit, operability, governance, supplychain. Postgres via docker compose for tests.
71 lines
1.9 KiB
C++
71 lines
1.9 KiB
C++
#include "Negotiate.hpp"
|
|
|
|
#include <cctype>
|
|
|
|
namespace molo::example::fw {
|
|
|
|
namespace {
|
|
|
|
std::string trim(std::string s) {
|
|
while (!s.empty() && (s.front() == ' ' || s.front() == '\t')) s.erase(s.begin());
|
|
while (!s.empty() && (s.back() == ' ' || s.back() == '\t')) s.pop_back();
|
|
return s;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
std::string negotiate(const std::string& accept,
|
|
const std::vector<std::string>& available) {
|
|
if (available.empty()) throw HttpError(500, "no_offers", "no offers");
|
|
if (accept.empty()) return available.front();
|
|
struct Range {
|
|
std::string type;
|
|
double q = 1.0;
|
|
};
|
|
std::vector<Range> ranges;
|
|
std::size_t start = 0;
|
|
while (start < accept.size()) {
|
|
std::size_t comma = accept.find(',', start);
|
|
if (comma == std::string::npos) comma = accept.size();
|
|
std::string part = trim(accept.substr(start, comma - start));
|
|
std::size_t semi = part.find(';');
|
|
Range r{trim(part.substr(0, semi)), 1.0};
|
|
if (semi != std::string::npos) {
|
|
std::string params = part.substr(semi + 1);
|
|
std::size_t q = params.find("q=");
|
|
if (q != std::string::npos) {
|
|
try {
|
|
r.q = std::stod(params.substr(q + 2));
|
|
} catch (...) {
|
|
r.q = 1.0;
|
|
}
|
|
}
|
|
}
|
|
ranges.push_back(r);
|
|
start = comma + 1;
|
|
}
|
|
std::string best;
|
|
double best_q = -1.0;
|
|
for (const auto& a : available) {
|
|
for (const auto& r : ranges) {
|
|
bool hit = r.type == "*/*" || r.type == a;
|
|
if (!hit) {
|
|
std::size_t slash = a.find('/');
|
|
std::string wild = slash == std::string::npos
|
|
? "*/*"
|
|
: a.substr(0, slash) + "/*";
|
|
hit = r.type == wild;
|
|
}
|
|
if (hit && r.q > best_q) {
|
|
best_q = r.q;
|
|
best = a;
|
|
}
|
|
}
|
|
}
|
|
if (best.empty() || best_q <= 0.0)
|
|
throw HttpError(406, "not_acceptable", "no acceptable format");
|
|
return best;
|
|
}
|
|
|
|
} // namespace molo::example::fw
|