PDA

View Full Version : QHttp related



whoops.slo
15th June 2006, 15:54
I have set a function that goes through the database. from it it collect url's and download the files. at some url's i get a response "Host XYZ not found" and the function does not work anymore (the function is called from a loop that goes from the first record to the last) - the QHttp get() does not work any more. the function start workiing again if i start it manually from button on the GUI. What is the difference betwet calling a function from the loop and from the GUI?
Regards;
Luka

jacek
15th June 2006, 16:03
What is the difference betwet calling a function from the loop and from the GUI?
None, if you have a single thread. Maybe there's something wrong with your application's logic? How many QHttp objects do you have?

whoops.slo
15th June 2006, 22:00
Here is the code of the app.:
void polje::skoci() {

int i = 0;
bool bOk;
QString str = ui.t_1->text();
int st = str.toInt(&bOk) + 1;

//write new number into textfield t_1
ui.t_1->setText(QString::number(st));

//define http path = in this example i'm using static URL, in the real case
//it is collected from database
//the URL below is the one making problems... <=host not found since it does not exist, but the loop end and I can not start it
QUrl urlt("http://www.anabanana.brb/");

//the URL below has corect host address, but the file is missing - responseHeader code 404
// QUrl urlt("http://www.bubi.si/luka.html");
//the URL below is correct, just to test if the app. work
// QUrl urlt("http://www.google.com/");

//define the path to the file into which we will write the contend of the page
QDir pot(qApp->applicationDirPath());
if(!pot.exists("html")) {
pot.mkdir("html");
}
file = new QFile("html/blog_" + QString::number(st) + ".html");
if (!file->open(QIODevice::WriteOnly)) {
QMessageBox::critical(this, "Napaka", "Ne morem odpreti datoteke.");
delete file;
return;
}

//open the connection and download the content of the page
//into the file specified
http->setHost(urlt.host());
httpGetId = http->get(urlt.path(), file);

}

void polje::httpRequestFinished(int requestId, bool error) {

if (requestId != httpGetId)
return;

//we close the specific file
file->close();

if (error) {
//insert the error string into textfield t_2
//just to find out what the error is
ui.t_2->insertPlainText("\n" + ui.t_1->text() + ": " + http->errorString());
}
else {
bool bOk;
QString str = ui.t_1->text();
int st = str.toInt(&bOk) + 1;
if (st <= 10) {
skoci();
}
}
}

void polje::readResponseHeader(const QHttpResponseHeader &responseHeader) {

ui.t_2->insertPlainText("\n" + ui.t_1->text() + ": " + QString::number(responseHeader.statusCode()));

}

I have defined QHttp and the rest of undefined variables in the header file in the private section:
QHttp *http;
QFile *file;
int httpGetId;
Can anybody find the explanation and perhaps even the solution? Thank you!

Regards;
Luka

jacek
15th June 2006, 22:29
Well... I don't see any loop here. Anyway in case of an error you land here:
if (error) {
//insert the error string into textfield t_2
//just to find out what the error is
ui.t_2->insertPlainText("\n" + ui.t_1->text() + ": " + http->errorString());
}
Could you explain what do you want to do then? What do you mean by "the loop end and I can not start it"?

One more thing: IMO it would be better to change:
if (st <= 10) {
skoci();
}to
if (st <= 10) {
QTimer::singleShot( 0, this, SLOT( skoci() ) );
}This way QHttp will have time to clean up itself after emitting requestFinished() signal.

whoops.slo
15th June 2006, 23:07
thanks for noticing that. it was my mistake, when i rewrite the code to make it clearer and to show just where my problem is i forgot to insert a lass to skoci() function...

if (error) {
//insert the error string into textfield t_2
//just to find out what the error is
ui.t_2->insertPlainText("\n" + ui.t_1->text() + ": " + http->errorString());
skoci();
}
else {
bool bOk;
QString str = ui.t_1->text();
int st = str.toInt(&bOk) + 1;
if (st <= 10) {
skoci();
}
}
As far as I understand QHttp mechanism (am a beginner at it) when a get() is finished a requestFinished() signal is send. I have connected requestFinished() with httpRequestFinished() and responseHeaderReceived() with readResponseHeader()... Therefor when get() finish the httpRequestFinished() is called. At that point I call again the function skoci() and repeat this 10 times. It works with second and third URL (responseHeaderRecieved codes 404 and 200, but with the first one I do not get a responseHeaderReceived() since the host does not exist. In return I get an error, but when I try to call skoci() function from that error I call it but the get() is not called again...
Timer::SingleShot() does not work in this contect - the second time the function skoci() is not called!
There is obiously something wrong with my aproach to this problem, but I can not find where I made a mistake...

Regards, Luka

jacek
16th June 2006, 00:11
It works with second and third URL (responseHeaderRecieved codes 404 and 200, but with the first one I do not get a responseHeaderReceived() since the host does not exist. In return I get an error, but when I try to call skoci() function from that error I call it but the get() is not called again...
Do you change the host after the error has occured?

Add this at the beginning of httpRequestFinished():
qDebug() << httpGetId << requestId << error;and this at the end of skoci():
qDebug() << urlt.host() << httpGetId; to see what's happening (don't forget about #include <QtDebug>).


Timer::SingleShot() does not work in this contect - the second time the function skoci() is not called!
Is that skoci() method a slot? Anyway you can forget about QTimer as QHttp is reentrant, so you can safely invoke setHost() and get() whenever you want.

whoops.slo
16th June 2006, 16:35
skoci() is not a slot - at least it was not meant to be...

I try what you suggest - qDebbug(). I am using Win XP, CodeBlock, MinGW and GDB and am new with debbugers. Therefor I can not understand what I should read from it (perhaps I have some setting set incorrectly). If you or somebody else have time and will to teach me how to set debbuger in this enviroment I would be most greatefull, since than I could at least look into what my app. is actually working :)

Thanks anyway for your help, I hope you can help me further, but if it is a lost case than... I will understand :)

