/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Kurt Pattyn <pattyn.kurt@gmail.com>.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtWebSockets module of the Qt Toolkit.
m_secureMode(secureMode),
m_pendingConnections(),
m_error(QWebSocketProtocol::CloseCodeNormal),
- m_errorString()
+ m_errorString(),
+ m_maxPendingConnections(30)
{
Q_ASSERT(pWebSocketServer);
+}
+
+/*!
+ \internal
+ */
+void QWebSocketServerPrivate::init()
+{
if (m_secureMode == NonSecureMode) {
m_pTcpServer = new QTcpServer();
if (Q_LIKELY(m_pTcpServer))
m_pTcpServer = pSslServer;
if (Q_LIKELY(m_pTcpServer)) {
QObjectPrivate::connect(pSslServer, &QSslServer::newEncryptedConnection,
- this, &QWebSocketServerPrivate::onNewConnection);
+ this, &QWebSocketServerPrivate::onNewConnection,
+ Qt::QueuedConnection);
QObject::connect(pSslServer, &QSslServer::peerVerifyError,
q_ptr, &QWebSocketServer::peerVerifyError);
QObject::connect(pSslServer, &QSslServer::sslErrors,
*/
QWebSocketServerPrivate::~QWebSocketServerPrivate()
{
- close();
+ close(true);
m_pTcpServer->deleteLater();
}
/*!
\internal
*/
-void QWebSocketServerPrivate::close()
+void QWebSocketServerPrivate::close(bool aboutToDestroy)
{
Q_Q(QWebSocketServer);
m_pTcpServer->close();
QWebSocketServer::tr("Server closed."));
pWebSocket->deleteLater();
}
- //emit signal via the event queue, so the server gets time
- //to process any hanging events, like flushing buffers aso
- QMetaObject::invokeMethod(q, "closed", Qt::QueuedConnection);
+ if (!aboutToDestroy) {
+ //emit signal via the event queue, so the server gets time
+ //to process any hanging events, like flushing buffers aso
+ QMetaObject::invokeMethod(q, "closed", Qt::QueuedConnection);
+ }
}
/*!
*/
int QWebSocketServerPrivate::maxPendingConnections() const
{
- return m_pTcpServer->maxPendingConnections();
+ return m_maxPendingConnections;
}
/*!
*/
void QWebSocketServerPrivate::setMaxPendingConnections(int numConnections)
{
- m_pTcpServer->setMaxPendingConnections(numConnections);
+ if (m_pTcpServer->maxPendingConnections() <= numConnections)
+ m_pTcpServer->setMaxPendingConnections(numConnections + 1);
+ m_maxPendingConnections = numConnections;
}
/*!
void QWebSocketServerPrivate::onNewConnection()
{
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);
+ this, &QWebSocketServerPrivate::handshakeReceived,
+ Qt::QueuedConnection);
}
/*!
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.
+ //Therefore, the readyRead signal is emitted twice.
+ //This is a guard against the BEAST attack.
+ //See: https://www.imperialviolet.org/2012/01/15/beastfollowup.html
+ //For Safari, the handshake is delivered at once
+ //FIXME: For FireFox, the readyRead signal is never emitted
+ //This is a bug in FireFox (see https://bugzilla.mozilla.org/show_bug.cgi?id=594502)
+ if (!pTcpSocket->canReadLine()) {
+ return;
+ }
+ disconnect(pTcpSocket, &QTcpSocket::readyRead,
+ this, &QWebSocketServerPrivate::handshakeReceived);
Q_Q(QWebSocketServer);
bool success = false;
bool isSecure = false;
- disconnect(pTcpSocket, &QTcpSocket::readyRead,
- this, &QWebSocketServerPrivate::handshakeReceived);
-
if (m_pendingConnections.length() >= maxPendingConnections()) {
pTcpSocket->close();
pTcpSocket->deleteLater();
qWarning() << QWebSocketServer::tr("Too many pending connections: " \
- "New websocket connection not accepted.");
+ "New WebSocket connection not accepted.");
setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
QWebSocketServer::tr("Too many pending connections."));
return;