curl-library
How to configure easy handle for FTP upload resume?
Date: Wed, 09 Nov 2011 17:15:02 +0100
I have a problem with transfer resume after connection had been lost and only a part of file has been uploaded to FTP server.
1. Size of uploaded file on server after resume is less than size of original file when I set only this:
Set_Easy_Opt(handle, CURLOPT_APPEND, 1l);
2. Size of uploaded file on server after resume is greater than size of original file when I set this among other options:
Set_Easy_Opt(handle, CURLOPT_RESUME_FROM, -1l);
or
Set_Easy_Opt(handle, CURLOPT_RESUME_FROM_LARGE, -1l);
It seems that in this case we have a sume of partially uploaded file and fully uploaded file.
When I try to upload files using this command:
curl -T /tmp/file4upload ftp://10.4.0.1/upload/foo10 -v -u user:pass -C -1
it worked.
I have tried various combinations of these settings and neither of them works. I also tried to check how it is done in CURL sources, but it didn't give me any results.
How should I configure my handle to make it work?
Here is link to code:
http://pastebin.com/YMmKxpbh
and the code itself:
template<typename OptionType>
void Set_Easy_Opt(CURL* easyHandle, CURLoption option, OptionType value) throw(std::exception)
{
CURLcode result = curl_easy_setopt(easyHandle, option, value);
if (result != CURLE_OK)
{
std::ostringstream str;
str << "curl_easy_setopt FAILED for option: " << option << ", value: " << value
<< " returned: " << (int) result << " " << curl_easy_strerror(result);
throw std::runtime_error(str.str());
}
}
tm_error_t TransferManager::SetupTransfer(transfer_data& transfer, CURL* handle)
{
const long MIN_OPERATION_TIME = 20;
const long FTP_RESPONSE_TIMEOUT = 90;
const long CONNECT_TIMEOUT = 60;
long timeout = difftime(transfer.task.expireTime, std::time(0));
if (timeout < MIN_OPERATION_TIME)
{
LOG_INFO("There is not enough time for the operation: " << timeout
<< " s, minimum is: " << MIN_OPERATION_TIME << " s");
Fclose(transfer.fileHandle);
return TM_OP_TOUT;
}
long connectTimeout = (timeout > CONNECT_TIMEOUT) ? CONNECT_TIMEOUT : timeout/2;
long ftpResponseTimeout = (FTP_RESPONSE_TIMEOUT < timeout) ? FTP_RESPONSE_TIMEOUT : (timeout - 1);
// for now it's only for upload
if (not transfer.fileHandle) // it can be initial try
{
transfer.fileHandle = fopen(transfer.task.GetLocalPath().c_str(), "r");
if (not transfer.fileHandle)
{
LOG_ERROR("CURL: Could not open file handle to: " << transfer.task.GetLocalPath());
return TM_FILE_ERR;
}
}
try {
curl_easy_reset(handle);
transfer.errorBuffer[0] = '\0'; // we clean buffer before every retry of transfer
Set_Easy_Opt(handle, CURLOPT_ERRORBUFFER, transfer.errorBuffer);
Set_Easy_Opt(handle, CURLOPT_URL, transfer.task.urlToFile.c_str());
Set_Easy_Opt(handle, CURLOPT_UPLOAD, 1l);
Set_Easy_Opt(handle, CURLOPT_APPEND, 1l);
//Set_Easy_Opt(handle, CURLOPT_RESUME_FROM, -1l); // continue upload
//Set_Easy_Opt(handle, CURLOPT_RESUME_FROM_LARGE, -1l); // continue upload
Set_Easy_Opt(handle, CURLOPT_READDATA, transfer.fileHandle);
std::string userPass = mFtpUser + ":" + mFtpPass;
Set_Easy_Opt(handle, CURLOPT_USERPWD, userPass.c_str());
Set_Easy_Opt(handle, CURLOPT_NOSIGNAL, 1l);
LOG_DEBUG("Setting timeout for task with " << transfer.task.urlToFile
<< ", timeout = " << timeout << ", connect timeout = " << connectTimeout
<< ", ftpResponseTimeout = " << ftpResponseTimeout);
Set_Easy_Opt(handle, CURLOPT_TIMEOUT, timeout);
Set_Easy_Opt(handle, CURLOPT_CONNECTTIMEOUT, connectTimeout);
Set_Easy_Opt(handle, CURLOPT_FTP_RESPONSE_TIMEOUT, ftpResponseTimeout);
#ifdef CURL_DEBUG_CALLBACK
Set_Easy_Opt(handle, CURLOPT_VERBOSE, 1l);
Set_Easy_Opt(handle, CURLOPT_DEBUGFUNCTION, CurlDebugCallback);
#endif
Set_Easy_Opt(handle, CURLOPT_LOW_SPEED_TIME, 60l);
Set_Easy_Opt(handle, CURLOPT_LOW_SPEED_LIMIT, 1l);
Set_Easy_Opt(handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
} catch (std::runtime_error const& e) {
LOG_ERROR("CURL: easy handle could not be configured for server task with url: \""
<< transfer.task.urlToFile << "\", local path: \"" << transfer.task.GetLocalPath()
<< "\", exception: " << e.what());
if (transfer.errorBuffer[0])
LOG_ERROR("CURL: ConfigureCurlHandle: curl error buffer: " << transfer.errorBuffer);
Fclose(transfer.fileHandle);
return TM_SOFTWARE_ERR;
}
CURLMcode curlResult = curl_multi_add_handle(mMultiHandle, handle);
if (curlResult != CURLM_OK)
{
LOG_ERROR("CURL: easy handle could not be added to multi!!!! error code: "
<< (int) curlResult << " " << curl_multi_strerror(curlResult));
Fclose(transfer.fileHandle);
return TM_SOFTWARE_ERR;
}
return TM_NO_ERR;
}
Regards
Marcin Adamski
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
Received on 2011-11-09