curl-library
Problem: curl multi pipelining mix up easy_handle
Date: Fri, 31 May 2013 05:35:06 +0000
Hi,
This is the problem I encountered:
It seems that multi session mix up the easy_handles (which are been added into the session) when used in multi pipelining.
The phenomenon looks like this:
(1) Enable curlmopt_pipelining and curlopt_followlocation
(2) Add easy_handle "A" with normal url "a" into multi_handle "m"
(3) Add easy_handle "B" with redirect url "b" into multi_handle "m"
(4) Run curl_multi_perform
(5) The result shows that easy_handle "A" is for redirect url "b"; and easy_handle "B" is for normal url "a"
(6) When to disable the multi pipelining, the phenomenon disappear.
I find this problem in one complicated application which use multiple interface in libcurl (version: 7.25 ) to download files from apache server (version: 2.2.12) with multi pipelining enabled. When to disable multi pipelining in this application, the problem disappear. I have extracted the curl download logic from this complicated application into a single file. I have attached this file in the following and you can refer it for the curl download logic in our complicated application.
My question:
Is this a known issue for multi interface with multi pipelining? If it is, is it been resolved at the latest version (a.k.a: 7.30). If it not, is there any workaround with multi pie lining enabled?
=================
#define HANDLER_SIZE 20
int curlDebugCallback (CURL* curl, curl_infotype intoType, char* msg, size_t msgSize)
{
std::string debugString(msg, msgSize);
fprintf(stdout, "curlDebugCallback: %s\n", debugString.c_str());
return 0;
}
int main(void)
{
CURLcode res;
CURLM *mMultiCurl;
FILE *outputFile;
std::string tempFilePath;
char curlErrorBuffer[200];
mMultiCurl = curl_multi_init();
curl_multi_setopt(mMultiCurl, CURLMOPT_PIPELINING, 1);
CURL *handles[HANDLER_SIZE];
FILE *outputFileHandlers[HANDLER_SIZE];
for (int i=0; i < HANDLER_SIZE; i++)
{
/* init the curl session */
handles[i] = curl_easy_init();
curl_easy_setopt(handles[i], CURLOPT_ERRORBUFFER, curlErrorBuffer);
curl_easy_setopt(handles[i], CURLOPT_HEADER, 0);
curl_easy_setopt(handles[i], CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(handles[i], CURLOPT_VERBOSE, 1);
curl_easy_setopt(handles[i], CURLOPT_FAILONERROR, true);
curl_easy_setopt(handles[i], CURLOPT_SSL_SESSIONID_CACHE, 0L);
curl_easy_setopt(handles[i], CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(handles[i], CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(handles[i], CURLOPT_HTTPAUTH, CURLAUTH_BASIC);//CURLAUTH_BASIC
curl_easy_setopt(handles[i], CURLOPT_COOKIEFILE, "csf2g-pm");
curl_easy_setopt(handles[i], CURLOPT_HTTPHEADER, NULL);
curl_easy_setopt(handles[i], CURLOPT_DEBUGFUNCTION, curlDebugCallback);
//specify URL to get
if ( i%2 == 0 )
{
//This url is not a redirect url
curl_easy_setopt(handles[i], CURLOPT_URL, "http://64.104.172.101/apache_pb.gif");
fprintf(stdout, "index is: %d, handler is: %p, url is %s\n",i, handles[i], "http://64.104.172.101/apache_pb.gif");
}
else
{
//This url is a redirect url
curl_easy_setopt(handles[i], CURLOPT_URL, "http://64.104.172.101/index.html");
fprintf(stdout, "index is %d, handler is: %p, url is %s\n",i, handles[i], "http://64.104.172.101/index.html");
}
char strtemp[10];
sprintf(strtemp, "%d", i);
std::string tempFilePath = "/Users/loc/Downloads/test"+ std::string(strtemp) + ".jpg";
outputFileHandlers[i] = fopen(tempFilePath.c_str(), "wb");
if(outputFileHandlers[i] == NULL)
{
fprintf(stderr, "open outputFile failed\n");
return 1;
}
curl_easy_setopt(handles[i], CURLOPT_WRITEDATA, outputFileHandlers[i]);
curl_multi_remove_handle(mMultiCurl, handles[i]);
curl_multi_add_handle(mMultiCurl, handles[i]);
}
int still_running;
CURLMcode mcode = curl_multi_perform(mMultiCurl, &still_running);
CURLMsg *msg; /* for picking up messages with the transfer status */
int msgs_left; /* how many messages are left */
int retries = 0;
while(still_running )
{
struct timeval timeout;
int rc; /* select() return code */
fd_set fdread;
fd_set fdwrite;
fd_set fdexcep;
int maxfd = -1;
long curl_timeo = -1;
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcep);
/* set a suitable timeout to play around with */
timeout.tv_sec = 1;
timeout.tv_usec = 0;
curl_multi_timeout(mMultiCurl, &curl_timeo);
if(curl_timeo >= 0)
{
timeout.tv_sec = curl_timeo / 1000;
if(timeout.tv_sec > 1)
timeout.tv_sec = 1;
else
timeout.tv_usec = (curl_timeo % 1000) * 1000;
}
/* get file descriptors from the transfers */
curl_multi_fdset(mMultiCurl, &fdread, &fdwrite, &fdexcep, &maxfd);
/* In a real-world program you OF COURSE check the return code of the
function calls. On success, the value of maxfd is guaranteed to be
greater or equal than -1. We call select(maxfd + 1, ...), specially in
case of (maxfd == -1), we call select(0, ...), which is basically equal
to sleep. */
rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
switch(rc)
{
case -1:
/* select error */
fprintf(stderr, "select error\n");
break;
case 0: /* timeout */
default: /* action */
mcode = curl_multi_perform(mMultiCurl, &still_running);
break;
}
retries++;
}
/* See how the transfers went */
while ((msg = curl_multi_info_read(mMultiCurl, &msgs_left)))
{
if (msg->msg == CURLMSG_DONE)
{
char* effectivurl;
bool found = false;
int i = 0;
for(; i< HANDLER_SIZE; i++)
{
if (msg->easy_handle == handles[i])
{
found = true;
break;
}
}
if (!found)
{
printf("curl handle not found\n");
return 1;
}
fseek(outputFileHandlers[i], 0, SEEK_END);
long outputFileSize = ftell(outputFileHandlers[i]);
int success = fclose(outputFileHandlers[i]);
double size = 0.0;
double cLength = 0.0;
curl_easy_getinfo(msg->easy_handle, CURLINFO_SIZE_DOWNLOAD, &size);
curl_easy_getinfo(msg->easy_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &cLength);
curl_easy_getinfo(msg->easy_handle, CURLINFO_EFFECTIVE_URL, &effectivurl);
printf("curl handle is %p,index is %d, url is %s, size is %lf, clength is %lf, msg_result is %d, error is %s\n",msg->easy_handle, i, effectivurl, size, cLength, msg->data.result, curlErrorBuffer);
if((cLength > 0.0 && cLength != size) || outputFileSize <= 0)
{
fprintf(stderr, "download photo lenth error\n");
}
}
}
/* cleanup curl stuff */
for(int i=0; i< HANDLER_SIZE; i++)
{
curl_easy_cleanup(handles[i]);
}
curl_multi_cleanup(mMultiCurl);
mMultiCurl = NULL;
return 0;
}
=================
Thanks.
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
Received on 2013-05-31