I am trying to send a multipart MIME message with custom streaming (multiple binary files). To this end, I cannot get my CURLOPT_READFUNCTION callback to use a pointer set by CURLFORM_STREAM.
So far as I can tell, the CURLFORM_STREAM documentation automatically calls the CURLOPT_READFUNCTION pointer when it begins to stream data. This is not happening for me.
Here’s my current code sample (I’ve been trying different configurations with no success). CURLCODECHECK and CURLFORMCHECK are macros that throw exceptions on an error. streams is a vector of my own StreamData structs.
CURLCODECHECK(curl_easy_setopt(m_Curl, CURLOPT_HTTPPOST, 1L));
CURLCODECHECK(curl_easy_setopt(m_Curl, CURLOPT_READFUNCTION, ::StreamReadFunction));
for (auto iter = streams.begin(); iter != streams.end(); ++iter)
{
std::string const & name = iter->first;
auto streamData = iter->second;
CURLFORMCHECK(curl_formadd(&m_Post, &last,
CURLFORM_COPYNAME, name.c_str(),
CURLFORM_FILENAME, streamData->fileName.c_str(),
CURLFORM_CONTENTTYPE, streamData->mimeType.c_str(),
CURLFORM_STREAM, (void *) streamData.get(),
CURLFORM_CONTENTSLENGTH, streamData->size,
CURLFORM_END));
}
My ::StreamReadFunction does get called, but unless I call curl_easy_setopt() with CURLOPT_READDATA set, it gets passed a null pointer for the fourth (void * userdata) argument.
In short,
CURLOPT_HTTPPOSTis not a replacement forCURLOPT_POST. Both must be provided andCURLOPT_POSTmust be set first.I moved my
curl_formadd()call to the top of the function, and followed it with:This then properly called my
::StreamReadFunctionwith my stream pointer.Note that
CURLOPT_POSTmust be set beforeCURLOPT_HTTPPOSTfor the stream callback to use the proper pointer (placingCURLOPT_POSTlater will cause a null pointer to be passed in).