in client-library/src/Attestation/AttestationClient/lib/AttestationLibUtils.cpp [281:411]
AttestationResult SendRequest(const std::string& url,
const std::string& payload,
std::string& http_response) {
AttestationResult result(AttestationResult::ErrorCode::SUCCESS);
CURL *curl = curl_easy_init();
if(curl == nullptr) {
result.code_ = AttestationResult::ErrorCode::ERROR_CURL_INITIALIZATION;
result.description_ = std::string("Failed to initialize curl for http request.");
return result;
}
// Create a header object to add the authentication token and content-type to the header.
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
// Set the url of the end point that we are trying to talk to.
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
// set the payload that will be sent to the endpoint.
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, payload.size());
#ifdef PLATFORM_UNIX
char* cainfo = NULL;
curl_easy_getinfo(curl, CURLINFO_CAINFO, &cainfo);
struct stat buffer;
if(cainfo && stat(cainfo, &buffer) == 0) {
CLIENT_LOG_INFO("Using default ca info path: %s", cainfo);
curl_easy_setopt(curl, CURLOPT_CAINFO, cainfo);
} else {
CLIENT_LOG_INFO("Using ca-bundle certs");
curl_easy_setopt(curl, CURLOPT_CAINFO, "curl-ca-bundle.crt");
}
#else
curl_easy_setopt(curl, CURLOPT_CAINFO, "curl-ca-bundle.crt");
curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
#endif
// 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);
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(response_code == HTTP_STATUS_OK) {
http_response = response;
break;
} else if(response_code == HTTP_STATUS_ATTESTATION_FAILURE) {
std::string error_msg = response;
CLIENT_LOG_ERROR("Attestation failed with error code:%ld description:%s",
response_code,
error_msg.c_str());
result.code_ = AttestationResult::ErrorCode::ERROR_ATTESTATION_FAILED;
result.description_ = error_msg;
break;
} else if (response_code == HTTP_STATUS_TOO_MANY_REQUESTS
|| response_code == HTTP_STATUS_REQUEST_TIMEOUT
|| response_code >= HTTP_STATUS_SERVER_ERROR) {
std::string error_msg = response;
CLIENT_LOG_ERROR("Http Request failed with error:%ld description:%s",
response_code,
error_msg.c_str());
CLIENT_LOG_INFO("Retrying");
//Retry sending the request since this is a server failure.
if(retries == MAX_RETRIES) {
CLIENT_LOG_ERROR("Http Request failed with error:%ld description:%s",
response_code,
error_msg.c_str());
CLIENT_LOG_ERROR("Maxinum retries exceeded.");
result.code_ = AttestationResult::ErrorCode::ERROR_HTTP_REQUEST_EXCEEDED_RETRIES;
result.description_ = error_msg;
break;
}
curl_off_t retry_after_seconds = 0;
curl_easy_getinfo(curl, CURLINFO_RETRY_AFTER, &retry_after_seconds);
if (retry_after_seconds) {
CLIENT_LOG_INFO("Http Request throttled by MAA, retry-after: %ld", retry_after_seconds);
}
long long exponential_back_off_seconds = static_cast<long long>(BACK_OFF_TIME_SECONDS * pow(2.0, static_cast<double>(retries++)));
long long sleep_time_milliseconds = To_MilliSeconds((exponential_back_off_seconds > retry_after_seconds ?
exponential_back_off_seconds :
retry_after_seconds)) + static_cast<long long>(generateRandomJitter());
CLIENT_LOG_INFO("Http Request wait time: %ld", sleep_time_milliseconds);
// Sleep for the backoff period and try again.
std::this_thread::sleep_for(
std::chrono::milliseconds(
sleep_time_milliseconds
));
response = std::string();
continue;
} else {
std::string error_msg = response;
CLIENT_LOG_ERROR("Http Request failed with error:%ld description:%s",
response_code,
error_msg.c_str());
result.code_ = AttestationResult::ErrorCode::ERROR_HTTP_REQUEST_FAILED;
result.description_ = error_msg;
break;
}
}
if(res != CURLE_OK) {
CLIENT_LOG_ERROR("Failed sending curl request with error:%s",
curl_easy_strerror(res));
result.code_ = AttestationResult::ErrorCode::ERROR_SENDING_CURL_REQUEST_FAILED;
result.description_ = std::string("Failed sending curl request with error:") + std::string(curl_easy_strerror(res));
}
curl_easy_cleanup(curl);
curl_slist_free_all(headers);
return result;
}