Files
moloapp/example/fw/Negotiate.cpp
T
retoor 3c4334cec9 feat: implement MoloApp plans 01-15 with integration
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.
2026-10-23 18:20:04 +02:00

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