From 55829ebc5664a65fcef158e7ccd3579aaffa8d20 Mon Sep 17 00:00:00 2001 From: Leonardo Sobral Cunha Date: Mon, 11 May 2009 17:37:37 +0200 Subject: Reset the 'connectedToScene' flag when changing the scene of a view In QGraphicsScene::_q_emitUpdated() the slot QGrpahicsView::updateScene(QList) gets connected and a boolean (connectedToScene) is set to prevent double connections. The problem is that this boolean was not reset when the view gets a new scene. Task-number: 253415 Reviewed-by: andreas --- src/gui/graphicsview/qgraphicsview.cpp | 1 + tests/auto/qgraphicsview/tst_qgraphicsview.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 05e4907..8b133f3 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -1681,6 +1681,7 @@ void QGraphicsView::setScene(QGraphicsScene *scene) disconnect(d->scene, SIGNAL(sceneRectChanged(QRectF)), this, SLOT(updateSceneRect(QRectF))); d->scene->d_func()->views.removeAll(this); + d->connectedToScene = false; } // Assign the new scene and update the contents (scrollbars, etc.)). diff --git a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp index b5af115..db1e4c3 100644 --- a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp @@ -200,6 +200,7 @@ private slots: void task239729_noViewUpdate(); void task239047_fitInViewSmallViewport(); void task245469_itemsAtPointWithClip(); + void task253415_reconnectUpdateSceneOnSceneChanged(); }; void tst_QGraphicsView::initTestCase() @@ -3044,5 +3045,28 @@ void tst_QGraphicsView::centerOnDirtyItem() QCOMPARE(before, after); } +void tst_QGraphicsView::task253415_reconnectUpdateSceneOnSceneChanged() +{ + QGraphicsView view; + QGraphicsView dummyView; + view.setWindowFlags(view.windowFlags() | Qt::WindowStaysOnTopHint); + view.resize(200, 200); + + QGraphicsScene scene1; + QObject::connect(&scene1, SIGNAL(changed(QList)), &dummyView, SLOT(updateScene(QList))); + view.setScene(&scene1); + + QTest::qWait(125); + + QGraphicsScene scene2; + QObject::connect(&scene2, SIGNAL(changed(QList)), &dummyView, SLOT(updateScene(QList))); + view.setScene(&scene2); + + QTest::qWait(125); + + bool wasConnected2 = QObject::disconnect(&scene2, SIGNAL(changed(QList)), &view, 0); + QVERIFY(wasConnected2); +} + QTEST_MAIN(tst_QGraphicsView) #include "tst_qgraphicsview.moc" -- cgit v0.12 From 589dfd480d6158aaa59ab56c8be6a6bfc41da3ef Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Wed, 13 May 2009 12:59:07 +0200 Subject: qdoc: Fixed some qdoc errors. --- doc/src/examples/fancybrowser.qdoc | 14 +++++++------- src/corelib/tools/qhash.cpp | 6 +++--- tools/designer/src/uitools/quiloader.cpp | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/src/examples/fancybrowser.qdoc b/doc/src/examples/fancybrowser.qdoc index ea4da71..631aff9 100644 --- a/doc/src/examples/fancybrowser.qdoc +++ b/doc/src/examples/fancybrowser.qdoc @@ -123,7 +123,7 @@ The first jQuery-based function, \c highlightAllLinks(), is designed to highlight all links in the current webpage. The JavaScript code looks - for web elements named \i {a}, which is the tag for a hyperlink. + for web elements named \e {a}, which is the tag for a hyperlink. For each such element, the background color is set to be yellow by using CSS. @@ -131,18 +131,18 @@ The \c rotateImages() function rotates the images on the current web page. Webkit supports CSS transforms and this JavaScript code - looks up all \i {img} elements and rotates the images 180 degrees + looks up all \e {img} elements and rotates the images 180 degrees and then back again. \snippet examples/webkit/fancybrowser/mainwindow.cpp 9 The remaining four methods remove different elements from the current web page. \c removeGifImages() removes all Gif images on the page by looking up - the \i {src} attribute of all the elements on the web page. Any element with - a \i {gif} file as its source is removed. \c removeInlineFrames() removes all - \i {iframe} or inline elements. \c removeObjectElements() removes all - \i {object} elements, and \c removeEmbeddedElements() removes any elements - such as plugins embedded on the page using the \i {embed} tag. + the \e {src} attribute of all the elements on the web page. Any element with + a \e {gif} file as its source is removed. \c removeInlineFrames() removes all + \e {iframe} or inline elements. \c removeObjectElements() removes all + \e {object} elements, and \c removeEmbeddedElements() removes any elements + such as plugins embedded on the page using the \e {embed} tag. */ diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index b2512e1..6c4a3ba 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -379,8 +379,7 @@ void QHashData::checkSanity() #endif /*! - \fn uint qHash(const QPair &key) - \relates QHash + \ \since 4.3 Returns the hash value for the \a key. @@ -502,7 +501,8 @@ void QHashData::checkSanity() key. With QHash, the items are arbitrarily ordered. \i The key type of a QMap must provide operator<(). The key type of a QHash must provide operator==() and a global - \l{qHash()} {hash} function. + hash function called qHash() (see the related non-member + functions). \endlist Here's an example QHash with QString keys and \c int values: diff --git a/tools/designer/src/uitools/quiloader.cpp b/tools/designer/src/uitools/quiloader.cpp index 548f07e..2a66095 100644 --- a/tools/designer/src/uitools/quiloader.cpp +++ b/tools/designer/src/uitools/quiloader.cpp @@ -572,9 +572,9 @@ void QUiLoaderPrivate::setupWidgetMap() const \class QUiLoader \inmodule QtUiTools - \brief enables standalone applications to dynamically create user - interfaces at run-time using the information stored in .ui files or - specified in plugin paths. + \brief The QUiLoader class enables standalone applications to + dynamically create user interfaces at run-time using the + information stored in .ui files or specified in plugin paths. In addition, you can customize or create your own user interface by deriving your own loader class. -- cgit v0.12 From ad7b21dd57d20cd55774d7a62db117905637e950 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Wed, 13 May 2009 13:44:03 +0200 Subject: qdoc: Fixed some qdoc errors. --- src/corelib/tools/qhash.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index 6c4a3ba..2313e0e 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -379,9 +379,10 @@ void QHashData::checkSanity() #endif /*! - \ + \fn uint qHash(const QPair &key) \since 4.3 - + \relates QHash + Returns the hash value for the \a key. Types \c T1 and \c T2 must be supported by qHash(). -- cgit v0.12 From 4910404284b1bb4fdde89d4fd8a420767ee52069 Mon Sep 17 00:00:00 2001 From: Morten Engvoldsen Date: Wed, 13 May 2009 13:48:13 +0200 Subject: Clearifying docs QSet::insert Chaning the sentence to clearify where the iterator points to. Task-number: 202656 Rev-by: Geir Vattekar --- doc/src/qset.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/qset.qdoc b/doc/src/qset.qdoc index 7fbf97a..afbedc3 100644 --- a/doc/src/qset.qdoc +++ b/doc/src/qset.qdoc @@ -437,7 +437,7 @@ \fn QSet::const_iterator QSet::insert(const T &value) Inserts item \a value into the set, if \a value isn't already - in the set, and returns an iterator positioned at the inserted + in the set, and returns an iterator pointing at the inserted item. \sa operator<<(), remove(), contains() -- cgit v0.12 From 87022c9a4ab00a9faaf6bcdaa8d5884962ccf305 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 13 May 2009 12:25:36 +0200 Subject: Fix handling of garbage data sent by the HTTP server instead of a proper HTTP reply. If the server's reply doesn't start with "HTTP/", then the reply is not valid. This could happen if we connected via HTTP to an HTTPS server. It could also happen with an Icecast server (reply ICY/x.y). Task-number: 248838 Reviewed-by: Markus Goetz --- src/network/access/qhttpnetworkconnection.cpp | 14 +++++++-- src/network/access/qhttpnetworkreply.cpp | 11 ++++++- tests/auto/qnetworkreply/tst_qnetworkreply.cpp | 42 ++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 5940fba..f558f2b 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -529,10 +529,20 @@ void QHttpNetworkConnectionPrivate::receiveReply(QAbstractSocket *socket, QHttpN QHttpNetworkReplyPrivate::ReplyState state = reply ? reply->d_func()->state : QHttpNetworkReplyPrivate::AllDoneState; switch (state) { case QHttpNetworkReplyPrivate::NothingDoneState: - case QHttpNetworkReplyPrivate::ReadingStatusState: - bytes += reply->d_func()->readStatus(socket); + case QHttpNetworkReplyPrivate::ReadingStatusState: { + qint64 statusBytes = reply->d_func()->readStatus(socket); + if (statusBytes == -1) { + // error reading the status, close the socket and emit error + socket->close(); + reply->d_func()->errorString = errorDetail(QNetworkReply::ProtocolFailure, socket); + emit reply->finishedWithError(QNetworkReply::ProtocolFailure, reply->d_func()->errorString); + QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); + break; + } + bytes += statusBytes; channels[i].lastStatus = reply->d_func()->statusCode; break; + } case QHttpNetworkReplyPrivate::ReadingHeaderState: bytes += reply->d_func()->readHeader(socket); if (reply->d_func()->state == QHttpNetworkReplyPrivate::ReadingDataState) { diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index fe3f6af..1b41e1e 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -409,6 +409,9 @@ qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket) if (fragment.endsWith('\r')) { fragment.truncate(fragment.length()-1); } + if (!fragment.startsWith("HTTP/")) + return -1; + parseStatus(fragment); state = ReadingHeaderState; fragment.clear(); // next fragment @@ -418,7 +421,13 @@ qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket) bytes += socket->read(&c, 1); fragment.append(c); } + + // is this a valid reply? + if (fragment.length() >= 5 && !fragment.startsWith("HTTP/")) + return -1; + } + return bytes; } @@ -660,4 +669,4 @@ void QHttpNetworkReply::ignoreSslErrors() QT_END_NAMESPACE -#endif // QT_NO_HTTP \ No newline at end of file +#endif // QT_NO_HTTP diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index 104b788..c97fcf3 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -172,6 +172,8 @@ private Q_SLOTS: void ioGetFromHttpsWithIgnoreSslErrors(); void ioGetFromHttpsWithSslHandshakeError(); #endif + void ioGetFromHttpBrokenServer_data(); + void ioGetFromHttpBrokenServer(); void ioGetWithManyProxies_data(); void ioGetWithManyProxies(); @@ -1887,6 +1889,46 @@ void tst_QNetworkReply::ioGetFromHttpsWithSslHandshakeError() } #endif +void tst_QNetworkReply::ioGetFromHttpBrokenServer_data() +{ + QTest::addColumn("dataToSend"); + QTest::addColumn("doDisconnect"); + + QTest::newRow("no-newline") << QByteArray("Hello World") << false; + QTest::newRow("just-newline") << QByteArray("\r\n") << false; + QTest::newRow("just-2newline") << QByteArray("\r\n\r\n") << false; + QTest::newRow("with-newlines") << QByteArray("Long first line\r\nLong second line") << false; + QTest::newRow("with-newlines2") << QByteArray("\r\nSecond line") << false; + QTest::newRow("with-newlines3") << QByteArray("ICY\r\nSecond line") << false; + + QTest::newRow("empty+disconnect") << QByteArray() << true; + + QTest::newRow("no-newline+disconnect") << QByteArray("Hello World") << true; + QTest::newRow("just-newline+disconnect") << QByteArray("\r\n") << true; + QTest::newRow("just-2newline+disconnect") << QByteArray("\r\n\r\n") << true; + QTest::newRow("with-newlines+disconnect") << QByteArray("Long first line\r\nLong second line") << true; + QTest::newRow("with-newlines2+disconnect") << QByteArray("\r\nSecond line") << true; + QTest::newRow("with-newlines3+disconnect") << QByteArray("ICY\r\nSecond line") << true; +} + +void tst_QNetworkReply::ioGetFromHttpBrokenServer() +{ + QFETCH(QByteArray, dataToSend); + QFETCH(bool, doDisconnect); + MiniHttpServer server(dataToSend); + server.doClose = doDisconnect; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), request.url()); + QVERIFY(reply->error() != QNetworkReply::NoError); +} + void tst_QNetworkReply::ioGetWithManyProxies_data() { QTest::addColumn >("proxyList"); -- cgit v0.12 From a18ebd2a70e83863bc9a8cc64a65791a6d879f02 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 13 May 2009 13:27:01 +0200 Subject: Improve the HTTP status line parsing and catch more errors. There's no need for using QByteArrayMatcher for one single character, so avoid the overhead. Also validate the message header a bit more: we require the status line to start with "HTTP/n.m " where n and m are positive integers less than 10. Task-number: 248838 Reviewed-by: Markus Goetz --- src/network/access/qhttpnetworkreply.cpp | 58 ++++++++++++++++---------- src/network/access/qhttpnetworkreply_p.h | 2 +- tests/auto/qnetworkreply/tst_qnetworkreply.cpp | 7 ++++ 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index 1b41e1e..69e0a4c 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -409,12 +409,12 @@ qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket) if (fragment.endsWith('\r')) { fragment.truncate(fragment.length()-1); } - if (!fragment.startsWith("HTTP/")) - return -1; - - parseStatus(fragment); + bool ok = parseStatus(fragment); state = ReadingHeaderState; fragment.clear(); // next fragment + + if (!ok) + return -1; break; } else { c = 0; @@ -431,26 +431,40 @@ qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket) return bytes; } -void QHttpNetworkReplyPrivate::parseStatus(const QByteArray &status) +bool QHttpNetworkReplyPrivate::parseStatus(const QByteArray &status) { - const QByteArrayMatcher sp(" "); - int i = sp.indexIn(status); - const QByteArray version = status.mid(0, i); - int j = sp.indexIn(status, i + 1); + // from RFC 2616: + // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF + // HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT + // that makes: 'HTTP/n.n xxx Message' + // byte count: 0123456789012 + + static const int minLength = 11; + static const int dotPos = 6; + static const int spacePos = 8; + static const char httpMagic[] = "HTTP/"; + + if (status.length() < minLength + || !status.startsWith(httpMagic) + || status.at(dotPos) != '.' + || status.at(spacePos) != ' ') { + // I don't know how to parse this status line + return false; + } + + // optimize for the valid case: defer checking until the end + majorVersion = status.at(dotPos - 1) - '0'; + minorVersion = status.at(dotPos + 1) - '0'; + + int i = spacePos; + int j = status.indexOf(' ', i + 1); // j == -1 || at(j) == ' ' so j+1 == 0 && j+1 <= length() const QByteArray code = status.mid(i + 1, j - i - 1); - const QByteArray reason = status.mid(j + 1, status.count() - j); - - const QByteArrayMatcher slash("/"); - int k = slash.indexIn(version); - const QByteArrayMatcher dot("."); - int l = dot.indexIn(version, k); - const QByteArray major = version.mid(k + 1, l - k - 1); - const QByteArray minor = version.mid(l + 1, version.count() - l); - - majorVersion = QString::fromAscii(major.constData()).toInt(); - minorVersion = QString::fromAscii(minor.constData()).toInt(); - statusCode = QString::fromAscii(code.constData()).toInt(); - reasonPhrase = QString::fromAscii(reason.constData()); + + bool ok; + statusCode = code.toInt(&ok); + reasonPhrase = QString::fromLatin1(status.constData() + j + 1); + + return ok && uint(majorVersion) <= 9 && uint(minorVersion) <= 9; } qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket) diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index c17c65c..cb4d34f 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -154,7 +154,7 @@ public: QHttpNetworkReplyPrivate(const QUrl &newUrl = QUrl()); ~QHttpNetworkReplyPrivate(); qint64 readStatus(QAbstractSocket *socket); - void parseStatus(const QByteArray &status); + bool parseStatus(const QByteArray &status); qint64 readHeader(QAbstractSocket *socket); void parseHeader(const QByteArray &header); qint64 readBody(QAbstractSocket *socket, QIODevice *out); diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index c97fcf3..4be0863 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -1900,6 +1900,9 @@ void tst_QNetworkReply::ioGetFromHttpBrokenServer_data() QTest::newRow("with-newlines") << QByteArray("Long first line\r\nLong second line") << false; QTest::newRow("with-newlines2") << QByteArray("\r\nSecond line") << false; QTest::newRow("with-newlines3") << QByteArray("ICY\r\nSecond line") << false; + QTest::newRow("invalid-version") << QByteArray("HTTP/123 200 \r\n") << false; + QTest::newRow("invalid-version2") << QByteArray("HTTP/a.\033 200 \r\n") << false; + QTest::newRow("invalid-reply-code") << QByteArray("HTTP/1.0 fuu \r\n") << false; QTest::newRow("empty+disconnect") << QByteArray() << true; @@ -1909,6 +1912,10 @@ void tst_QNetworkReply::ioGetFromHttpBrokenServer_data() QTest::newRow("with-newlines+disconnect") << QByteArray("Long first line\r\nLong second line") << true; QTest::newRow("with-newlines2+disconnect") << QByteArray("\r\nSecond line") << true; QTest::newRow("with-newlines3+disconnect") << QByteArray("ICY\r\nSecond line") << true; + + QTest::newRow("invalid-version+disconnect") << QByteArray("HTTP/123 200 ") << true; + QTest::newRow("invalid-version2+disconnect") << QByteArray("HTTP/a.\033 200 ") << true; + QTest::newRow("invalid-reply-code+disconnect") << QByteArray("HTTP/1.0 fuu ") << true; } void tst_QNetworkReply::ioGetFromHttpBrokenServer() -- cgit v0.12