@@ -1300,16 +1300,21 @@ void CcdbApi::deleteObject(std::string const& path, long timestamp) const
13001300{
13011301 CURL * curl;
13021302 CURLcode res;
1303- stringstream fullUrl;
13041303 long timestampLocal = timestamp == -1 ? getCurrentTimestamp () : timestamp;
13051304
13061305 curl = curl_easy_init ();
13071306 if (curl != nullptr ) {
13081307 curl_easy_setopt (curl, CURLOPT_CUSTOMREQUEST , " DELETE" );
13091308 curl_easy_setopt (curl, CURLOPT_USERAGENT , mUniqueAgentID .c_str ());
1309+ // A DELETE is a write, so it needs the gate token as storing does.
1310+ struct curl_slist * list = appendGateToken (nullptr );
1311+ curl_easy_setopt (curl, CURLOPT_HTTPHEADER , list);
13101312 curlSetSSLOptions (curl);
13111313
13121314 for (size_t hostIndex = 0 ; hostIndex < hostsPool.size (); hostIndex++) {
1315+ // Inside the loop: hoisted out, the stream accumulates and the second
1316+ // host's URL is the first with the second appended.
1317+ stringstream fullUrl;
13131318 fullUrl << getHostUrl (hostIndex) << " /" << path << " /" << timestampLocal;
13141319 curl_easy_setopt (curl, CURLOPT_URL , fullUrl.str ().c_str ());
13151320
@@ -1318,17 +1323,23 @@ void CcdbApi::deleteObject(std::string const& path, long timestamp) const
13181323 if (res != CURLE_OK ) {
13191324 LOGP (alarm, " CURL_perform() failed: {}" , curl_easy_strerror (res));
13201325 }
1321- curl_easy_cleanup (curl);
13221326 }
1327+ // After the loop, not inside it: cleaning up per host left every later
1328+ // iteration using a freed handle.
1329+ curl_easy_cleanup (curl);
1330+ curl_slist_free_all (list);
13231331 }
13241332}
13251333
13261334void CcdbApi::truncate (std::string const & path) const
13271335{
13281336 CURL * curl;
13291337 CURLcode res;
1330- stringstream fullUrl;
13311338 for (size_t i = 0 ; i < hostsPool.size (); i++) {
1339+ // Declared inside the loop: a stringstream hoisted out of it accumulates,
1340+ // so the second host's URL would be the first one with the second appended
1341+ // to it. Latent until now -- every caller used a single-host pool.
1342+ stringstream fullUrl;
13321343 std::string url = getHostUrl (i);
13331344 fullUrl << url << " /truncate/" << path;
13341345
@@ -1337,6 +1348,13 @@ void CcdbApi::truncate(std::string const& path) const
13371348 if (curl != nullptr ) {
13381349 curl_easy_setopt (curl, CURLOPT_URL , fullUrl.str ().c_str ());
13391350
1351+ // Truncating is a write, so it needs the gate token exactly as storing
1352+ // does. This was the one write path left without it, which a broker
1353+ // answers 401 -- failing every CCDB suite in their teardown, since each
1354+ // one truncates the path it just wrote.
1355+ struct curl_slist * list = appendGateToken (nullptr );
1356+ curl_easy_setopt (curl, CURLOPT_HTTPHEADER , list);
1357+
13401358 curlSetSSLOptions (curl);
13411359
13421360 // Perform the request, res will get the return code
@@ -1345,6 +1363,7 @@ void CcdbApi::truncate(std::string const& path) const
13451363 LOGP (alarm, " CURL_perform() failed: {}" , curl_easy_strerror (res));
13461364 }
13471365 curl_easy_cleanup (curl);
1366+ curl_slist_free_all (list);
13481367 }
13491368 }
13501369}
@@ -1363,8 +1382,15 @@ bool CcdbApi::isHostReachable() const
13631382 curl = curl_easy_init ();
13641383 curl_easy_setopt (curl, CURLOPT_USERAGENT , mUniqueAgentID .c_str ());
13651384 if (curl) {
1385+ // Each host in turn, not mUrl: mUrl holds whatever was passed to init(),
1386+ // which for a failover setup is the whole comma-separated list. curl
1387+ // rejects that as malformed (CURLE_URL_MALFORMAT), so every multi-host
1388+ // instance reported itself unreachable no matter how healthy its hosts
1389+ // were -- and testCcdbApiMultipleUrls, whose cases are gated on this,
1390+ // silently skipped instead of running.
13661391 for (size_t hostIndex = 0 ; hostIndex < hostsPool.size () && res != CURLE_OK ; hostIndex++) {
1367- curl_easy_setopt (curl, CURLOPT_URL , mUrl .data ());
1392+ std::string url = getHostUrl (hostIndex);
1393+ curl_easy_setopt (curl, CURLOPT_URL , url.c_str ());
13681394 curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION , write_data);
13691395 curlSetSSLOptions (curl);
13701396 res = CURL_perform (curl);
@@ -1661,8 +1687,12 @@ int CcdbApi::updateMetadata(std::string const& path, std::map<std::string, std::
16611687 curl_easy_setopt (curl, CURLOPT_USERAGENT , mUniqueAgentID .c_str ());
16621688 if (curl != nullptr ) {
16631689 CURLcode res;
1664- stringstream fullUrl;
1690+ // A PUT is a write, so it needs the gate token as storing does.
1691+ struct curl_slist * list = appendGateToken (nullptr );
16651692 for (size_t hostIndex = 0 ; hostIndex < hostsPool.size (); hostIndex++) {
1693+ // Inside the loop: hoisted out, the stream accumulates and the second
1694+ // host's URL is the first with the second appended.
1695+ stringstream fullUrl;
16661696 fullUrl << getHostUrl (hostIndex) << " /" << path << " /" << timestamp;
16671697 if (newEOV > 0 ) {
16681698 fullUrl << " /" << newEOV;
@@ -1689,6 +1719,7 @@ int CcdbApi::updateMetadata(std::string const& path, std::map<std::string, std::
16891719 curl_easy_setopt (curl, CURLOPT_CUSTOMREQUEST , " PUT" ); // make sure we use PUT
16901720 curl_easy_setopt (curl, CURLOPT_USERAGENT , mUniqueAgentID .c_str ());
16911721 curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION , 1L );
1722+ curl_easy_setopt (curl, CURLOPT_HTTPHEADER , list);
16921723 curlSetSSLOptions (curl);
16931724
16941725 // Perform the request, res will get the return code
@@ -1699,9 +1730,12 @@ int CcdbApi::updateMetadata(std::string const& path, std::map<std::string, std::
16991730 } else {
17001731 ret = 0 ;
17011732 }
1702- curl_easy_cleanup (curl);
17031733 }
17041734 }
1735+ // After the loop, not inside it: cleaning up per host left every later
1736+ // iteration using a freed handle.
1737+ curl_easy_cleanup (curl);
1738+ curl_slist_free_all (list);
17051739 }
17061740 return ret;
17071741}
0 commit comments