Commit 6ce818a1 authored by Aleksey Lysenko's avatar Aleksey Lysenko Committed by Lars Schmertmann
Browse files

Add a function to hand off a tcp socket to the websocket server


This method allows a listening port to process connections with
different protocols.  It lets the websocket server handle a TCP
socket, upgrading it to a websocket

[ChangeLog][QWebSocketServer] Add support to handle external QTcpSocket

Done-with: André Klitzing <aklitzing@gmail.com>
Task-number: QTBUG-54276
Change-Id: Ia36b481dc87d6f3806e9f1e61e75e528640f1937
Reviewed-by: default avatarTimur Pocheptsov <timur.pocheptsov@qt.io>
parent dfc91928
No related merge requests found
Showing with 69 additions and 11 deletions
......@@ -612,4 +612,18 @@ QList<QWebSocketProtocol::Version> QWebSocketServer::supportedVersions() const
return d->supportedVersions();
}
/*!
Upgrades a tcp \a socket to websocket.
The QWebSocketServer object will take ownership of the socket
object and delete it when appropriate.
\since 5.9
*/
void QWebSocketServer::handleConnection(QTcpSocket *socket) const
{
Q_D(const QWebSocketServer);
d->handleConnection(socket);
}
QT_END_NAMESPACE
......@@ -54,6 +54,7 @@
QT_BEGIN_NAMESPACE
class QTcpSocket;
class QWebSocketServerPrivate;
class QWebSocket;
class QWebSocketCorsAuthenticator;
......@@ -118,6 +119,8 @@ public:
QList<QWebSocketProtocol::Version> supportedVersions() const;
void handleConnection(QTcpSocket *socket) const;
Q_SIGNALS:
void acceptError(QAbstractSocket::SocketError socketError);
void serverError(QWebSocketProtocol::CloseCode closeCode);
......
......@@ -384,17 +384,8 @@ void QWebSocketServerPrivate::setError(QWebSocketProtocol::CloseCode code, const
*/
void QWebSocketServerPrivate::onNewConnection()
{
while (m_pTcpServer->hasPendingConnections()) {
QTcpSocket *pTcpSocket = m_pTcpServer->nextPendingConnection();
//use a queued connection because a QSslSocket
//needs the event loop to process incoming data
//if not queued, data is incomplete when handshakeReceived is called
QObjectPrivate::connect(pTcpSocket, &QTcpSocket::readyRead,
this, &QWebSocketServerPrivate::handshakeReceived,
Qt::QueuedConnection);
QObjectPrivate::connect(pTcpSocket, &QTcpSocket::disconnected,
this, &QWebSocketServerPrivate::onSocketDisconnected);
}
while (m_pTcpServer->hasPendingConnections())
handleConnection(m_pTcpServer->nextPendingConnection());
}
/*!
......@@ -491,4 +482,17 @@ void QWebSocketServerPrivate::handshakeReceived()
}
}
void QWebSocketServerPrivate::handleConnection(QTcpSocket *pTcpSocket) const
{
if (Q_LIKELY(pTcpSocket)) {
// Use a queued connection because a QSslSocket needs the event loop to process incoming
// data. If not queued, data is incomplete when handshakeReceived is called.
QObjectPrivate::connect(pTcpSocket, &QTcpSocket::readyRead,
this, &QWebSocketServerPrivate::handshakeReceived,
Qt::QueuedConnection);
QObjectPrivate::connect(pTcpSocket, &QTcpSocket::disconnected,
this, &QWebSocketServerPrivate::onSocketDisconnected);
}
}
QT_END_NAMESPACE
......@@ -65,6 +65,7 @@
QT_BEGIN_NAMESPACE
class QTcpServer;
class QTcpSocket;
class QWebSocketServer;
class QWebSocketServerPrivate : public QObjectPrivate
......@@ -120,6 +121,8 @@ public:
void setError(QWebSocketProtocol::CloseCode code, const QString &errorString);
void handleConnection(QTcpSocket *pTcpSocket) const;
QWebSocketServer * const q_ptr;
private:
......
......@@ -28,6 +28,7 @@
#include <QString>
#include <QtTest>
#include <QNetworkProxy>
#include <QTcpServer>
#ifndef QT_NO_OPENSSL
#include <QtNetwork/qsslpresharedkeyauthenticator.h>
#include <QtNetwork/qsslcipher.h>
......@@ -110,6 +111,7 @@ private Q_SLOTS:
void tst_maxPendingConnections();
void tst_serverDestroyedWhileSocketConnected();
void tst_scheme(); // qtbug-55927
void tst_handleConnection();
};
tst_QWebSocketServer::tst_QWebSocketServer()
......@@ -563,6 +565,38 @@ void tst_QWebSocketServer::tst_scheme()
#endif
}
void tst_QWebSocketServer::tst_handleConnection()
{
QWebSocketServer wsServer(QString(), QWebSocketServer::NonSecureMode);
QSignalSpy wsServerConnectionSpy(&wsServer, &QWebSocketServer::newConnection);
QTcpServer tcpServer;
connect(&tcpServer, &QTcpServer::newConnection,
[&tcpServer, &wsServer]() {
wsServer.handleConnection(tcpServer.nextPendingConnection());
});
QVERIFY(tcpServer.listen());
QWebSocket webSocket;
QSignalSpy wsConnectedSpy(&webSocket, &QWebSocket::connected);
webSocket.open(QStringLiteral("ws://localhost:%1").arg(tcpServer.serverPort()));
QVERIFY(wsConnectedSpy.wait());
if (wsServerConnectionSpy.isEmpty())
QVERIFY(wsServerConnectionSpy.wait());
QScopedPointer<QWebSocket> webServerSocket(wsServer.nextPendingConnection());
QVERIFY(!webServerSocket.isNull());
QSignalSpy wsMessageReceivedSpy(webServerSocket.data(), &QWebSocket::textMessageReceived);
webSocket.sendTextMessage("dummy");
wsMessageReceivedSpy.wait();
QCOMPARE(wsMessageReceivedSpy.count(), 1);
QList<QVariant> arguments = wsMessageReceivedSpy.takeFirst();
QCOMPARE(arguments.first().toString(), QString("dummy"));
}
QTEST_MAIN(tst_QWebSocketServer)
#include "tst_qwebsocketserver.moc"
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment