in client-library/src/Attestation/AttestationClient/lib/ImdsClient.cpp [189:290]
std::string ImdsClient::InvokeHttpRequest(
const std::string& url,
const ImdsClient::HttpVerb& http_verb,
const std::string& request_body) {
std::string http_response;
if (url.empty()) {
CLIENT_LOG_ERROR("The URL can not be empty");
return http_response;
}
CURL* curl = curl_easy_init();
if (curl == nullptr) {
CLIENT_LOG_ERROR("Failed to initialize curl for http request.");
return http_response;
}
// Set the the HTTPHEADER object to send Metadata in the response.
struct curl_slist* headers = NULL;
headers = curl_slist_append(headers, "Metadata:true");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
// Send a pointer to a std::string to hold the response from the end
// point along with the handler function.
std::string response;
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteResponseCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
// Set the url of the end point that we are trying to talk to.
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
if (http_verb == ImdsClient::HttpVerb::POST) {
if (request_body.empty()) {
CLIENT_LOG_ERROR("Request body missing for POST request");
return http_response;
}
// Set Http request to be a POST request as expected by the THIM endpoint.
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
// set the payload that will be sent to the endpoint.
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request_body.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, request_body.size());
}
// Adding timeout for 300 sec
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 300L);
CURLcode res = CURLE_OK;
uint8_t retries = 0;
while ((res = curl_easy_perform(curl)) == CURLE_OK) {
long response_code = HTTP_STATUS_OK;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
if (HTTP_STATUS_OK == response_code) {
http_response = response;
if (http_response.size() == 0) {
CLIENT_LOG_ERROR("HTTP response found empty");
break;
}
CLIENT_LOG_INFO("HTTP response retrieved: %s", http_response.c_str());
break;
}
else if (response_code == HTTP_STATUS_RESOURCE_NOT_FOUND ||
response_code == HTTP_STATUS_TOO_MANY_REQUESTS ||
response_code >= HTTP_STATUS_INTERNAL_SERVER_ERROR) {
//If we receive any of these responses from IMDS, we can retry
//after an exponential backoff time
// Sleep for the backoff period and try again
if (retries == MAX_RETRIES) {
CLIENT_LOG_ERROR("HTTP request failed. Maximum retries exceeded\n");
break;
}
CLIENT_LOG_ERROR("HTTP request failed with response code:%ld description:%s",
response_code,
response.c_str());
CLIENT_LOG_INFO("Retrying HTTP request:%d", retries);
// Retry with backoff 30 -> 60 -> 120 seconds
std::this_thread::sleep_for(
std::chrono::seconds(
static_cast<long long>(30 * pow(2.0, static_cast<double>(retries++)))
));
response = std::string();
continue;
}
else {
CLIENT_LOG_ERROR("HTTP request failed with response code:%ld description:%s",
response_code,
response.c_str());
break;
}
}
if (res != CURLE_OK) {
CLIENT_LOG_ERROR("curl_easy_perform() failed:%s", curl_easy_strerror(res));
}
curl_easy_cleanup(curl);
curl_slist_free_all(headers);
return http_response;
}