Multipart upload problem
-
Dear all,
I have to replace a CURL function for multipart upload by QHttpMultipart.
The example in the documentation does not work for my case and I just can't get it running.
Your help is highly appreciated.
Thanks in advance, AxelOriginal CURL based code:
CURL *curl; CURLcode res; struct curl_httppost *formpost = NULL; struct curl_httppost *lastptr = NULL; struct curl_slist *headerlist = NULL; static const char buf[] = "Expect:"; curl_global_init(CURL_GLOBAL_ALL); // set up the header curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "cache-control:", CURLFORM_COPYCONTENTS, "no-cache", CURLFORM_END); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "content-type:", CURLFORM_COPYCONTENTS, "multipart/form-data", CURLFORM_END); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "part1", CURLFORM_COPYCONTENTS, "dummyname.csv", CURLFORM_END); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "part2", CURLFORM_BUFFER, "data", CURLFORM_BUFFERPTR, contents.data(), CURLFORM_BUFFERLENGTH, contents.size(), CURLFORM_END); curl = curl_easy_init(); string authkey = "apikey: " + get_apikey(); headerlist = curl_slist_append(headerlist, authkey.c_str()); headerlist = curl_slist_append(headerlist, buf); string readBuffer; if (curl) { curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunction); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); res = curl_easy_perform(curl);
New code which does not work:
const string url = URL + "upload?file=" + filekey; QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); QHttpPart cachePart; cachePart.setRawHeader("cache-control:", "no-cache"); QHttpPart contentType; contentType.setRawHeader("content-type:", "multipart/form-data"); QHttpPart fileName; fileName.setRawHeader("part1", "dummyname.csv"); QHttpPart data; data.setRawHeader("part2", "data"); data.setBody(QByteArray(contents.c_str())); multiPart->append(cachePart); multiPart->append(contentType); multiPart->append(fileName); multiPart->append(data); QUrl u((URL+"upload").c_str()); QUrlQuery q; q.addQueryItem("file",filekey.c_str()); u.setQuery(q); QNetworkRequest request(u); request.setRawHeader("apikey",get_apikey().c_str()); QNetworkAccessManager* nm= new QNetworkAccessManager; auto reply = nm->post(request, multiPart); multiPart->setParent(reply); // delete the multiPart with the reply QEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); bool success = (reply->error()==QNetworkReply::NoError); string r = reply->readAll().toStdString(); delete reply; return success;
-
@AxelVienna
please don't force synchronous behaviour on asynchronous apisQEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec();
That's inviting all kinds of strange behaviour and hard to track down bugs.
-
Hi,
What exact error do you get ?
Why are you creating one part per raw header ? That looks off.
-
Hi SGaist,
thanks for looking into the issue. I did not get any error message. The code misbehaved and just did not upload any data.
With some trial and error and your advice not to set raw headers, I got it working with the code attached.
The issue is solved, I just have not gotten any wiser.
Brgds
Axelconst string url = URL + "upload?file=" + filekey; QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); QHttpPart cachePart; cachePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"cache-control:\"")); cachePart.setBody("no-nache"); QHttpPart contentType; contentType.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"content-type:\"")); contentType.setBody("multipart/form-data"); QHttpPart fileName; fileName.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"part1\"")); fileName.setBody("dummyname.csv"); QHttpPart data; data.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"part2\"")); data.setBody(QByteArray(contents.c_str())); multiPart->append(cachePart); multiPart->append(contentType); multiPart->append(fileName); multiPart->append(data); QUrl u((URL+"upload").c_str()); QUrlQuery q; q.addQueryItem("file",filekey.c_str()); u.setQuery(q); QNetworkRequest request(u); request.setRawHeader("apikey",get_apikey().c_str()); QNetworkAccessManager* nm= new QNetworkAccessManager; auto reply = nm->post(request, multiPart); multiPart->setParent(reply); // delete the multiPart with the reply QEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec();
-
@AxelVienna
please don't force synchronous behaviour on asynchronous apisQEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec();
That's inviting all kinds of strange behaviour and hard to track down bugs.