Regards,
Luka

jacek
16th June 2006, 17:19
skoci() is not a slot - at least it was not meant to be...
That explains why the trick with QTimer didn't work.


I am using Win XP, CodeBlock, MinGW and GDB and am new with debbugers. Therefor I can not understand what I should read from it
Under windows you must add "CONFIG += console" to your .pro file to see the qDebug() output. Although debugger should be able to intercept these messages without it. Unfortunately I don't do much development under windows, so I can't help you with it.

whoops.slo
19th June 2006, 10:17
I was not able to get anything from the debugger. Instead I put requested strigns to be send to the textbox. This is the response I got from using host, that do not exist:

2
2, 1
2, 2
1: Host www.anabanana.brb not found
5
And this is from the one that exist (The "loop" run 5 times):

2
2, 1
1: 200
2, 2
4
4, 3
2: 200
4, 4
6
6, 5
3: 200
6, 6
8
8, 7
4: 200
8, 8
10
10, 9
5: 200
10, 10
I put the line below at the end of the skoci():

ui.t_2->insertPlainText("\n" + QString::number(httpGetId));
and the line below at the beggining of httpRequestFinished():

ui.t_2->insertPlainText("\n" + QString::number(httpGetId) + ", " + QString::number(requestId));
Can this help?
Regards, Luka

jacek
19th June 2006, 16:27
What happens when you change skoci() like this?

http->setHost( "localhost" ); // added
http->setHost( urlt.host() );
httpGetId = http->get( urlt.path(), file );

whoops.slo
20th June 2006, 07:38
I get the same responce:
3
3, 1
3, 2
3, 3
6

I'll try something else... Before I call GET() I will check for ERROR(). If ERROR() is HostNotFound than GET() will not be called...

jacek
20th June 2006, 15:44
I get the same responce
I've made a little experiment:
#include <QApplication>
#include <QHttp>

class Test : public QObject
{
Q_OBJECT
public:
Test() : QObject( 0 )
{
_http = new QHttp( "www.xxx.zzz", 80, this );
connect( _http, SIGNAL( readyRead( const QHttpResponseHeader & ) ), this, SLOT( read( const QHttpResponseHeader & ) ) );
connect( _http, SIGNAL( requestFinished( int, bool )), this, SLOT( finished( int, bool ) ) );
connect( _http, SIGNAL( done(bool) ), this, SLOT( done(bool) ) );
start();
};

private slots:
void start()
{
int id = _http->get( "/" );
qWarning( "start id=%d", id );
}

void done( bool error )
{
qWarning("done: %d", error );
qWarning("error: %s", qPrintable( _http->errorString() ) );
// start();
}
void finished( int id, bool error )
{
qWarning("finished: %d %d ", id, error );
start();
}

void read( const QHttpResponseHeader& header )
{
qWarning( "code: %d, reason: %s", header.statusCode(), qPrintable( header.reasonPhrase() ) );
qWarning( _http->readAll() );
}

private:
QHttp *_http;

};

int main( int argc, char **argv )
{
QApplication app( argc, argv );
Test t;
return app.exec();
}

#include "main.moc"

and got this:
$ ./http
start id=1
finished: 1 1
start id=2
done: 1
error: Host www.xxx.zzz not found
Note that after the second request is started ("start id=2") done() slot is immediately called (with error == true), so it seems that you just start the new request too early.

There's even and example in the docs:
For example, if you have the following sequence of requests
http->setHost("www.foo.bar"); // id == 1
http->get("/index.html"); // id == 2
http->post("register.html", data); // id == 3
and the get() request fails because the host lookup fails, then the post() request is never executed and the signals would look like this:
requestStarted(1)
requestFinished(1, false)

requestStarted(2)
stateChanged(HostLookup)
requestFinished(2, true)

done(true)

stateChanged(Unconnected)But it isn't obvious that this is exactly the same case as in your program.

If you comment out the call to start() in finished() slot and uncomment the one in done(), QHttp will process requests continuously.

whoops.slo
20th June 2006, 21:57
Thank you for your time! You were correct, the new request was send too early. The example you wrote is just what I needed!

Thank you again! Regards;
Luka