cURL / Mailing Lists / curl-library / Single Mail

curl-library

Is it safe to set curl options inside a callback function?

From: Milmar Tan <milmarqtan_at_gmail.com>
Date: Fri, 28 Aug 2009 23:23:41 +0800

The nature of the program I'm making is that I need to be able to get
the content-length header to allocate space for an image, then write
the image to this allocated space in just a single curl_easy_perform
call.

Previously I tried having two separate curl_easy_perform calls, the
first is a 'look-ahead' to get the content-length and perform data
allocation based on it, and the second to get the data. However, this
approach doesn't work in some proxy servers because some proxy servers
return different sizes in the two curl_easy_perform calls for the same
image (i.e. the first curl_easy_perform will return a size of 1.5KB
for image A, while the second curl_easy_perform will return a size of
1KB still for image A).  This causes my program to either have too
much or too little allocated space.

So, my idea is this: Using a single curl_easy_perform call, I'll wait
for the content-length header in the CURLOPT_HEADERFUNCTION callback.
Then when this callback is called and I find the content-length
header, I'll perform the allocations, stop the retrieval of the
headers, then start writing the data retrieved. Here's the sample
code:

...
CURL * pxCurlHandle1;
size_t headerwrite( void *ptr, size_t size, size_t nmemb, void *stream);
size_t writefunction(void *ptr, size_t size, size_t nmemb, void
*stream); //function that will write the data to the buffer
int fd; //descriptor that will refer to the stream

int main(int argc, char *argv[])
{
curl_global_init(CURL_GLOBAL_WIN32);
pxCurlHandle1 = curl_easy_init();
curl_easy_setopt(pxCurlHandle1, CURLOPT_URL, "http://www.myurl.com/test.jpg");
curl_easy_setopt(pxCurlHandle1, CURLOPT_HEADER, 1); //get the header
curl_easy_setopt(pxCurlHandle1, CURLOPT_HEADERFUNCTION, headerwrite);
curl_easy_perform(pxCurlHandle1);
curl_easy_cleanup(pxCurlHandle1);
curl_global_cleanup();
system("PAUSE");
return 0;
}

size_t headerwrite( void *ptr, size_t size, size_t nmemb, void *stream)
{
char * ptr1 = (char *)malloc(size*nmemb+1); //allocate memory
including teminator
memcpy(ptr1, ptr, size*nmemb);
ptr1[size*nmemb+1]='\0'; //terminate

if(strstr(ptr1, "Content-Length")) //find the Content-Length header
{
curl_easy_setopt(pxCurlHandle1, CURLOPT_HEADER, 0); //disable
retrieval of other headers
curl_easy_setopt(pxCurlHandle1, CURLOPT_HEADERFUNCTION, NULL);
//remove the header callback

/*add code here to get the content-length*/
/*add code here to allocate the buffer based on the content-length*/
/*add code here to initialize fd (it can be a socket or something that
can accept a stream of data)*/

curl_easy_setopt(pxCurlHandle1,CURLOPT_WRITEFUNCTION,writefunction);
//assign the writefunction so data will now be written to fd
curl_easy_setopt(pxCurlHandle1, CURLOPT_WRITEDATA, fd);

}

return size*nmemb;
}
...

Is it safe to call these curl_easy_setopts inside headerwrite?
If this is not advisable, then is there any other possible solution
for my dilemma with some kinds of proxy servers as described above?

Thanks,

Milmar
Received on 2009-08-28