PDA

View Full Version : How to code a (simple ?) cUrl command in Qt ?



nils_heidorn
29th August 2013, 13:49
Hello !
I have a simple cUrl command that i need to code in a Qt app:
curl -u user:pass -F "filename=test.txt" -F "fname=@foo.txt" http://www.myserver.com/fileupload.htm

(Not that i know much of cUrl other then it can do MUCH more :-) )

So this should fill out a form with a "test.txt" and upload a file while providing basic user/pass credentials.

Could i do this whith built-in Qt functions or do i need to run the cUrl command line binary OR to use the cUrl library ?

Any help is really appreciated :-)

Greetings,

Nils

nils_heidorn
29th August 2013, 16:30
Any help ?
It seems IF i code the curl command line from above in C++ code using libcurl it wuld be something like this (for the two -F parameters):


curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "sendfile",
CURLFORM_FILE, "postit2.c",
CURLFORM_END);

/* Fill in the filename field */
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "filename",
CURLFORM_COPYCONTENTS, "postit2.c",
CURLFORM_END);


But i'd like to avoid to "yet use another lib" if i could do this with Qt native stuff.
Do you have any hint to do this without curl CLI or libcurl ?

Nils

wysota
29th August 2013, 16:57
What kind of help do you expect from us?

nils_heidorn
29th August 2013, 17:53
Hi !
Sorry if i failed to make myself clear.
I need some hint / help / sample code that only uses Qt native commands and that has the same result as the curl command line that i posted. (Or presumably as the sniplet of using curl.h).

I fail to explain it more simple.

Greetings,

Nils

wysota
29th August 2013, 20:16
Hmmm... so you want a complete solution for the task? It's not 5 lines of code, you know...

nils_heidorn
29th August 2013, 20:55
Hi wysota !
Its not about what i want but what someone is willing to do.
At least i know that it is NOT 5 lines of code :-)

I am really not new to Qt but i NEVER did web stuff...
I assume that the QNetworkAccessManager may be the thing to check out but it looks so complex that a simple "No" or "Yes" would already help. And if someone feels like it i am sure that there are some key aspects that could help me tremendously.
But with your reputation here i already feel sheepish to explain to YOU you help can look.
I'll take what i get, networkwise i really start at ZERO.
And if you tell me not to do it as libcurl is much better to do it then thats it.
(provided that you give a minimum of reasoning, i would HATE to incorporate another huge lib if i do not need to).

Greetings,

Nils

wysota
29th August 2013, 21:17
I assume that the QNetworkAccessManager may be the thing to check out but it looks so complex that a simple "No" or "Yes" would already help.
Yes :)


And if someone feels like it i am sure that there are some key aspects that could help me tremendously.
The key aspect is definitely encoding the form. The rest is easily handled by QNetworkRequest.


And if you tell me not to do it as libcurl is much better to do it then thats it.
Well... if you like reinventing the wheel then that's fine with me :) If size is an issue and you're using Qt anyway then indeed not using 3rd party libs is an advantage.

nils_heidorn
29th August 2013, 21:33
Hi !

Thanks again :-)
Ooookay, if you feel like it, may help me out with encoding the form, right now i do not even know what that may means (well besides foggy ideas) :-)

And for re-inventing the wheel:
Of course if it is too hard doing it the "Qt way" then i will use curl, but i hoped that the curl 30 liner could be done at least with a Qt 50 liner or so...

Its not about reinventing the wheel but about having to get a spare tire and learning that there already is one hidden deep in the trunk that is a BIT hard to get at ;-)


Greetings,

Nils

wysota
29th August 2013, 22:36
Ooookay, if you feel like it, may help me out with encoding the form, right now i do not even know what that may means (well besides foggy ideas) :-)
Search the web for "http form encoding"

nils_heidorn
30th August 2013, 08:29
Hi !
After i knew what to search for i found at least 2 threads that might help me. Now i have to wait for the test server to be up and running to try out stuff :-)

AM i allowed to post links to other forums here ?
I'd love too, so others can follow the same path ...

Just let me know.

Greetings,

Nils

wysota
30th August 2013, 08:43
AM i allowed to post links to other forums here ?
I'd love too, so others can follow the same path ...

Sure, no problem.

nils_heidorn
30th August 2013, 08:57
Hi !

So here are the links to posts in other forums. I HOPE they will help me, cannot try right now as the test server is not yet up.
Please let me know if you do *not* think that those links will be helpful.

http://qt-project.org/forums/viewthread/11361
http://stackoverflow.com/questions/2599423/how-can-i-post-data-to-a-url-using-qnetworkaccessmanager


Greetings,
Nils

wysota
30th August 2013, 09:03
Basically you should just use QHttpPart class. Just be aware it still requires that you know what you are doing.

nils_heidorn
30th August 2013, 09:06
Hi wysota,
i feared you would say that... I am limited to Qt 4.7.4 and QHttpPart is 4.8...
Argh#&%$§#

;-)

wysota
30th August 2013, 11:23
It doesn't change that much, you still have to know how to craft the form part either way.

