Details
-
Bug
-
Resolution: Out of scope
-
P3: Somewhat important
-
None
-
4.6.3
-
None
-
WINSCW emulator of Symbian^1
Description
Dear Sirs,
please allow me to report an oddity which I have experienced while creating a multithreaded app which uses QNetworkAccessManagers.
After some time, execution terminates with:
210.600 [Qt Message] ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 47c5c8c4. Receiver '' (of type 'QNetworkAccessCache') was created in thread 47c40c54", file qcoreapplication.cpp, line
210.600 [Qt Message] 348
This occurs even though disable caching by setting setCache to NULL AND(!!!)settingb both save and read cache policies to NULL. The relevant class is below:
#include "QtFeedFetcher.h" #include "QtParseAtom.h" #include "QtParseRSS1.h" #include "QtParseRSS2.h" #include <QRegExp> #include <QXmlStreamReader> QtFeedFetcher::QtFeedFetcher(QString _feedURL) {//Runs in MAIN THREAD myFeedURL=_feedURL; myDoneFlag=false; myNWManager=new QNetworkAccessManager(); myNWManager->moveToThread(this); myNWManager->setCache(NULL); connect(myNWManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply *))); } bool QtFeedFetcher::checkDone() {//Runs in MAIN THREAD bool valCache; myDoneFlagMutex.lock(); valCache=myDoneFlag; myDoneFlagMutex.unlock(); return valCache; } QString QtFeedFetcher::checkErr() {//Runs in MAIN THREAD return ""; } void QtFeedFetcher::setUndone() {//Runs in MAIN THREAD myDoneFlagMutex.lock(); myDoneFlag=false; myDoneFlagMutex.unlock(); } void QtFeedFetcher::run() {//Runs in AUXILLIARY THREAD myDoneFlagMutex.lock(); myDoneFlag=false; myDoneFlagMutex.unlock(); myOriginalUrl=myFeedURL; if(myOriginalUrl.isValid()) { QNetworkRequest request; request.setUrl(myOriginalUrl); request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false); //request.setRawHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"); myNWManager->get(request); myNWManager->setCache(NULL); //Run the event loop exec(); } else { qDebug("Invalid URL!"); } } void QtFeedFetcher::replyFinished(QNetworkReply* reply) { /* * Reply is finished! * We'll ask for the reply about the Redirection attribute * http://doc.trolltech.com/qnetworkrequest.html#Attribute-enum */ QVariant possibleRedirectUrl=reply->attribute(QNetworkRequest::RedirectionTargetAttribute); /* We'll deduct if the redirection is valid in the redirectUrl function */ myUrlRedirectedTo = this->redirectUrl(possibleRedirectUrl.toUrl(),myUrlRedirectedTo); /* If the URL is not empty, we're being redirected. */ if(!myUrlRedirectedTo.isEmpty()) { //QString text = QString("QNAMRedirect::replyFinished: Redirected to ").append(myUrlRedirectedTo.toString()); /* We'll do another request to the redirection url. */ QNetworkRequest request; request.setUrl(myUrlRedirectedTo); request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false); myNWManager->get(request); } else { /* * We weren't redirected anymore * so we arrived to the final destination... * * Now we must device whom to feed */ QString readAll=reply->readAll(); QString headerCrappe=reply->header(QNetworkRequest::ContentTypeHeader).toString(); QXmlStreamReader xml; QtParseVirtual* virtualParser=NULL; xml.clear(); xml.addData(readAll); if(readAll.contains(QRegExp("<rss +version\=\"2.0\""))) {//Rss2, tested against http://cyber.law.harvard.edu/rss/examples/rss2sample.xml //qDebug("RSS2"); virtualParser=new QtParseRSS2(&xml); } else if(readAll.contains(QRegExp("<rss +version\=\"0.92\""))) {//Rss2==0.92, tested against http://cyber.law.harvard.edu/rss/examples/sampleRss092.xml //qDebug("RSS0.92"); virtualParser=new QtParseRSS2(&xml); } else if(readAll.contains(QRegExp("<rss +version\=\"0.91\""))) {//Rss2==0.91, tested against http://cyber.law.harvard.edu/rss/examples/sampleRss091.xml //qDebug("RSS0.91"); virtualParser=new QtParseRSS2(&xml); } else if(headerCrappe.contains(QRegExp("application/atom"))) {//atom, tested against http://antone.geckotribe.com/alpha-gecko/categories/arts/poetry/feed/atom/ //qDebug("Atom"); virtualParser=new QtParseAtom(&xml); } else if(readAll.contains(QRegExp("<rdf"))) {//Untested Rss1 crap (not sure if we need it) - only if all others do not match //qDebug("Rss1"); virtualParser=new QtParseRSS1(&xml); } else { //qDebug("No Feed data found."); } if(virtualParser!=NULL) { //qDebug("Directly parsing virtual"); myItems=virtualParser->processMe(); if(myItems.count()==0)goto other_else; } else {//try to parse something //TODO memory leak!!!! other_else: QVector<QtFeedItem*> myAtomItems; QVector<QtFeedItem*> myRSS2Items; virtualParser=new QtParseAtom(&xml); myAtomItems=virtualParser->processMe(); xml.clear(); xml.addData(readAll); virtualParser=new QtParseRSS2(&xml); myRSS2Items=virtualParser->processMe(); if(myRSS2Items.count()>myAtomItems.count()) { myItems=myRSS2Items; } else { myItems=myAtomItems; } } myDoneFlagMutex.lock(); myDoneFlag=true; myDoneFlagMutex.unlock(); delete virtualParser; /* ...so this can be cleared. */ myUrlRedirectedTo.clear(); //TODOdelete reply; quit(); } /* Clean up. */ //reply->deleteLater(); //TODOdelete reply; } QUrl QtFeedFetcher::redirectUrl(QUrl possibleRedirectUrl, QUrl oldRedirectUrl) { QUrl redirectUrl; /* * Check if the URL is empty and * that we aren't being fooled into a infinite redirect loop. * We could also keep track of how many redirects we have been to * and set a limit to it, but we'll leave that to you. */ if(!possibleRedirectUrl.isEmpty() && possibleRedirectUrl != oldRedirectUrl) { redirectUrl = possibleRedirectUrl; } return redirectUrl; }