in src/curl.cpp [2335:2596]
int S3fsCurl::RequestPerform(bool dontAddAuthHeaders /*=false*/)
{
if(S3fsLog::IsS3fsLogDbg()){
char* ptr_url = NULL;
curl_easy_getinfo(hCurl, CURLINFO_EFFECTIVE_URL , &ptr_url);
S3FS_PRN_DBG("connecting to URL %s", SAFESTRPTR(ptr_url));
}
LastResponseCode = S3FSCURL_RESPONSECODE_NOTSET;
long responseCode = S3FSCURL_RESPONSECODE_NOTSET;
int result = S3FSCURL_PERFORM_RESULT_NOTSET;
// 1 attempt + retries...
for(int retrycnt = 0; S3FSCURL_PERFORM_RESULT_NOTSET == result && retrycnt < S3fsCurl::retries; ++retrycnt){
// Reset response code
responseCode = S3FSCURL_RESPONSECODE_NOTSET;
// Insert headers
if(!dontAddAuthHeaders) {
insertAuthHeaders();
}
if(CURLE_OK != curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders)){
return false;
}
// Requests
curlCode = curl_easy_perform(hCurl);
// Check result
switch(curlCode){
case CURLE_OK:
// Need to look at the HTTP response code
if(0 != curl_easy_getinfo(hCurl, CURLINFO_RESPONSE_CODE, &responseCode)){
S3FS_PRN_ERR("curl_easy_getinfo failed while trying to retrieve HTTP response code");
responseCode = S3FSCURL_RESPONSECODE_FATAL_ERROR;
result = -EIO;
break;
}
if(responseCode >= 200 && responseCode < 300){
S3FS_PRN_INFO3("HTTP response code %ld", responseCode);
result = 0;
break;
}
{
// Try to parse more specific AWS error code otherwise fall back to HTTP error code.
std::string value;
if(simple_parse_xml(bodydata.c_str(), bodydata.size(), "Code", value)){
// TODO: other error codes
if(value == "EntityTooLarge"){
result = -EFBIG;
break;
}else if(value == "InvalidObjectState"){
result = -EREMOTE;
break;
}else if(value == "KeyTooLongError"){
result = -ENAMETOOLONG;
break;
}
}
}
// Service response codes which are >= 300 && < 500
switch(responseCode){
case 301:
case 307:
S3FS_PRN_ERR("HTTP response code 301(Moved Permanently: also happens when bucket's region is incorrect), returning EIO. Body Text: %s", bodydata.c_str());
S3FS_PRN_ERR("The options of url and endpoint may be useful for solving, please try to use both options.");
result = -EIO;
break;
case 400:
if(op == "HEAD"){
if(path.size() > 1024){
S3FS_PRN_ERR("HEAD HTTP response code %ld with path longer than 1024, returning ENAMETOOLONG.", responseCode);
return -ENAMETOOLONG;
}
S3FS_PRN_ERR("HEAD HTTP response code %ld, returning EPERM.", responseCode);
result = -EPERM;
}else{
S3FS_PRN_ERR("HTTP response code %ld, returning EIO. Body Text: %s", responseCode, bodydata.c_str());
result = -EIO;
}
break;
case 403:
S3FS_PRN_ERR("HTTP response code %ld, returning EPERM. Body Text: %s", responseCode, bodydata.c_str());
result = -EPERM;
break;
case 404:
S3FS_PRN_INFO3("HTTP response code 404 was returned, returning ENOENT");
S3FS_PRN_DBG("Body Text: %s", bodydata.c_str());
result = -ENOENT;
break;
case 416:
S3FS_PRN_INFO3("HTTP response code 416 was returned, returning EIO");
result = -EIO;
break;
case 501:
S3FS_PRN_INFO3("HTTP response code 501 was returned, returning ENOTSUP");
S3FS_PRN_DBG("Body Text: %s", bodydata.c_str());
result = -ENOTSUP;
break;
case 500:
case 503: {
S3FS_PRN_INFO3("HTTP response code %ld was returned, slowing down", responseCode);
S3FS_PRN_DBG("Body Text: %s", bodydata.c_str());
// Add jitter to avoid thundering herd.
unsigned int sleep_time = 2 << retry_count;
sleep(sleep_time + static_cast<unsigned int>(random()) % sleep_time);
break;
}
default:
S3FS_PRN_ERR("HTTP response code %ld, returning EIO. Body Text: %s", responseCode, bodydata.c_str());
result = -EIO;
break;
}
break;
case CURLE_WRITE_ERROR:
S3FS_PRN_ERR("### CURLE_WRITE_ERROR");
sleep(2);
break;
case CURLE_OPERATION_TIMEDOUT:
S3FS_PRN_ERR("### CURLE_OPERATION_TIMEDOUT");
sleep(2);
break;
case CURLE_COULDNT_RESOLVE_HOST:
S3FS_PRN_ERR("### CURLE_COULDNT_RESOLVE_HOST");
sleep(2);
break;
case CURLE_COULDNT_CONNECT:
S3FS_PRN_ERR("### CURLE_COULDNT_CONNECT");
sleep(4);
break;
case CURLE_GOT_NOTHING:
S3FS_PRN_ERR("### CURLE_GOT_NOTHING");
sleep(4);
break;
case CURLE_ABORTED_BY_CALLBACK:
S3FS_PRN_ERR("### CURLE_ABORTED_BY_CALLBACK");
sleep(4);
{
AutoLock lock(&S3fsCurl::curl_handles_lock);
S3fsCurl::curl_times[hCurl] = time(0);
}
break;
case CURLE_PARTIAL_FILE:
S3FS_PRN_ERR("### CURLE_PARTIAL_FILE");
sleep(4);
break;
case CURLE_SEND_ERROR:
S3FS_PRN_ERR("### CURLE_SEND_ERROR");
sleep(2);
break;
case CURLE_RECV_ERROR:
S3FS_PRN_ERR("### CURLE_RECV_ERROR");
sleep(2);
break;
case CURLE_SSL_CONNECT_ERROR:
S3FS_PRN_ERR("### CURLE_SSL_CONNECT_ERROR");
sleep(2);
break;
case CURLE_SSL_CACERT:
S3FS_PRN_ERR("### CURLE_SSL_CACERT");
// try to locate cert, if successful, then set the
// option and continue
if(S3fsCurl::curl_ca_bundle.empty()){
if(!S3fsCurl::LocateBundle()){
S3FS_PRN_ERR("could not get CURL_CA_BUNDLE.");
result = -EIO;
}
// retry with CAINFO
}else{
S3FS_PRN_ERR("curlCode: %d msg: %s", curlCode, curl_easy_strerror(curlCode));
result = -EIO;
}
break;
#ifdef CURLE_PEER_FAILED_VERIFICATION
case CURLE_PEER_FAILED_VERIFICATION:
S3FS_PRN_ERR("### CURLE_PEER_FAILED_VERIFICATION");
first_pos = S3fsCred::GetBucket().find_first_of('.');
if(first_pos != std::string::npos){
S3FS_PRN_INFO("curl returned a CURL_PEER_FAILED_VERIFICATION error");
S3FS_PRN_INFO("security issue found: buckets with periods in their name are incompatible with http");
S3FS_PRN_INFO("This check can be over-ridden by using the -o ssl_verify_hostname=0");
S3FS_PRN_INFO("The certificate will still be checked but the hostname will not be verified.");
S3FS_PRN_INFO("A more secure method would be to use a bucket name without periods.");
}else{
S3FS_PRN_INFO("my_curl_easy_perform: curlCode: %d -- %s", curlCode, curl_easy_strerror(curlCode));
}
result = -EIO;
break;
#endif
// This should be invalid since curl option HTTP FAILONERROR is now off
case CURLE_HTTP_RETURNED_ERROR:
S3FS_PRN_ERR("### CURLE_HTTP_RETURNED_ERROR");
if(0 != curl_easy_getinfo(hCurl, CURLINFO_RESPONSE_CODE, &responseCode)){
result = -EIO;
}else{
S3FS_PRN_INFO3("HTTP response code =%ld", responseCode);
// Let's try to retrieve the
if(404 == responseCode){
result = -ENOENT;
}else if(500 > responseCode){
result = -EIO;
}
}
break;
// Unknown CURL return code
default:
S3FS_PRN_ERR("###curlCode: %d msg: %s", curlCode, curl_easy_strerror(curlCode));
result = -EIO;
break;
} // switch
if(S3FSCURL_PERFORM_RESULT_NOTSET == result){
S3FS_PRN_INFO("### retrying...");
if(!RemakeHandle()){
S3FS_PRN_INFO("Failed to reset handle and internal data for retrying.");
result = -EIO;
break;
}
}
} // for
// set last response code
if(S3FSCURL_RESPONSECODE_NOTSET == responseCode){
LastResponseCode = S3FSCURL_RESPONSECODE_FATAL_ERROR;
}else{
LastResponseCode = responseCode;
}
if(S3FSCURL_PERFORM_RESULT_NOTSET == result){
S3FS_PRN_ERR("### giving up");
result = -EIO;
}
return result;
}