Loading client/client.cpp +59 −42 Original line number Diff line number Diff line Loading @@ -80,29 +80,29 @@ void Client::cacheGpoResult(const std::string& key) { } namespace { std::vector<char> safe_post(libhttppp::HttpClient& client, libhttppp::HttpRequest& req, std::vector<char> safe_post(ClientConnection& con, libhttppp::HttpRequest& req, const std::vector<char>& body, size_t maxTries) { for (;;) { try { return client.Post(req, body, maxTries); return con.httpClient().Post(req, body, maxTries); } catch (libhttppp::HTTPException&) { client.reconnect(); return client.Post(req, body, maxTries); if (!con.downgrade()) throw; } catch (netplus::NetException&) { client.reconnect(); return client.Post(req, body, maxTries); if (!con.downgrade()) throw; } } } std::vector<char> safe_get(libhttppp::HttpClient& client, libhttppp::HttpRequest& req, std::vector<char> safe_get(ClientConnection& con, libhttppp::HttpRequest& req, size_t maxTries) { for (;;) { try { return client.Get(req, maxTries); return con.httpClient().Get(req, maxTries); } catch (libhttppp::HTTPException&) { client.reconnect(); return client.Get(req, maxTries); if (!con.downgrade()) throw; } catch (netplus::NetException&) { client.reconnect(); return client.Get(req, maxTries); if (!con.downgrade()) throw; } } } Loading Loading @@ -179,17 +179,19 @@ void ClientConnection::reConnect() { void ClientConnection::setUrl(const libhttppp::HttpUrl& url) { _Url = url; _Vers = 3; std::string path = normalize_path(_Url.getPath()); if (path == "/") path = "/settings/admin/api"; _RequestPath = path; if (_Client) { _Client = std::make_unique<libhttppp::HttpClient>(_Url, 3); _Client = std::make_unique<libhttppp::HttpClient>(_Url, _Vers); _Client->setTimeout(_Timeout); } } void ClientConnection::setUrl(const std::string& url) { _Url = libhttppp::HttpUrl(url.c_str(), true); _Vers = 3; std::string path = _Url.getPath(); if (path.empty() || path == "/") { path = extract_path_from_url(url); Loading @@ -198,7 +200,7 @@ void ClientConnection::setUrl(const std::string& url) { if (path == "/") path = "/settings/admin/api"; _RequestPath = path; if (_Client) { _Client = std::make_unique<libhttppp::HttpClient>(_Url, 3); _Client = std::make_unique<libhttppp::HttpClient>(_Url, _Vers); _Client->setTimeout(_Timeout); } } Loading Loading @@ -228,22 +230,37 @@ void ClientConnection::setMaxTries(int maxtries) { _MaxTries = maxtries; } void ClientConnection::setTimeout(int timeout_sec) { _Timeout = timeout_sec; } libhttppp::HttpClient& ClientConnection::httpClient() { if (!_Client) { _Client = std::make_unique<libhttppp::HttpClient>(_Url, _Vers); _Client->setTimeout(_Timeout); } return *_Client; } bool ClientConnection::downgrade() { if (_Vers == 3) { _Vers = 1; } else if (_Vers != 0) { _Vers = 0; } else { return false; } _Client = std::make_unique<libhttppp::HttpClient>(_Url, _Vers); _Client->setTimeout(_Timeout); return true; } // -------- Client -------- Client::Client(ClientConnection& clt) : _Con(clt) { if (!_Con._Client) { _Con._Client = std::make_unique<libhttppp::HttpClient>(_Con._Url, 3); _Con._Client->setTimeout(_Con._Timeout); } clt.httpClient(); } Client::~Client() = default; inline void ensure_http_client(ClientConnection& con) { if (!con._Client) { con._Client = std::make_unique<libhttppp::HttpClient>(con._Url, 3); con._Client->setTimeout(con._Timeout); } con.httpClient(); } bool Client::ClientAuth() { Loading Loading @@ -272,7 +289,7 @@ bool Client::ClientAuth() { nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading Loading @@ -341,7 +358,7 @@ bool Client::UserAuth() { nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading Loading @@ -412,7 +429,7 @@ void Client::SessionInfo(class SessionData& sdat) { nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading Loading @@ -486,7 +503,7 @@ bool Client::remSession() { nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading Loading @@ -558,7 +575,7 @@ void Client::changeUserPw(const std::string& oldpw, const std::string& newpw) { nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); (void)safe_post(*_Con._Client, nreq, out, _Con._MaxTries); // Optionally: parse response if you care (void)safe_post(_Con, nreq, out, _Con._MaxTries); // Optionally: parse response if you care json_object_put(jresponse); } Loading Loading @@ -589,7 +606,7 @@ void Client::UserInfo(class UserData& udat) { nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading Loading @@ -657,7 +674,7 @@ void Client::getAvatar(const ::uuid::uuid& did, const ::uuid::uuid& uid, resq.setHeaderData("accept")->push_back("image/jpeg"); resq.setRequestURL(url.str().c_str()); std::vector<char> avatar = safe_get(*_Con._Client, resq, _Con._MaxTries); std::vector<char> avatar = safe_get(_Con, resq, _Con._MaxTries); resp.setState(HTTP200); resp.setContentType("image/jpeg"); Loading Loading @@ -695,7 +712,7 @@ bool Client::GPOcheck(class ::uuid::uuid gpoid) { nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading Loading @@ -766,7 +783,7 @@ std::string Client::addConnection(const std::string& clientname, const std::stri nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading Loading @@ -830,7 +847,7 @@ void Client::remConnection(const uuid::uuid& clientid) { nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); (void)safe_post(*_Con._Client, nreq, out, _Con._MaxTries); (void)safe_post(_Con, nreq, out, _Con._MaxTries); json_object_put(jresponse); } Loading Loading @@ -866,7 +883,7 @@ void Client::editConnection(const uuid::uuid& clientid, nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); (void)safe_post(*_Con._Client, nreq, out, _Con._MaxTries); (void)safe_post(_Con, nreq, out, _Con._MaxTries); json_object_put(jresponse); } Loading Loading @@ -909,7 +926,7 @@ std::string Client::GPOadd(const uuid::uuid& gpoid, const std::string& name, con nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading Loading @@ -984,7 +1001,7 @@ bool Client::GPOexits(class uuid::uuid gpoid) { // keeping name for compatibilit nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading Loading @@ -1051,7 +1068,7 @@ std::vector<Client::GroupInfo> Client::listGroups() { nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading client/client.h +12 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,17 @@ namespace authdb { void setSessionID(const uuid::uuid &sid); void reConnect(); // Lazily construct (if needed) and return the underlying HTTP client. libhttppp::HttpClient& httpClient(); // Step the preferred protocol version down (HTTP/3 -> HTTP/2-or-1.1 -> // HTTP/1.1) and rebuild the client at the new version. Returns false // once already at the HTTP/1.1 floor. Called after a request-level // failure on an established connection -- e.g. the HTTP/3 handshake // succeeds but the peer never answers the actual request -- since // that isn't caught by HttpClient's own handshake-only H3 fallback. bool downgrade(); private: libhttppp::HttpUrl _Url; std::string _CltName; Loading @@ -96,6 +107,7 @@ namespace authdb { uuid::uuid _ClientId; int _MaxTries = 3; int _Timeout = 10; int _Vers = 3; friend inline void ensure_http_client(ClientConnection& con); friend std::vector<char> post_with_redirect(ClientConnection& con, libhttppp::HttpRequest& req, Loading Loading
client/client.cpp +59 −42 Original line number Diff line number Diff line Loading @@ -80,29 +80,29 @@ void Client::cacheGpoResult(const std::string& key) { } namespace { std::vector<char> safe_post(libhttppp::HttpClient& client, libhttppp::HttpRequest& req, std::vector<char> safe_post(ClientConnection& con, libhttppp::HttpRequest& req, const std::vector<char>& body, size_t maxTries) { for (;;) { try { return client.Post(req, body, maxTries); return con.httpClient().Post(req, body, maxTries); } catch (libhttppp::HTTPException&) { client.reconnect(); return client.Post(req, body, maxTries); if (!con.downgrade()) throw; } catch (netplus::NetException&) { client.reconnect(); return client.Post(req, body, maxTries); if (!con.downgrade()) throw; } } } std::vector<char> safe_get(libhttppp::HttpClient& client, libhttppp::HttpRequest& req, std::vector<char> safe_get(ClientConnection& con, libhttppp::HttpRequest& req, size_t maxTries) { for (;;) { try { return client.Get(req, maxTries); return con.httpClient().Get(req, maxTries); } catch (libhttppp::HTTPException&) { client.reconnect(); return client.Get(req, maxTries); if (!con.downgrade()) throw; } catch (netplus::NetException&) { client.reconnect(); return client.Get(req, maxTries); if (!con.downgrade()) throw; } } } Loading Loading @@ -179,17 +179,19 @@ void ClientConnection::reConnect() { void ClientConnection::setUrl(const libhttppp::HttpUrl& url) { _Url = url; _Vers = 3; std::string path = normalize_path(_Url.getPath()); if (path == "/") path = "/settings/admin/api"; _RequestPath = path; if (_Client) { _Client = std::make_unique<libhttppp::HttpClient>(_Url, 3); _Client = std::make_unique<libhttppp::HttpClient>(_Url, _Vers); _Client->setTimeout(_Timeout); } } void ClientConnection::setUrl(const std::string& url) { _Url = libhttppp::HttpUrl(url.c_str(), true); _Vers = 3; std::string path = _Url.getPath(); if (path.empty() || path == "/") { path = extract_path_from_url(url); Loading @@ -198,7 +200,7 @@ void ClientConnection::setUrl(const std::string& url) { if (path == "/") path = "/settings/admin/api"; _RequestPath = path; if (_Client) { _Client = std::make_unique<libhttppp::HttpClient>(_Url, 3); _Client = std::make_unique<libhttppp::HttpClient>(_Url, _Vers); _Client->setTimeout(_Timeout); } } Loading Loading @@ -228,22 +230,37 @@ void ClientConnection::setMaxTries(int maxtries) { _MaxTries = maxtries; } void ClientConnection::setTimeout(int timeout_sec) { _Timeout = timeout_sec; } libhttppp::HttpClient& ClientConnection::httpClient() { if (!_Client) { _Client = std::make_unique<libhttppp::HttpClient>(_Url, _Vers); _Client->setTimeout(_Timeout); } return *_Client; } bool ClientConnection::downgrade() { if (_Vers == 3) { _Vers = 1; } else if (_Vers != 0) { _Vers = 0; } else { return false; } _Client = std::make_unique<libhttppp::HttpClient>(_Url, _Vers); _Client->setTimeout(_Timeout); return true; } // -------- Client -------- Client::Client(ClientConnection& clt) : _Con(clt) { if (!_Con._Client) { _Con._Client = std::make_unique<libhttppp::HttpClient>(_Con._Url, 3); _Con._Client->setTimeout(_Con._Timeout); } clt.httpClient(); } Client::~Client() = default; inline void ensure_http_client(ClientConnection& con) { if (!con._Client) { con._Client = std::make_unique<libhttppp::HttpClient>(con._Url, 3); con._Client->setTimeout(con._Timeout); } con.httpClient(); } bool Client::ClientAuth() { Loading Loading @@ -272,7 +289,7 @@ bool Client::ClientAuth() { nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading Loading @@ -341,7 +358,7 @@ bool Client::UserAuth() { nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading Loading @@ -412,7 +429,7 @@ void Client::SessionInfo(class SessionData& sdat) { nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading Loading @@ -486,7 +503,7 @@ bool Client::remSession() { nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading Loading @@ -558,7 +575,7 @@ void Client::changeUserPw(const std::string& oldpw, const std::string& newpw) { nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); (void)safe_post(*_Con._Client, nreq, out, _Con._MaxTries); // Optionally: parse response if you care (void)safe_post(_Con, nreq, out, _Con._MaxTries); // Optionally: parse response if you care json_object_put(jresponse); } Loading Loading @@ -589,7 +606,7 @@ void Client::UserInfo(class UserData& udat) { nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading Loading @@ -657,7 +674,7 @@ void Client::getAvatar(const ::uuid::uuid& did, const ::uuid::uuid& uid, resq.setHeaderData("accept")->push_back("image/jpeg"); resq.setRequestURL(url.str().c_str()); std::vector<char> avatar = safe_get(*_Con._Client, resq, _Con._MaxTries); std::vector<char> avatar = safe_get(_Con, resq, _Con._MaxTries); resp.setState(HTTP200); resp.setContentType("image/jpeg"); Loading Loading @@ -695,7 +712,7 @@ bool Client::GPOcheck(class ::uuid::uuid gpoid) { nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading Loading @@ -766,7 +783,7 @@ std::string Client::addConnection(const std::string& clientname, const std::stri nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading Loading @@ -830,7 +847,7 @@ void Client::remConnection(const uuid::uuid& clientid) { nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); (void)safe_post(*_Con._Client, nreq, out, _Con._MaxTries); (void)safe_post(_Con, nreq, out, _Con._MaxTries); json_object_put(jresponse); } Loading Loading @@ -866,7 +883,7 @@ void Client::editConnection(const uuid::uuid& clientid, nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); (void)safe_post(*_Con._Client, nreq, out, _Con._MaxTries); (void)safe_post(_Con, nreq, out, _Con._MaxTries); json_object_put(jresponse); } Loading Loading @@ -909,7 +926,7 @@ std::string Client::GPOadd(const uuid::uuid& gpoid, const std::string& name, con nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading Loading @@ -984,7 +1001,7 @@ bool Client::GPOexits(class uuid::uuid gpoid) { // keeping name for compatibilit nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading Loading @@ -1051,7 +1068,7 @@ std::vector<Client::GroupInfo> Client::listGroups() { nreq.setHeaderData("accept")->push_back("application/json"); nreq.setHeaderData("content-type")->push_back("application/json"); nreq.setRequestURL(_Con._RequestPath.c_str()); std::vector<char> resp(safe_post(*_Con._Client, nreq, out, _Con._MaxTries)); std::vector<char> resp(safe_post(_Con, nreq, out, _Con._MaxTries)); resp.push_back('\0'); json_object_put(jresponse); Loading
client/client.h +12 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,17 @@ namespace authdb { void setSessionID(const uuid::uuid &sid); void reConnect(); // Lazily construct (if needed) and return the underlying HTTP client. libhttppp::HttpClient& httpClient(); // Step the preferred protocol version down (HTTP/3 -> HTTP/2-or-1.1 -> // HTTP/1.1) and rebuild the client at the new version. Returns false // once already at the HTTP/1.1 floor. Called after a request-level // failure on an established connection -- e.g. the HTTP/3 handshake // succeeds but the peer never answers the actual request -- since // that isn't caught by HttpClient's own handshake-only H3 fallback. bool downgrade(); private: libhttppp::HttpUrl _Url; std::string _CltName; Loading @@ -96,6 +107,7 @@ namespace authdb { uuid::uuid _ClientId; int _MaxTries = 3; int _Timeout = 10; int _Vers = 3; friend inline void ensure_http_client(ClientConnection& con); friend std::vector<char> post_with_redirect(ClientConnection& con, libhttppp::HttpRequest& req, Loading