diff options
-rw-r--r-- | doc/src/examples/fancybrowser.qdoc | 14 | ||||
-rw-r--r-- | doc/src/qset.qdoc | 2 | ||||
-rw-r--r-- | src/corelib/tools/qhash.cpp | 7 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsview.cpp | 1 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkconnection.cpp | 14 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkreply.cpp | 61 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkreply_p.h | 2 | ||||
-rw-r--r-- | tests/auto/qgraphicsview/tst_qgraphicsview.cpp | 24 | ||||
-rw-r--r-- | tests/auto/qnetworkreply/tst_qnetworkreply.cpp | 49 | ||||
-rw-r--r-- | tools/designer/src/uitools/quiloader.cpp | 6 |
10 files changed, 144 insertions, 36 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/doc/src/qset.qdoc b/doc/src/qset.qdoc index 9795123..2d12661 100644 --- a/doc/src/qset.qdoc +++ b/doc/src/qset.qdoc @@ -447,7 +447,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() diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index b2512e1..2313e0e 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -380,9 +380,9 @@ void QHashData::checkSanity() /*! \fn uint qHash(const QPair<T1, T2> &key) - \relates QHash \since 4.3 - + \relates QHash + Returns the hash value for the \a key. Types \c T1 and \c T2 must be supported by qHash(). @@ -502,7 +502,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/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 2876016..5e33896 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -1691,6 +1691,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/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index af0ac84..d4bf008 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -586,10 +586,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 4485485..310994c 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -409,39 +409,62 @@ qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket) if (fragment.endsWith('\r')) { fragment.truncate(fragment.length()-1); } - parseStatus(fragment); + bool ok = parseStatus(fragment); state = ReadingHeaderState; fragment.clear(); // next fragment + + if (!ok) + return -1; break; } else { c = 0; bytes += socket->read(&c, 1); fragment.append(c); } + + // is this a valid reply? + if (fragment.length() >= 5 && !fragment.startsWith("HTTP/")) + return -1; + } + 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 238a1da..cc5cce8 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/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp index bb61f90..920cba7 100644 --- a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp @@ -204,6 +204,7 @@ private slots: void task239729_noViewUpdate(); void task239047_fitInViewSmallViewport(); void task245469_itemsAtPointWithClip(); + void task253415_reconnectUpdateSceneOnSceneChanged(); }; void tst_QGraphicsView::initTestCase() @@ -3200,5 +3201,28 @@ void tst_QGraphicsView::mouseTracking2() QCOMPARE(spy.count(), 1); } +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<QRectF>)), &dummyView, SLOT(updateScene(QList<QRectF>))); + view.setScene(&scene1); + + QTest::qWait(125); + + QGraphicsScene scene2; + QObject::connect(&scene2, SIGNAL(changed(QList<QRectF>)), &dummyView, SLOT(updateScene(QList<QRectF>))); + view.setScene(&scene2); + + QTest::qWait(125); + + bool wasConnected2 = QObject::disconnect(&scene2, SIGNAL(changed(QList<QRectF>)), &view, 0); + QVERIFY(wasConnected2); +} + QTEST_MAIN(tst_QGraphicsView) #include "tst_qgraphicsview.moc" diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index a8ba36f..6c622f7 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -183,6 +183,8 @@ private Q_SLOTS: void ioGetFromHttpsWithIgnoreSslErrors(); void ioGetFromHttpsWithSslHandshakeError(); #endif + void ioGetFromHttpBrokenServer_data(); + void ioGetFromHttpBrokenServer(); void ioGetWithManyProxies_data(); void ioGetWithManyProxies(); @@ -2041,6 +2043,53 @@ void tst_QNetworkReply::ioGetFromHttpsWithSslHandshakeError() } #endif +void tst_QNetworkReply::ioGetFromHttpBrokenServer_data() +{ + QTest::addColumn<QByteArray>("dataToSend"); + QTest::addColumn<bool>("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("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; + + 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; + + 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() +{ + 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<QList<QNetworkProxy> >("proxyList"); 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. |