nils_heidorn
30th August 2013, 13:05
Hi !
Instead of waiting for our test server i am using this sample web form to play around with file posting:
http://www.cs.tut.fi/~jkorpela/forms/file.html
If you scroll 3 pages down there is a sample cgi that seems to fit my need 100%:
http://www.cs.tut.fi/cgi-bin/run/~jkorpela/echo.cgi

So if i adapt my original curl command from the first post into this:
curl -F "textline=curltest" -F "datafile=@fddtest.fdd" http://www.cs.tut.fi/cgi-bin/run/~jkorpela/echo.cgi
(basically just omitted user/pass and changed parameter name to fit the demo upload site)

It works fine AND by now i have written code that also seems to satisfy that sample site ( I compared in / output with Wireshark).
I may post it here if there are any new "ideas" apart from the links i posted above. (i am using the code from the first link).
If i do NOT have to modify it heavily than i will not post my code version, no need to feed the entropy monster ;-)

Thanks again for putting me on the right track...

Nils

Hi !
Instead of waiting for our test server i am using this sample web form to play around with file posting:
http://www.cs.tut.fi/~jkorpela/forms/file.html
If you scroll 3 pages down there is a sample cgi that seems to fit my need 100%:
http://www.cs.tut.fi/cgi-bin/run/~jkorpela/echo.cgi

So if i adapt my original curl command from the first post into this:
curl -F "textline=curltest" -F "datafile=@fddtest.fdd" http://www.cs.tut.fi/cgi-bin/run/~jkorpela/echo.cgi
(basically just omitted user/pass and changed parameter name to fit the demo upload site)

It works fine AND by now i have written code that also seems to satisfy that sample site ( I compared in / output with Wireshark).
I may post it here if there are any new "ideas" apart from the links i posted above. (i am using the code from the first link).
If i do NOT have to modify it heavily than i will not post my code version, no need to feed the entropy monster ;-)

Thanks again for putting me on the right track...

Nils

Added after 1 28 minutes:

Hi again !
I got it to work completely with a demo upload server (mentioned above).
I added some stuff to the code i found also mentioned above so i post it here if someone needs to do the same stuff.
(Added blocking for async transfer, progress update and error handling).
Of course the response could be too large to display it ina amessagewindow and one could add a shorter timeout when blocking for the request to end, but i do NOT need it and its simple to add,,,
I hope this helps someone, lets see if the stuff also works on that mighty server i REALLY need to feed. If not i'll be back to ask some questions :-)

Nils




//first define the parameters: host, sub Url, <parameter> for file to be uploaded and <parameter> for filename and <
QString host("www.cs.tut.fi");
QString upUrl("/cgi-bin/run/~jkorpela/echo.cgi");
QString upFileName("datafile");
QString upFileText("textline");
QString upFileDescription("QtTest");
QByteArray response;
QBuffer responseBuf(&response);
//pre load the file to be sent, for huge files one would not load it here but give an open file aka QIODevice to the request.
QString exportFName("/Users/dev/eportFile.bin");
QFile exportFile(exportFName);
if(!exportFile.open(QIODevice::ReadOnly))
return;
QByteArray fContents = exportFile.readAll();
exportFile.close();
//file part
QHttp *http = new QHttp(this);
QString boundary = "---------------------------193971182219750";

QByteArray datas(QString("--" + boundary + "\r\n").toAscii());
datas += "Content-Disposition: form-data; name=\""+upFileName+"\"; filename=\""+QFileInfo(exportFName).fileName()+"\"\r\n";
datas += "Content-Type: application/octet-stream\r\n\r\n";

datas += fContents;
datas += "\r\n";
//description part
datas += QString("--" + boundary + "\r\n").toAscii();
datas += "Content-Disposition: form-data; name=\""+upFileText+"\"\r\n\r\n";
datas += upFileDescription+"\r\n";
datas += QString("--" + boundary + "--\r\n").toAscii();

QHttpRequestHeader header("POST", upUrl);
header.setValue("Host", host);
header.setValue("Content-Type", "multipart/form-data; boundary=" + boundary);
header.setValue("Content-Length", QString::number(datas.length()));
http->setHost(host);

QEventLoop loop; // wait & block for transfer to finish for longer files may show an animation or find out how to display progress...
connect(http, SIGNAL(done(bool)), &loop, SLOT(quit()));
connect(http, SIGNAL(dataSendProgress(int,int)), this, SLOT(slotDataSendProgress(int, int))); //optional progress proc
//actually sending & receiving stuff
http->request(header, datas, &responseBuf);
loop.exec();
//checking for error and displaying result if successful
QString resultMsg;
if(http->error() != QHttp::NoError)
resultMsg = tr("An error occured while trying to upload the file: \n")+http->errorString();
else
resultMsg = tr("Successfully transfered file, the response was:\n")+response;
QMessageBox::information(this, tr("web transfer result"), resultMsg);
delete http;

...
//optional progress slot:


void MyStoopidClass::slotDataSendProgress(int done, int total)
{
qDebug() << done << " of " << total;
}