in lib/CurlWrapper.h [97:181]
inline CurlWrapper::Result CurlWrapper::get(const std::string& url, const std::string& header,
const Options& options, const TlsContext* tlsContext) const {
assert(handle_);
curl_easy_setopt(handle_, CURLOPT_URL, url.c_str());
if (!options.postFields.empty()) {
curl_easy_setopt(handle_, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(handle_, CURLOPT_POSTFIELDS, options.postFields.c_str());
}
// Write response
curl_easy_setopt(
handle_, CURLOPT_WRITEFUNCTION,
+[](char* buffer, size_t size, size_t nitems, void* outstream) -> size_t {
static_cast<std::string*>(outstream)->append(buffer, size * nitems);
return size * nitems;
});
std::string response;
curl_easy_setopt(handle_, CURLOPT_WRITEDATA, &response);
// New connection is made for each call
curl_easy_setopt(handle_, CURLOPT_FRESH_CONNECT, 1L);
curl_easy_setopt(handle_, CURLOPT_FORBID_REUSE, 1L);
// Skipping signal handling - results in timeouts not honored during the DNS lookup
// Without this config, Curl_resolv_timeout might crash in multi-threads environment
curl_easy_setopt(handle_, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(handle_, CURLOPT_TIMEOUT, options.timeoutInSeconds);
if (!options.userAgent.empty()) {
curl_easy_setopt(handle_, CURLOPT_USERAGENT, options.userAgent.c_str());
}
curl_easy_setopt(handle_, CURLOPT_FAILONERROR, 1L);
// Redirects
curl_easy_setopt(handle_, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(handle_, CURLOPT_MAXREDIRS, options.maxLookupRedirects);
char errorBuffer[CURL_ERROR_SIZE] = "";
curl_easy_setopt(handle_, CURLOPT_ERRORBUFFER, errorBuffer);
curl_slist* headers = nullptr;
CurlListGuard headersGuard{headers};
if (!header.empty()) {
headers = curl_slist_append(headers, header.c_str());
curl_easy_setopt(handle_, CURLOPT_HTTPHEADER, headers);
}
if (tlsContext) {
CURLcode code;
code = curl_easy_setopt(handle_, CURLOPT_SSLENGINE, nullptr);
if (code != CURLE_OK) {
return {code, "", -1, "",
"Unable to load SSL engine for url " + url + ": " + curl_easy_strerror(code)};
}
code = curl_easy_setopt(handle_, CURLOPT_SSLENGINE_DEFAULT, 1L);
if (code != CURLE_OK) {
return {code, "", -1, "",
"Unable to load SSL engine as default for url " + url + ": " + curl_easy_strerror(code)};
}
curl_easy_setopt(handle_, CURLOPT_SSL_VERIFYHOST, tlsContext->validateHostname ? 1L : 0L);
curl_easy_setopt(handle_, CURLOPT_SSL_VERIFYPEER, tlsContext->allowInsecure ? 0L : 1L);
if (!tlsContext->trustCertsFilePath.empty()) {
curl_easy_setopt(handle_, CURLOPT_CAINFO, tlsContext->trustCertsFilePath.c_str());
}
if (!tlsContext->certPath.empty() && !tlsContext->keyPath.empty()) {
curl_easy_setopt(handle_, CURLOPT_SSLCERT, tlsContext->certPath.c_str());
curl_easy_setopt(handle_, CURLOPT_SSLKEY, tlsContext->keyPath.c_str());
}
}
auto res = curl_easy_perform(handle_);
long responseCode;
curl_easy_getinfo(handle_, CURLINFO_RESPONSE_CODE, &responseCode);
Result result{res, response, responseCode, "", "", std::string(errorBuffer)};
if (responseCode == 307 || responseCode == 302 || responseCode == 301) {
char* url;
curl_easy_getinfo(handle_, CURLINFO_REDIRECT_URL, &url);
// `url` is null when the host of the redirect URL cannot be resolved
if (url) {
result.redirectUrl = url;
}
}
return result;
}