diff options
-rw-r--r-- | .qmake.conf | 2 | ||||
-rw-r--r-- | examples/websockets/sslechoserver/sslechoserver.h | 2 | ||||
-rw-r--r-- | src/websockets/doc/qtwebsockets.qdocconf | 2 | ||||
-rw-r--r-- | src/websockets/qwebsocket_p.cpp | 67 | ||||
-rw-r--r-- | src/websockets/qwebsockethandshakeresponse_p.h | 4 | ||||
-rw-r--r-- | src/websockets/qwebsocketserver.cpp | 38 | ||||
-rw-r--r-- | src/websockets/qwebsocketserver.h | 1 | ||||
-rw-r--r-- | src/websockets/qwebsocketserver_p.cpp | 5 | ||||
-rw-r--r-- | src/websockets/websockets.pro | 2 | ||||
-rw-r--r-- | tests/auto/dataprocessor/tst_dataprocessor.cpp | 1 | ||||
-rw-r--r-- | tests/auto/qwebsocketserver/tst_qwebsocketserver.cpp | 16 |
11 files changed, 96 insertions, 44 deletions
diff --git a/.qmake.conf b/.qmake.conf index e2217eb..cc1234c 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -3,4 +3,4 @@ load(qt_build_config) CONFIG += qt_example_installs CONFIG += warning_clean -MODULE_VERSION = 5.3.1 +MODULE_VERSION = 5.4.0 diff --git a/examples/websockets/sslechoserver/sslechoserver.h b/examples/websockets/sslechoserver/sslechoserver.h index 84dfeab..f4e9a9b 100644 --- a/examples/websockets/sslechoserver/sslechoserver.h +++ b/examples/websockets/sslechoserver/sslechoserver.h @@ -56,8 +56,6 @@ public: explicit SslEchoServer(quint16 port, QObject *parent = Q_NULLPTR); virtual ~SslEchoServer(); -Q_SIGNALS: - private Q_SLOTS: void onNewConnection(); void processTextMessage(QString message); diff --git a/src/websockets/doc/qtwebsockets.qdocconf b/src/websockets/doc/qtwebsockets.qdocconf index db1553d..5358450 100644 --- a/src/websockets/doc/qtwebsockets.qdocconf +++ b/src/websockets/doc/qtwebsockets.qdocconf @@ -27,7 +27,7 @@ qhp.QtWebSockets.subprojects.classes.sortPages = true qhp.QtWebSockets.subprojects.qml.title = QML Types qhp.QtWebSockets.subprojects.qml.indexTitle = Qt WebSockets QML Types -qhp.QtWebSockets.subprojects.qml.selectors = fake:qmlclass +qhp.QtWebSockets.subprojects.qml.selectors = qmlclass qhp.QtWebSockets.subprojects.qml.sortPages = true qhp.QtWebSockets.subprojects.examples.title = Examples diff --git a/src/websockets/qwebsocket_p.cpp b/src/websockets/qwebsocket_p.cpp index 18962ff..385ae71 100644 --- a/src/websockets/qwebsocket_p.cpp +++ b/src/websockets/qwebsocket_p.cpp @@ -848,6 +848,45 @@ QString readLine(QTcpSocket *pSocket) return line; } +// this function is a copy of QHttpNetworkReplyPrivate::parseStatus +static bool parseStatusLine(const QByteArray &status, int *majorVersion, int *minorVersion, + int *statusCode, QString *reasonPhrase) +{ + // 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); + + bool ok; + *statusCode = code.toInt(&ok); + *reasonPhrase = QString::fromLatin1(status.constData() + j + 1); + + return ok && uint(*majorVersion) <= 9 && uint(* minorVersion) <= 9; +} + + //called on the client for a server handshake response /*! \internal @@ -861,25 +900,13 @@ void QWebSocketPrivate::processHandshake(QTcpSocket *pSocket) bool ok = false; QString errorDescription; - const QString regExpStatusLine(QStringLiteral("^(HTTP/[0-9]+\\.[0-9]+)\\s([0-9]+)\\s(.*)")); - const QRegularExpression regExp(regExpStatusLine); - const QString statusLine = readLine(pSocket); - QString httpProtocol; + const QByteArray statusLine = pSocket->readLine(); + int httpMajorVersion, httpMinorVersion; int httpStatusCode; QString httpStatusMessage; - const QRegularExpressionMatch match = regExp.match(statusLine); - if (Q_LIKELY(match.hasMatch())) { - QStringList tokens = match.capturedTexts(); - tokens.removeFirst(); //remove the search string - if (tokens.length() == 3) { - httpProtocol = tokens[0]; - httpStatusCode = tokens[1].toInt(); - httpStatusMessage = tokens[2].trimmed(); - ok = true; - } - } - if (Q_UNLIKELY(!ok)) { - errorDescription = QWebSocket::tr("Invalid statusline in response: %1.").arg(statusLine); + if (Q_UNLIKELY(!parseStatusLine(statusLine, &httpMajorVersion, &httpMinorVersion, + &httpStatusCode, &httpStatusMessage))) { + errorDescription = QWebSocket::tr("Invalid statusline in response: %1.").arg(QString::fromLatin1(statusLine)); } else { QString headerLine = readLine(pSocket); QMap<QString, QString> headers; @@ -906,11 +933,9 @@ void QWebSocketPrivate::processHandshake(QTcpSocket *pSocket) if (Q_LIKELY(httpStatusCode == 101)) { //HTTP/x.y 101 Switching Protocols - bool conversionOk = false; - const float version = httpProtocol.midRef(5).toFloat(&conversionOk); //TODO: do not check the httpStatusText right now ok = !(acceptKey.isEmpty() || - (!conversionOk || (version < 1.1f)) || + (httpMajorVersion < 1 || httpMinorVersion < 1) || (upgrade.toLower() != QStringLiteral("websocket")) || (connection.toLower() != QStringLiteral("upgrade"))); if (ok) { @@ -923,7 +948,7 @@ void QWebSocketPrivate::processHandshake(QTcpSocket *pSocket) } else { errorDescription = QWebSocket::tr("QWebSocketPrivate::processHandshake: Invalid statusline in response: %1.") - .arg(statusLine); + .arg(QString::fromLatin1(statusLine)); } } else if (httpStatusCode == 400) { //HTTP/1.1 400 Bad Request diff --git a/src/websockets/qwebsockethandshakeresponse_p.h b/src/websockets/qwebsockethandshakeresponse_p.h index 030d26f..bc98af2 100644 --- a/src/websockets/qwebsockethandshakeresponse_p.h +++ b/src/websockets/qwebsockethandshakeresponse_p.h @@ -86,10 +86,6 @@ public: QWebSocketProtocol::CloseCode error() const; QString errorString() const; -public Q_SLOTS: - -Q_SIGNALS: - private: bool m_isValid; bool m_canUpgrade; diff --git a/src/websockets/qwebsocketserver.cpp b/src/websockets/qwebsocketserver.cpp index 20aa009..2d8f26b 100644 --- a/src/websockets/qwebsocketserver.cpp +++ b/src/websockets/qwebsocketserver.cpp @@ -495,6 +495,44 @@ quint16 QWebSocketServer::serverPort() const } /*! + Returns a URL clients can use to connect to this server if the server is listening for connections. + Otherwise an invalid URL is returned. + + \sa serverPort(), serverAddress(), listen() + */ +QUrl QWebSocketServer::serverUrl() const +{ + QUrl url; + + if (!isListening()) { + return url; + } + + switch (secureMode()) { + case NonSecureMode: + url.setScheme(QStringLiteral("ws")); + break; + #ifndef QT_NO_SSL + case SecureMode: + url.setScheme(QStringLiteral("wss")); + break; + #endif + } + + url.setPort(serverPort()); + + if (serverAddress() == QHostAddress(QHostAddress::Any)) { + // NOTE: On Windows at least, clients cannot connect to QHostAddress::Any + // so in that case we always return LocalHost instead. + url.setHost(QHostAddress(QHostAddress::LocalHost).toString()); + } else { + url.setHost(serverAddress().toString()); + } + + return url; +} + +/*! Sets the maximum number of pending accepted connections to \a numConnections. WebSocketServer will accept no more than \a numConnections incoming connections before nextPendingConnection() is called. diff --git a/src/websockets/qwebsocketserver.h b/src/websockets/qwebsocketserver.h index 1f89ca9..4e76cd4 100644 --- a/src/websockets/qwebsocketserver.h +++ b/src/websockets/qwebsocketserver.h @@ -90,6 +90,7 @@ public: quint16 serverPort() const; QHostAddress serverAddress() const; + QUrl serverUrl() const; SslMode secureMode() const; diff --git a/src/websockets/qwebsocketserver_p.cpp b/src/websockets/qwebsocketserver_p.cpp index 70bc5da..17cb565 100644 --- a/src/websockets/qwebsocketserver_p.cpp +++ b/src/websockets/qwebsocketserver_p.cpp @@ -407,12 +407,10 @@ void QWebSocketServerPrivate::onCloseConnection() void QWebSocketServerPrivate::handshakeReceived() { if (Q_UNLIKELY(!currentSender)) { - qWarning() << QWebSocketServer::tr("Sender is NULL. This is a Qt bug."); return; } QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(currentSender->sender); if (Q_UNLIKELY(!pTcpSocket)) { - qWarning() << QWebSocketServer::tr("Sender is not a QTcpSocket. This is a Qt bug!!!"); return; } //When using Google Chrome the handshake in received in two parts. @@ -434,8 +432,6 @@ void QWebSocketServerPrivate::handshakeReceived() if (m_pendingConnections.length() >= maxPendingConnections()) { pTcpSocket->close(); pTcpSocket->deleteLater(); - qWarning() << QWebSocketServer::tr("Too many pending connections: " \ - "New WebSocket connection not accepted."); setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection, QWebSocketServer::tr("Too many pending connections.")); return; @@ -483,7 +479,6 @@ void QWebSocketServerPrivate::handshakeReceived() } } if (!success) { - qWarning() << QWebSocketServer::tr("Closing socket because of invalid or unsupported request."); pTcpSocket->close(); } } diff --git a/src/websockets/websockets.pro b/src/websockets/websockets.pro index 99e84b6..5b5ff78 100644 --- a/src/websockets/websockets.pro +++ b/src/websockets/websockets.pro @@ -1,7 +1,7 @@ load(qt_build_config) TARGET = QtWebSockets -QT = core network core-private sql +QT = core network core-private TEMPLATE = lib diff --git a/tests/auto/dataprocessor/tst_dataprocessor.cpp b/tests/auto/dataprocessor/tst_dataprocessor.cpp index a63193a..de9b7a3 100644 --- a/tests/auto/dataprocessor/tst_dataprocessor.cpp +++ b/tests/auto/dataprocessor/tst_dataprocessor.cpp @@ -53,7 +53,6 @@ const quint8 FIN = 0x80; const quint8 RSV1 = 0x40; const quint8 RSV2 = 0x30; const quint8 RSV3 = 0x10; -const quint8 MASK = 0x80; QT_USE_NAMESPACE diff --git a/tests/auto/qwebsocketserver/tst_qwebsocketserver.cpp b/tests/auto/qwebsocketserver/tst_qwebsocketserver.cpp index 2e2dcd6..78e7041 100644 --- a/tests/auto/qwebsocketserver/tst_qwebsocketserver.cpp +++ b/tests/auto/qwebsocketserver/tst_qwebsocketserver.cpp @@ -147,6 +147,7 @@ void tst_QWebSocketServer::tst_initialisation() QCOMPARE(server.supportedVersions().count(), 1); QCOMPARE(server.supportedVersions().at(0), QWebSocketProtocol::VersionLatest); QCOMPARE(server.supportedVersions().at(0), QWebSocketProtocol::Version13); + QCOMPARE(server.serverUrl(), QUrl()); } { @@ -254,9 +255,11 @@ void tst_QWebSocketServer::tst_connectivity() QSignalSpy socketConnectedSpy(&socket, SIGNAL(connected())); QVERIFY(server.listen()); + QCOMPARE(server.serverAddress(), QHostAddress(QHostAddress::Any)); + QCOMPARE(server.serverUrl(), QUrl(QStringLiteral("ws://") + QHostAddress(QHostAddress::LocalHost).toString() + + QStringLiteral(":").append(QString::number(server.serverPort())))); - socket.open(QStringLiteral("ws://") + QHostAddress(QHostAddress::LocalHost).toString() + - QStringLiteral(":").append(QString::number(server.serverPort()))); + socket.open(server.serverUrl().toString()); if (socketConnectedSpy.count() == 0) QVERIFY(socketConnectedSpy.wait()); @@ -305,23 +308,20 @@ void tst_QWebSocketServer::tst_maxPendingConnections() QVERIFY(server.listen()); - socket1.open(QStringLiteral("ws://") + QHostAddress(QHostAddress::LocalHost).toString() + - QStringLiteral(":").append(QString::number(server.serverPort()))); + socket1.open(server.serverUrl().toString()); if (socket1ConnectedSpy.count() == 0) QVERIFY(socket1ConnectedSpy.wait()); QCOMPARE(socket1.state(), QAbstractSocket::ConnectedState); QCOMPARE(serverConnectionSpy.count(), 1); QCOMPARE(corsAuthenticationSpy.count(), 1); - socket2.open(QStringLiteral("ws://") + QHostAddress(QHostAddress::LocalHost).toString() + - QStringLiteral(":").append(QString::number(server.serverPort()))); + socket2.open(server.serverUrl().toString()); if (socket2ConnectedSpy.count() == 0) QVERIFY(socket2ConnectedSpy.wait()); QCOMPARE(socket2.state(), QAbstractSocket::ConnectedState); QCOMPARE(serverConnectionSpy.count(), 2); QCOMPARE(corsAuthenticationSpy.count(), 2); - socket3.open(QStringLiteral("ws://") + server.serverAddress().toString() + - QStringLiteral(":").append(QString::number(server.serverPort()))); + socket3.open(server.serverUrl().toString()); if (socket3ConnectedSpy.count() == 0) QVERIFY(!socket3ConnectedSpy.wait(250)); QCOMPARE(socket3.state(), QAbstractSocket::UnconnectedState); |