Implement of secure web sockets
authorKurt Pattyn <pattyn.kurt@gmail.com>
Thu, 31 Oct 2013 08:31:25 +0000 (09:31 +0100)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Thu, 31 Oct 2013 10:52:27 +0000 (11:52 +0100)
Change-Id: I1f96d5e4e327eae211fd6b458168e1f7607e2dcf
Reviewed-by: Kurt Pattyn <pattyn.kurt@gmail.com>
src/websockets/qwebsocket.cpp
src/websockets/qwebsocket.h
src/websockets/qwebsocket_p.cpp
src/websockets/qwebsocket_p.h

index d209f37..b1fc57c 100644 (file)
@@ -107,6 +107,16 @@ not been filled in with new information when the signal returns.
 
     \sa close()
 */
+/*!
+    \fn void QWebSocket::bytesWritten(qint64 bytes)
+
+    This signal is emitted every time a payload of data has been written to the socket.
+    The \a bytes argument is set to the number of bytes that were written in this payload.
+
+    \note This signal has the same meaning both for secure and non-secure websockets.
+    As opposed to QSslSocket, bytesWritten() is only emitted when encrypted data is effectively written (\sa {{QSslSocket:}}{{encryptedBytesWritten}}).
+    \sa close()
+*/
 
 /*!
     \fn void QWebSocket::textFrameReceived(QString frame, bool isLastFrame);
index a820dcd..fbc3b36 100644 (file)
@@ -24,7 +24,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 #ifndef QT_NO_NETWORKPROXY
 #include <QNetworkProxy>
 #endif
-
+#ifndef QT_NO_SSL
+#include <QSslError>
+#include <QSslConfiguration>
+#endif
 #include "qwebsockets_global.h"
 #include "qwebsocketprotocol.h"
 
@@ -83,6 +86,12 @@ public:
     qint64 write(const QString &message);      //send data as text
     qint64 write(const QByteArray &data);      //send data as binary
 
+#ifndef QT_NO_SSL
+    void ignoreSslErrors(const QList<QSslError> &errors);
+    void setSslConfiguration(const QSslConfiguration &sslConfiguration);
+    QSslConfiguration sslConfiguration() const;
+#endif
+
 public Q_SLOTS:
     void close(QWebSocketProtocol::CloseCode closeCode = QWebSocketProtocol::CC_NORMAL, const QString &reason = QString());
     void open(const QUrl &url, bool mask = true);
@@ -103,6 +112,7 @@ Q_SIGNALS:
     void binaryMessageReceived(QByteArray message);
     void error(QAbstractSocket::SocketError error);
     void pong(quint64 elapsedTime, QByteArray payload);
+    void bytesWritten(qint64 bytes);
 
 private:
     QWebSocket(QTcpSocket *pTcpSocket, QWebSocketProtocol::Version version, QObject *parent = Q_NULLPTR);
index ca7e903..e47f4e6 100644 (file)
@@ -48,7 +48,7 @@ const quint64 FRAME_SIZE_IN_BYTES = 512 * 512 * 2;    //maximum size of a frame whe
 QWebSocketPrivate::QWebSocketPrivate(const QString &origin, QWebSocketProtocol::Version version, QWebSocket *pWebSocket, QObject *parent) :
     QObject(parent),
     q_ptr(pWebSocket),
-    m_pSocket(new QTcpSocket(this)),
+    m_pSocket(Q_NULLPTR),
     m_errorString(),
     m_version(version),
     m_resourceName(),
@@ -65,7 +65,7 @@ QWebSocketPrivate::QWebSocketPrivate(const QString &origin, QWebSocketProtocol::
     m_dataProcessor()
 {
     Q_ASSERT(pWebSocket);
-    makeConnections(m_pSocket);
+    //makeConnections(m_pSocket);
     qsrand(static_cast<uint>(QDateTime::currentMSecsSinceEpoch()));
 }
 
@@ -184,7 +184,35 @@ qint64 QWebSocketPrivate::write(const QByteArray &data)
     return doWriteData(data, true);
 }
 
+#ifndef QT_NO_SSL
+/*!
+    \internal
+ */
+void QWebSocketPrivate::setSslConfiguration(const QSslConfiguration &sslConfiguration)
+{
+    m_sslConfiguration = sslConfiguration;
+}
+
+/*!
+    \internal
+ */
+QSslConfiguration QWebSocketPrivate::sslConfiguration() const
+{
+    return m_sslConfiguration;
+}
+
+/*!
+    \internal
+ */
+void QWebSocketPrivate::ignoreSslErrors(const QList<QSslError> &errors)
+{
+    m_ignoredSslErrors = errors;
+}
+
+#endif
+
 /*!
+  Called from QWebSocketServer
   \internal
  */
 QWebSocket *QWebSocketPrivate::upgradeFrom(QTcpSocket *pTcpSocket,
@@ -245,6 +273,8 @@ void QWebSocketPrivate::close(QWebSocketProtocol::CloseCode closeCode, QString r
  */
 void QWebSocketPrivate::open(const QUrl &url, bool mask)
 {
+    Q_Q(QWebSocket);
+
     m_dataProcessor.clear();
     m_isClosingHandshakeReceived = false;
     m_isClosingHandshakeSent = false;
@@ -266,9 +296,40 @@ void QWebSocketPrivate::open(const QUrl &url, bool mask)
     setResourceName(resourceName);
     enableMasking(mask);
 
-    setSocketState(QAbstractSocket::ConnectingState);
+#ifndef QT_NO_SSL
+    if (url.scheme() == QStringLiteral("wss"))
+    {
+        if (!QSslSocket::supportsSsl())
+        {
+            qWarning() << tr("SSL Sockets are not supported on this platform.");
+            setErrorString(tr("SSL Sockets are not supported on this platform."));
+            emit q->error(QAbstractSocket::UnsupportedSocketOperationError);
+            return;
+        }
+        else
+        {
+            QSslSocket *sslSocket = new QSslSocket(this);
+            m_pSocket = sslSocket;
+
+            makeConnections(m_pSocket);
+            connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)), q, SIGNAL(bytesWritten(qint64)));
+            setSocketState(QAbstractSocket::ConnectingState);
 
-    m_pSocket->connectToHost(url.host(), url.port(80));
+            sslSocket->setSslConfiguration(m_sslConfiguration);
+            sslSocket->ignoreSslErrors(m_ignoredSslErrors);
+            sslSocket->connectToHostEncrypted(url.host(), url.port(443));
+        }
+    }
+    else
+#endif
+    {
+        m_pSocket = new QTcpSocket(this);
+
+        makeConnections(m_pSocket);
+        connect(m_pSocket, SIGNAL(bytesWritten(qint64)), q, SIGNAL(bytesWritten(qint64)));
+        setSocketState(QAbstractSocket::ConnectingState);
+        m_pSocket->connectToHost(url.host(), url.port(80));
+    }
 }
 
 /*!
index b2dcdb8..90543e3 100644 (file)
@@ -35,6 +35,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 #ifndef QT_NO_NETWORKPROXY
 #include <QNetworkProxy>
 #endif
+#ifndef QT_NO_SSL
+#include <QSslConfiguration>
+#include <QSslError>
+#endif
 #include <QTime>
 
 #include "qwebsocketprotocol.h"
@@ -98,6 +102,12 @@ public:
     qint64 write(const QString &message);      //send data as text
     qint64 write(const QByteArray &data);      //send data as binary
 
+#ifndef QT_NO_SSL
+    void ignoreSslErrors(const QList<QSslError> &errors);
+    void setSslConfiguration(const QSslConfiguration &sslConfiguration);
+    QSslConfiguration sslConfiguration() const;
+#endif
+
 public Q_SLOTS:
     void close(QWebSocketProtocol::CloseCode closeCode, QString reason);
     void open(const QUrl &url, bool mask);
@@ -113,6 +123,10 @@ private Q_SLOTS:
 
 private:
     QWebSocket * const q_ptr;
+#ifndef QT_NO_SSL
+    QSslConfiguration m_sslConfiguration;
+    QList<QSslError> m_ignoredSslErrors;
+#endif
 
     QWebSocketPrivate(QTcpSocket *pTcpSocket, QWebSocketProtocol::Version version, QWebSocket *pWebSocket, QObject *parent = Q_NULLPTR);
     void setVersion(QWebSocketProtocol::Version version);