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_HTTPPOST
is not a replacement for CURLOPT_POST
. Both must be provided and CURLOPT_POST
must be set first.
I moved my curl_formadd()
call to the top of the function, and followed it with:
CURLCODECHECK(curl_easy_setopt(m_Curl, CURLOPT_POST, 1L));
CURLCODECHECK(curl_easy_setopt(m_Curl, CURLOPT_POSTFIELDSIZE, fieldSize));
CURLCODECHECK(curl_easy_setopt(m_Curl, CURLOPT_READFUNCTION, ::StreamReadFunction));
CURLCODECHECK(curl_easy_setopt(m_Curl, CURLOPT_HTTPPOST, m_Post));
CURLCODECHECK(curl_easy_setopt(m_Curl, CURLOPT_VERBOSE, 1L));
CURLCODECHECK(curl_easy_setopt(m_Curl, CURLOPT_HEADER, 1L));
This then properly called my ::StreamReadFunction
with my stream pointer.
Note that CURLOPT_POST
must be set before CURLOPT_HTTPPOST
for the stream callback to use the proper pointer (placing CURLOPT_POST
later will cause a null pointer to be passed in).