in sdk/src/http/CurlHttpClient.cc [432:643]
std::shared_ptr<HttpResponse> CurlHttpClient::makeRequest(const std::shared_ptr<HttpRequest> &request)
{
OSS_LOG(LogLevel::LogDebug, TAG, "request(%p) enter makeRequest", request.get());
curl_slist *list = nullptr;
auto& headers = request->Headers();
for (const auto &p : headers) {
if (p.second.empty())
continue;
std::string str = p.first;
str.append(": ").append(p.second);
list = curl_slist_append(list, str.c_str());
}
// Disable Expect: 100-continue
list = curl_slist_append(list, "Expect:");
auto response = std::make_shared<HttpResponse>(request);
std::iostream::pos_type requestBodyPos = -1;
if (request->Body() != nullptr) {
requestBodyPos = request->Body()->tellg();
}
CURL * curl = curlContainer_->Acquire();
OSS_LOG(LogLevel::LogDebug, TAG, "request(%p) acquire curl handle:%p", request.get(), curl);
uint64_t initCRC64 = 0;
#ifdef ENABLE_OSS_TEST
if (headers.find("oss-test-crc64") != headers.end()) {
initCRC64 = std::strtoull(headers.at("oss-test-crc64").c_str(), nullptr, 10);
}
#endif
TransferState transferState = {
this,
curl,
request.get(),
response.get(),
0, -1,
true, -1,
request->TransferProgress().Handler,
request->TransferProgress().UserData,
request->hasCheckCrc64(), initCRC64, initCRC64,
0, 0
};
if (request->hasHeader(Http::CONTENT_LENGTH)) {
transferState.total = std::atoll(request->Header(Http::CONTENT_LENGTH).c_str());
}
std::string url = request->url().toString();
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
switch (request->method())
{
case Http::Method::Head:
curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
break;
case Http::Method::Put:
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
break;
case Http::Method::Post:
curl_easy_setopt(curl, CURLOPT_POST, 1L);
break;
case Http::Method::Delete:
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
break;
case Http::Method::Get:
default:
break;
}
curl_easy_setopt(curl, CURLOPT_USERAGENT,userAgent_.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &transferState);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, recvHeaders);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &transferState);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, recvBody);
curl_easy_setopt(curl, CURLOPT_READDATA, &transferState);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, sendBody);
if (verifySSL_) {
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
}
if(!caPath_.empty()) {
curl_easy_setopt(curl, CURLOPT_CAPATH, caPath_.c_str());
}
if(!caFile_.empty()){
curl_easy_setopt(curl, CURLOPT_CAINFO, caFile_.c_str());
}
if (!proxyHost_.empty()) {
std::stringstream ss;
ss << Http::SchemeToString(proxyScheme_) << "://" << proxyHost_;
curl_easy_setopt(curl, CURLOPT_PROXY, ss.str().c_str());
curl_easy_setopt(curl, CURLOPT_PROXYPORT, (long) proxyPort_);
curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, proxyUserName_.c_str());
curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD, proxyPassword_.c_str());
}
if (!networkInterface_.empty()) {
curl_easy_setopt(curl, CURLOPT_INTERFACE, networkInterface_.c_str());
}
//debug
if (GetLogLevelInner() >= LogLevel::LogInfo) {
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, debugCallback);
}
//Error Buffer
char errbuf[CURL_ERROR_SIZE];
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
errbuf[0] = 0;
//progress Callback
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progressCallback);
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &transferState);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
//Send bytes/sec
if (sendRateLimiter_ != nullptr) {
transferState.sendSpeed = sendRateLimiter_->Rate();
auto speed = static_cast<curl_off_t>(transferState.sendSpeed);
speed = speed * 1024;
curl_easy_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE, speed);
}
//Recv bytes/sec
if (recvRateLimiter_ != nullptr) {
transferState.recvSpeed = recvRateLimiter_->Rate();
auto speed = static_cast<curl_off_t>(transferState.recvSpeed);
speed = speed * 1024;
curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, speed);
}
CURLcode res = curl_easy_perform(curl);
long response_code= 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
if (res == CURLE_OK) {
response->setStatusCode(response_code);
} else {
response->setStatusCode(res + ERROR_CURL_BASE);
switch (res) {
case 23: //CURLE_WRITE_ERROR
{
std::string msg(curl_easy_strerror(res));
if (response->Body() == nullptr) {
msg.append(". Caused by content is null.");
}
else if (response->Body()->bad()) {
msg.append(". Caused by content is in bad state(Read/writing error on i/o operation).");
}
else if (response->Body()->fail()) {
msg.append(". Caused by content is in fail state(Logical error on i/o operation).");
}
response->setStatusMsg(msg);
}
break;
default:
{
std::string msg(curl_easy_strerror(res));
msg.append(".").append(errbuf);
response->setStatusMsg(msg);
}
break;
};
}
switch (request->method())
{
case Http::Method::Put:
case Http::Method::Post:
request->setCrc64Result(transferState.sendCrc64Value);
break;
default:
request->setCrc64Result(transferState.recvCrc64Value);
break;
}
request->setTransferedBytes(transferState.transferred);
curlContainer_->Release(curl, (res != CURLE_OK));
curl_slist_free_all(list);
auto & body = response->Body();
if (body != nullptr) {
body->flush();
if (res != CURLE_OK && transferState.recvBodyPos != static_cast<std::streampos>(-1)) {
OSS_LOG(LogLevel::LogDebug, TAG, "request(%p) setResponseBody, tellp:%lld, recvBodyPos:%lld",
request.get(), body->tellp(), transferState.recvBodyPos);
body->clear();
body->seekp(transferState.recvBodyPos);
}
}
else {
response->addBody(std::make_shared<std::stringstream>());
}
if (requestBodyPos != static_cast<std::streampos>(-1)) {
request->Body()->clear();
request->Body()->seekg(requestBodyPos);
}
OSS_LOG(LogLevel::LogDebug, TAG, "request(%p) leave makeRequest, CURLcode:%d, ResponseCode:%d",
request.get(), res, response_code);
return response;
}