As seen at the libcurl documentation for curl_easy_setopt()
, the callback function is called as many times as required to deliver all the bytes of the fetched page.
Your function overwrites the same buffer on every call, with the result that after curl_easy_perform()
has finished fetching the file, you only have whatever fit in the final call to tobuffer()
left.
In short, your function tobuffer()
must do something other than overwrite the same buffer on each call.
update
For example, you could do something like the following completely untested code:
struct buf {
char *buffer;
size_t bufferlen;
size_t writepos;
} buffer = {0};
size_t tobuffer(char *ptr, size_t size, size_t nmemb, void *stream)
{
size_t nbytes = size*nmemb;
if (!buffer.buffer) {
buffer.buffer = malloc(1024);
buffer.bufferlen = 1024;
buffer.writepos = 0;
}
if (buffer.writepos + nbytes < buffer.bufferlen) {
buffer.bufferlen = 2 * buffer.bufferlen;
buffer.buffer = realloc(buffer, buffer.bufferlen);
}
assert(buffer.buffer != NULL);
memcpy(buffer.buffer+buffer.writepos,ptr,nbytes);
return nbytes;
}
At some later point in your program you will need to free the allocated memory something like this:
void freebuffer(struct buf *b) {
free(b->buffer);
b->buffer = NULL;
b->bufferlen = 0;
b->writepos = 0;
}
Also, note that I've used memcpy()
instead of strncpy()
to move data to the buffer. This is important because libcurl makes no claim that the data passed to the callback function is actually a NUL terminated ASCII string. In particular, if you retrieve a .gif image file, it certainly can (and will) contain zero bytes in the file which you would want to preserve in your buffer. strncpy()
will stop copying after the first NUL it sees in the source data.
As an exercise for the reader, I've left all the error handling out of this code. You must put some in. Furthermore, I've also left in a juicy memory leak on the off chance that the call to realloc()
fails.
Another improvement would be to make use of the option that allows the value of the stream
parameter to the callback to come from the libcurl caller. That could be used to allocate manage your buffer without using global variables. I'd strongly recommend doing that as well.