Use the proper protocol names
[contrib/qtwebsockets.git] / src / websockets / qwebsocketserver_p.cpp
index 912c66e..de3d04d 100644 (file)
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** 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.
@@ -70,9 +70,17 @@ QWebSocketServerPrivate::QWebSocketServerPrivate(const QString &serverName,
     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))
@@ -86,7 +94,8 @@ QWebSocketServerPrivate::QWebSocketServerPrivate(const QString &serverName,
         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,
@@ -104,14 +113,14 @@ QWebSocketServerPrivate::QWebSocketServerPrivate(const QString &serverName,
  */
 QWebSocketServerPrivate::~QWebSocketServerPrivate()
 {
-    close();
+    close(true);
     m_pTcpServer->deleteLater();
 }
 
 /*!
     \internal
  */
-void QWebSocketServerPrivate::close()
+void QWebSocketServerPrivate::close(bool aboutToDestroy)
 {
     Q_Q(QWebSocketServer);
     m_pTcpServer->close();
@@ -121,9 +130,11 @@ void QWebSocketServerPrivate::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);
+    }
 }
 
 /*!
@@ -169,7 +180,7 @@ bool QWebSocketServerPrivate::listen(const QHostAddress &address, quint16 port)
  */
 int QWebSocketServerPrivate::maxPendingConnections() const
 {
-    return m_pTcpServer->maxPendingConnections();
+    return m_maxPendingConnections;
 }
 
 /*!
@@ -264,7 +275,9 @@ quint16 QWebSocketServerPrivate::serverPort() const
  */
 void QWebSocketServerPrivate::setMaxPendingConnections(int numConnections)
 {
-    m_pTcpServer->setMaxPendingConnections(numConnections);
+    if (m_pTcpServer->maxPendingConnections() <= numConnections)
+        m_pTcpServer->setMaxPendingConnections(numConnections + 1);
+    m_maxPendingConnections = numConnections;
 }
 
 /*!
@@ -368,8 +381,12 @@ void QWebSocketServerPrivate::setError(QWebSocketProtocol::CloseCode code, const
 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);
 }
 
 /*!
@@ -398,18 +415,27 @@ void QWebSocketServerPrivate::handshakeReceived()
         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;