Add user configurable mask generation
[contrib/qtwebsockets.git] / src / websockets / qwebsocket_p.cpp
index 8505ddb..bff060f 100644 (file)
@@ -44,6 +44,7 @@
 #include "qwebsocketprotocol_p.h"
 #include "qwebsockethandshakerequest_p.h"
 #include "qwebsockethandshakeresponse_p.h"
+#include "qdefaultmaskgenerator_p.h"
 
 #include <QtCore/QUrl>
 #include <QtNetwork/QAuthenticator>
@@ -87,11 +88,11 @@ QWebSocketConfiguration::QWebSocketConfiguration() :
     \internal
 */
 QWebSocketPrivate::QWebSocketPrivate(const QString &origin, QWebSocketProtocol::Version version,
-                                     QWebSocket *pWebSocket, QObject *parent) :
-    QObject(parent),
+                                     QWebSocket *pWebSocket) :
+    QObjectPrivate(),
     q_ptr(pWebSocket),
     m_pSocket(),
-    m_errorString(),
+    m_errorString(QWebSocket::tr("Unknown error")),
     m_version(version),
     m_resourceName(),
     m_requestUrl(),
@@ -99,25 +100,28 @@ QWebSocketPrivate::QWebSocketPrivate(const QString &origin, QWebSocketProtocol::
     m_protocol(),
     m_extension(),
     m_socketState(QAbstractSocket::UnconnectedState),
+    m_pauseMode(QAbstractSocket::PauseNever),
+    m_readBufferSize(0),
     m_key(),
     m_mustMask(true),
     m_isClosingHandshakeSent(false),
     m_isClosingHandshakeReceived(false),
-    m_closeCode(QWebSocketProtocol::CC_NORMAL),
+    m_closeCode(QWebSocketProtocol::CloseCodeNormal),
     m_closeReason(),
     m_pingTimer(),
     m_dataProcessor(),
-    m_configuration()
+    m_configuration(),
+    m_pMaskGenerator(&m_defaultMaskGenerator),
+    m_defaultMaskGenerator()
 {
-    init();
 }
 
 /*!
     \internal
 */
 QWebSocketPrivate::QWebSocketPrivate(QTcpSocket *pTcpSocket, QWebSocketProtocol::Version version,
-                                     QWebSocket *pWebSocket, QObject *parent) :
-    QObject(parent),
+                                     QWebSocket *pWebSocket) :
+    QObjectPrivate(),
     q_ptr(pWebSocket),
     m_pSocket(pTcpSocket),
     m_errorString(pTcpSocket->errorString()),
@@ -128,18 +132,20 @@ QWebSocketPrivate::QWebSocketPrivate(QTcpSocket *pTcpSocket, QWebSocketProtocol:
     m_protocol(),
     m_extension(),
     m_socketState(pTcpSocket->state()),
+    m_pauseMode(pTcpSocket->pauseMode()),
+    m_readBufferSize(pTcpSocket->readBufferSize()),
     m_key(),
     m_mustMask(true),
     m_isClosingHandshakeSent(false),
     m_isClosingHandshakeReceived(false),
-    m_closeCode(QWebSocketProtocol::CC_NORMAL),
+    m_closeCode(QWebSocketProtocol::CloseCodeNormal),
     m_closeReason(),
     m_pingTimer(),
     m_dataProcessor(),
-    m_configuration()
+    m_configuration(),
+    m_pMaskGenerator(&m_defaultMaskGenerator),
+    m_defaultMaskGenerator()
 {
-    init();
-    makeConnections(m_pSocket.data());
 }
 
 /*!
@@ -148,7 +154,13 @@ QWebSocketPrivate::QWebSocketPrivate(QTcpSocket *pTcpSocket, QWebSocketProtocol:
 void QWebSocketPrivate::init()
 {
     Q_ASSERT(q_ptr);
-    qsrand(static_cast<uint>(QDateTime::currentMSecsSinceEpoch()));
+    Q_ASSERT(m_pMaskGenerator);
+
+    m_pMaskGenerator->seed();
+
+    if (m_pSocket) {
+        makeConnections(m_pSocket.data());
+    }
 }
 
 /*!
@@ -159,7 +171,7 @@ QWebSocketPrivate::~QWebSocketPrivate()
     if (!m_pSocket)
         return;
     if (state() == QAbstractSocket::ConnectedState)
-        close(QWebSocketProtocol::CC_GOING_AWAY, tr("Connection closed"));
+        close(QWebSocketProtocol::CloseCodeGoingAway, QWebSocket::tr("Connection closed"));
     releaseConnections(m_pSocket.data());
 }
 
@@ -177,7 +189,7 @@ void QWebSocketPrivate::abort()
  */
 QAbstractSocket::SocketError QWebSocketPrivate::error() const
 {
-    QAbstractSocket::SocketError err = QAbstractSocket::OperationError;
+    QAbstractSocket::SocketError err = QAbstractSocket::UnknownSocketError;
     if (Q_LIKELY(m_pSocket))
         err = m_pSocket->error();
     return err;
@@ -210,30 +222,7 @@ bool QWebSocketPrivate::flush()
 /*!
     \internal
  */
-qint64 QWebSocketPrivate::write(const char *message)
-{
-    if (!message || !*message)
-        return qint64(0);
-    uint size = qstrlen(message);
-    qint64 maxSize = qMin(qint64(size), qint64(std::numeric_limits<QString::size_type>::max()));
-    return doWriteFrames(QString::fromUtf8(message, maxSize).toUtf8(), false);
-}
-
-/*!
-    \internal
- */
-qint64 QWebSocketPrivate::write(const char *message, qint64 maxSize)
-{
-    if (!message || (maxSize <= qint64(0)) || !*message)
-        return qint64(0);
-    maxSize = qMin(maxSize, qint64(std::numeric_limits<QString::size_type>::max()));
-    return doWriteFrames(QString::fromUtf8(message, maxSize).toUtf8(), false);
-}
-
-/*!
-    \internal
- */
-qint64 QWebSocketPrivate::write(const QString &message)
+qint64 QWebSocketPrivate::sendTextMessage(const QString &message)
 {
     return doWriteFrames(message.toUtf8(), false);
 }
@@ -241,7 +230,7 @@ qint64 QWebSocketPrivate::write(const QString &message)
 /*!
     \internal
  */
-qint64 QWebSocketPrivate::write(const QByteArray &data)
+qint64 QWebSocketPrivate::sendBinaryMessage(const QByteArray &data)
 {
     return doWriteFrames(data, true);
 }
@@ -318,17 +307,17 @@ void QWebSocketPrivate::close(QWebSocketProtocol::CloseCode closeCode, QString r
         return;
     if (!m_isClosingHandshakeSent) {
         Q_Q(QWebSocket);
-        quint32 maskingKey = 0;
-        if (m_mustMask)
-            maskingKey = generateMaskingKey();
         const quint16 code = qToBigEndian<quint16>(closeCode);
         QByteArray payload;
         payload.append(static_cast<const char *>(static_cast<const void *>(&code)), 2);
         if (!reason.isEmpty())
             payload.append(reason.toUtf8());
-        if (m_mustMask)
+        quint32 maskingKey = 0;
+        if (m_mustMask) {
+            maskingKey = generateMaskingKey();
             QWebSocketProtocol::mask(payload.data(), payload.size(), maskingKey);
-        QByteArray frame = getFrameHeader(QWebSocketProtocol::OC_CLOSE,
+        }
+        QByteArray frame = getFrameHeader(QWebSocketProtocol::OpCodeClose,
                                           payload.size(), maskingKey, true);
         frame.append(payload);
         m_pSocket->write(frame);
@@ -347,8 +336,14 @@ void QWebSocketPrivate::close(QWebSocketProtocol::CloseCode closeCode, QString r
 void QWebSocketPrivate::open(const QUrl &url, bool mask)
 {
     //just delete the old socket for the moment;
-    //later, we can add more 'intelligent' handling by looking at the url
+    //later, we can add more 'intelligent' handling by looking at the URL
     //m_pSocket.reset();
+    Q_Q(QWebSocket);
+    if (!url.isValid() || url.toString().contains(QStringLiteral("\r\n"))) {
+        setErrorString(QWebSocket::tr("Invalid URL."));
+        Q_EMIT q->error(QAbstractSocket::ConnectionRefusedError);
+        return;
+    }
     QTcpSocket *pTcpSocket = m_pSocket.take();
     if (pTcpSocket) {
         releaseConnections(pTcpSocket);
@@ -356,14 +351,18 @@ void QWebSocketPrivate::open(const QUrl &url, bool mask)
     }
     //if (m_url != url)
     if (Q_LIKELY(!m_pSocket)) {
-        Q_Q(QWebSocket);
-
         m_dataProcessor.clear();
         m_isClosingHandshakeReceived = false;
         m_isClosingHandshakeSent = false;
 
         setRequestUrl(url);
         QString resourceName = url.path();
+        if (resourceName.contains(QStringLiteral("\r\n"))) {
+            setRequestUrl(QUrl());  //clear requestUrl
+            setErrorString(QWebSocket::tr("Invalid resource name."));
+            Q_EMIT q->error(QAbstractSocket::ConnectionRefusedError);
+            return;
+        }
         if (!url.query().isEmpty()) {
             if (!resourceName.endsWith(QChar::fromLatin1('?'))) {
                 resourceName.append(QChar::fromLatin1('?'));
@@ -378,19 +377,26 @@ void QWebSocketPrivate::open(const QUrl &url, bool mask)
     #ifndef QT_NO_SSL
         if (url.scheme() == QStringLiteral("wss")) {
             if (!QSslSocket::supportsSsl()) {
-                const QString message = tr("SSL Sockets are not supported on this platform.");
+                const QString message =
+                        QWebSocket::tr("SSL Sockets are not supported on this platform.");
                 setErrorString(message);
                 Q_EMIT q->error(QAbstractSocket::UnsupportedSocketOperationError);
             } else {
-                QSslSocket *sslSocket = new QSslSocket(this);
+                QSslSocket *sslSocket = new QSslSocket;
                 m_pSocket.reset(sslSocket);
                 if (Q_LIKELY(m_pSocket)) {
                     m_pSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
                     m_pSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
+                    m_pSocket->setReadBufferSize(m_readBufferSize);
+                    m_pSocket->setPauseMode(m_pauseMode);
 
                     makeConnections(m_pSocket.data());
-                    connect(sslSocket, &QSslSocket::encryptedBytesWritten, q,
-                            &QWebSocket::bytesWritten);
+                    QObject::connect(sslSocket, &QSslSocket::encryptedBytesWritten, q,
+                                     &QWebSocket::bytesWritten);
+                    typedef void (QSslSocket:: *sslErrorSignalType)(const QList<QSslError> &);
+                    QObject::connect(sslSocket,
+                                     static_cast<sslErrorSignalType>(&QSslSocket::sslErrors),
+                                     q, &QWebSocket::sslErrors);
                     setSocketState(QAbstractSocket::ConnectingState);
 
                     sslSocket->setSslConfiguration(m_configuration.m_sslConfiguration);
@@ -403,7 +409,7 @@ void QWebSocketPrivate::open(const QUrl &url, bool mask)
     #endif
                     sslSocket->connectToHostEncrypted(url.host(), url.port(443));
                 } else {
-                    const QString message = tr("Out of memory.");
+                    const QString message = QWebSocket::tr("Out of memory.");
                     setErrorString(message);
                     Q_EMIT q->error(QAbstractSocket::SocketResourceError);
                 }
@@ -411,26 +417,29 @@ void QWebSocketPrivate::open(const QUrl &url, bool mask)
         } else
     #endif
         if (url.scheme() == QStringLiteral("ws")) {
-            m_pSocket.reset(new QTcpSocket(this));
+            m_pSocket.reset(new QTcpSocket);
             if (Q_LIKELY(m_pSocket)) {
                 m_pSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
                 m_pSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
+                m_pSocket->setReadBufferSize(m_readBufferSize);
+                m_pSocket->setPauseMode(m_pauseMode);
 
                 makeConnections(m_pSocket.data());
-                connect(m_pSocket.data(), &QAbstractSocket::bytesWritten, q,
-                        &QWebSocket::bytesWritten);
+                QObject::connect(m_pSocket.data(), &QAbstractSocket::bytesWritten, q,
+                                 &QWebSocket::bytesWritten);
                 setSocketState(QAbstractSocket::ConnectingState);
     #ifndef QT_NO_NETWORKPROXY
                 m_pSocket->setProxy(m_configuration.m_proxy);
     #endif
                 m_pSocket->connectToHost(url.host(), url.port(80));
             } else {
-                const QString message = tr("Out of memory.");
+                const QString message = QWebSocket::tr("Out of memory.");
                 setErrorString(message);
                 Q_EMIT q->error(QAbstractSocket::SocketResourceError);
             }
         } else {
-            const QString message = tr("Unsupported websockets scheme: %1").arg(url.scheme());
+            const QString message =
+                    QWebSocket::tr("Unsupported websockets scheme: %1").arg(url.scheme());
             setErrorString(message);
             Q_EMIT q->error(QAbstractSocket::UnsupportedSocketOperationError);
         }
@@ -440,14 +449,13 @@ void QWebSocketPrivate::open(const QUrl &url, bool mask)
 /*!
     \internal
  */
-void QWebSocketPrivate::ping(QByteArray payload)
+void QWebSocketPrivate::ping(const QByteArray &payload)
 {
-    if (payload.length() > 125)
-        payload.truncate(125);
+    QByteArray payloadTruncated = payload.left(125);
     m_pingTimer.restart();
-    QByteArray pingFrame = getFrameHeader(QWebSocketProtocol::OC_PING, payload.size(),
+    QByteArray pingFrame = getFrameHeader(QWebSocketProtocol::OpCodePing, payloadTruncated.size(),
                                           0 /*do not mask*/, true);
-    pingFrame.append(payload);
+    pingFrame.append(payloadTruncated);
     qint64 ret = writeFrame(pingFrame);
     Q_UNUSED(ret);
 }
@@ -530,40 +538,40 @@ void QWebSocketPrivate::makeConnections(const QTcpSocket *pTcpSocket)
         //pass through signals
         typedef void (QAbstractSocket:: *ASErrorSignal)(QAbstractSocket::SocketError);
         typedef void (QWebSocket:: *WSErrorSignal)(QAbstractSocket::SocketError);
-        connect(pTcpSocket,
-                static_cast<ASErrorSignal>(&QAbstractSocket::error),
-                q, static_cast<WSErrorSignal>(&QWebSocket::error));
-        connect(pTcpSocket, &QAbstractSocket::proxyAuthenticationRequired, q,
-                &QWebSocket::proxyAuthenticationRequired);
-        connect(pTcpSocket, &QAbstractSocket::readChannelFinished, q,
-                &QWebSocket::readChannelFinished);
-        connect(pTcpSocket, &QAbstractSocket::aboutToClose, q, &QWebSocket::aboutToClose);
+        QObject::connect(pTcpSocket,
+                         static_cast<ASErrorSignal>(&QAbstractSocket::error),
+                         q, static_cast<WSErrorSignal>(&QWebSocket::error));
+        QObject::connect(pTcpSocket, &QAbstractSocket::proxyAuthenticationRequired, q,
+                         &QWebSocket::proxyAuthenticationRequired);
+        QObject::connect(pTcpSocket, &QAbstractSocket::readChannelFinished, q,
+                         &QWebSocket::readChannelFinished);
+        QObject::connect(pTcpSocket, &QAbstractSocket::aboutToClose, q, &QWebSocket::aboutToClose);
 
         //catch signals
-        connect(pTcpSocket, &QAbstractSocket::stateChanged, this,
-                &QWebSocketPrivate::processStateChanged);
+        QObjectPrivate::connect(pTcpSocket, &QAbstractSocket::stateChanged, this,
+                                &QWebSocketPrivate::processStateChanged);
         //!!!important to use a QueuedConnection here;
         //with QTcpSocket there is no problem, but with QSslSocket the processing hangs
-        connect(pTcpSocket, &QAbstractSocket::readyRead, this,
-                &QWebSocketPrivate::processData, Qt::QueuedConnection);
+        QObjectPrivate::connect(pTcpSocket, &QAbstractSocket::readyRead, this,
+                                &QWebSocketPrivate::processData, Qt::QueuedConnection);
     }
 
-    connect(&m_dataProcessor, &QWebSocketDataProcessor::textFrameReceived, q,
-            &QWebSocket::textFrameReceived);
-    connect(&m_dataProcessor, &QWebSocketDataProcessor::binaryFrameReceived, q,
-            &QWebSocket::binaryFrameReceived);
-    connect(&m_dataProcessor, &QWebSocketDataProcessor::binaryMessageReceived, q,
-            &QWebSocket::binaryMessageReceived);
-    connect(&m_dataProcessor, &QWebSocketDataProcessor::textMessageReceived, q,
-            &QWebSocket::textMessageReceived);
-    connect(&m_dataProcessor, &QWebSocketDataProcessor::errorEncountered, this,
-            &QWebSocketPrivate::close);
-    connect(&m_dataProcessor, &QWebSocketDataProcessor::pingReceived, this,
-            &QWebSocketPrivate::processPing);
-    connect(&m_dataProcessor, &QWebSocketDataProcessor::pongReceived, this,
-            &QWebSocketPrivate::processPong);
-    connect(&m_dataProcessor, &QWebSocketDataProcessor::closeReceived, this,
-            &QWebSocketPrivate::processClose);
+    QObject::connect(&m_dataProcessor, &QWebSocketDataProcessor::textFrameReceived, q,
+                     &QWebSocket::textFrameReceived);
+    QObject::connect(&m_dataProcessor, &QWebSocketDataProcessor::binaryFrameReceived, q,
+                     &QWebSocket::binaryFrameReceived);
+    QObject::connect(&m_dataProcessor, &QWebSocketDataProcessor::binaryMessageReceived, q,
+                     &QWebSocket::binaryMessageReceived);
+    QObject::connect(&m_dataProcessor, &QWebSocketDataProcessor::textMessageReceived, q,
+                     &QWebSocket::textMessageReceived);
+    QObjectPrivate::connect(&m_dataProcessor, &QWebSocketDataProcessor::errorEncountered, this,
+                            &QWebSocketPrivate::close);
+    QObjectPrivate::connect(&m_dataProcessor, &QWebSocketDataProcessor::pingReceived, this,
+                            &QWebSocketPrivate::processPing);
+    QObjectPrivate::connect(&m_dataProcessor, &QWebSocketDataProcessor::pongReceived, this,
+                            &QWebSocketPrivate::processPong);
+    QObjectPrivate::connect(&m_dataProcessor, &QWebSocketDataProcessor::closeReceived, this,
+                            &QWebSocketPrivate::processClose);
 }
 
 /*!
@@ -572,8 +580,8 @@ void QWebSocketPrivate::makeConnections(const QTcpSocket *pTcpSocket)
 void QWebSocketPrivate::releaseConnections(const QTcpSocket *pTcpSocket)
 {
     if (Q_LIKELY(pTcpSocket))
-        disconnect(pTcpSocket);
-    disconnect(&m_dataProcessor);
+        pTcpSocket->disconnect(pTcpSocket);
+    m_dataProcessor.disconnect();
 }
 
 /*!
@@ -652,9 +660,8 @@ QByteArray QWebSocketPrivate::getFrameHeader(QWebSocketProtocol::OpCode opCode,
     bool ok = payloadLength <= 0x7FFFFFFFFFFFFFFFULL;
 
     if (Q_LIKELY(ok)) {
-        //FIN, RSV1-3, opcode
-        byte = static_cast<quint8>((opCode & 0x0F) | (lastFrame ? 0x80 : 0x00));       //FIN, opcode
-        //RSV-1, RSV-2 and RSV-3 are zero
+        //FIN, RSV1-3, opcode (RSV-1, RSV-2 and RSV-3 are zero)
+        byte = static_cast<quint8>((opCode & 0x0F) | (lastFrame ? 0x80 : 0x00));
         header.append(static_cast<char>(byte));
 
         byte = 0x00;
@@ -694,12 +701,12 @@ QByteArray QWebSocketPrivate::getFrameHeader(QWebSocketProtocol::OpCode opCode,
 qint64 QWebSocketPrivate::doWriteFrames(const QByteArray &data, bool isBinary)
 {
     qint64 payloadWritten = 0;
-    if (Q_UNLIKELY(!m_pSocket))
+    if (Q_UNLIKELY(!m_pSocket) || (state() != QAbstractSocket::ConnectedState))
         return payloadWritten;
 
     Q_Q(QWebSocket);
     const QWebSocketProtocol::OpCode firstOpCode = isBinary ?
-                QWebSocketProtocol::OC_BINARY : QWebSocketProtocol::OC_TEXT;
+                QWebSocketProtocol::OpCodeBinary : QWebSocketProtocol::OpCodeText;
 
     int numFrames = data.size() / FRAME_SIZE_IN_BYTES;
     QByteArray tmpData(data);
@@ -727,7 +734,7 @@ qint64 QWebSocketPrivate::doWriteFrames(const QByteArray &data, bool isBinary)
 
         const quint64 size = qMin(bytesLeft, FRAME_SIZE_IN_BYTES);
         const QWebSocketProtocol::OpCode opcode = isFirstFrame ? firstOpCode
-                                                               : QWebSocketProtocol::OC_CONTINUE;
+                                                               : QWebSocketProtocol::OpCodeContinue;
 
         //write header
         bytesWritten += m_pSocket->write(getFrameHeader(opcode, size, maskingKey, isLastFrame));
@@ -743,7 +750,7 @@ qint64 QWebSocketPrivate::doWriteFrames(const QByteArray &data, bool isBinary)
                 payloadWritten += written;
             } else {
                 m_pSocket->flush();
-                setErrorString(tr("Error writing bytes to socket: %1.")
+                setErrorString(QWebSocket::tr("Error writing bytes to socket: %1.")
                                .arg(m_pSocket->errorString()));
                 Q_EMIT q->error(QAbstractSocket::NetworkError);
                 break;
@@ -753,26 +760,19 @@ qint64 QWebSocketPrivate::doWriteFrames(const QByteArray &data, bool isBinary)
         bytesLeft -= size;
     }
     if (Q_UNLIKELY(payloadWritten != data.size())) {
-        setErrorString(tr("Bytes written %1 != %2.").arg(payloadWritten).arg(data.size()));
+        setErrorString(QWebSocket::tr("Bytes written %1 != %2.")
+                       .arg(payloadWritten).arg(data.size()));
         Q_EMIT q->error(QAbstractSocket::NetworkError);
     }
     return payloadWritten;
 }
 
 /*!
- * \internal
- */
-quint32 QWebSocketPrivate::generateRandomNumber() const
-{
-    return quint32((double(qrand()) / RAND_MAX) * std::numeric_limits<quint32>::max());
-}
-
-/*!
     \internal
  */
 quint32 QWebSocketPrivate::generateMaskingKey() const
 {
-    return generateRandomNumber();
+    return m_pMaskGenerator->nextMask();
 }
 
 /*!
@@ -783,7 +783,7 @@ QByteArray QWebSocketPrivate::generateKey() const
     QByteArray key;
 
     for (int i = 0; i < 4; ++i) {
-        const quint32 tmp = generateRandomNumber();
+        const quint32 tmp = m_pMaskGenerator->nextMask();
         key.append(static_cast<const char *>(static_cast<const void *>(&tmp)), sizeof(quint32));
     }
 
@@ -876,28 +876,30 @@ void QWebSocketPrivate::processHandshake(QTcpSocket *pSocket)
         }
     }
     if (Q_UNLIKELY(!ok)) {
-        errorDescription = tr("Invalid statusline in response: %1.").arg(statusLine);
+        errorDescription = QWebSocket::tr("Invalid statusline in response: %1.").arg(statusLine);
     } else {
         QString headerLine = readLine(pSocket);
         QMap<QString, QString> headers;
         while (!headerLine.isEmpty()) {
             const QStringList headerField = headerLine.split(QStringLiteral(": "),
                                                              QString::SkipEmptyParts);
-            headers.insertMulti(headerField[0], headerField[1]);
+            if (headerField.size() == 2) {
+                headers.insertMulti(headerField[0], headerField[1]);
+            }
             headerLine = readLine(pSocket);
         }
 
         const QString acceptKey = headers.value(QStringLiteral("Sec-WebSocket-Accept"),
-                                                QStringLiteral(""));
-        const QString upgrade = headers.value(QStringLiteral("Upgrade"), QStringLiteral(""));
-        const QString connection = headers.value(QStringLiteral("Connection"), QStringLiteral(""));
+                                                QString());
+        const QString upgrade = headers.value(QStringLiteral("Upgrade"), QString());
+        const QString connection = headers.value(QStringLiteral("Connection"), QString());
 //        unused for the moment
 //        const QString extensions = headers.value(QStringLiteral("Sec-WebSocket-Extensions"),
-//                                                 QStringLiteral(""));
+//                                                 QString());
 //        const QString protocol = headers.value(QStringLiteral("Sec-WebSocket-Protocol"),
-//                                               QStringLiteral(""));
+//                                               QString());
         const QString version = headers.value(QStringLiteral("Sec-WebSocket-Version"),
-                                              QStringLiteral(""));
+                                              QString());
 
         if (Q_LIKELY(httpStatusCode == 101)) {
             //HTTP/x.y 101 Switching Protocols
@@ -913,11 +915,11 @@ void QWebSocketPrivate::processHandshake(QTcpSocket *pSocket)
                 ok = (accept == acceptKey);
                 if (!ok)
                     errorDescription =
-                      tr("Accept-Key received from server %1 does not match the client key %2.")
+                      QWebSocket::tr("Accept-Key received from server %1 does not match the client key %2.")
                             .arg(acceptKey).arg(accept);
             } else {
                 errorDescription =
-                    tr("QWebSocketPrivate::processHandshake: Invalid statusline in response: %1.")
+                    QWebSocket::tr("QWebSocketPrivate::processHandshake: Invalid statusline in response: %1.")
                         .arg(statusLine);
             }
         } else if (httpStatusCode == 400) {
@@ -929,21 +931,20 @@ void QWebSocketPrivate::processHandshake(QTcpSocket *pSocket)
                     //if needed to switch protocol version, then we are finished here
                     //because we cannot handle other protocols than the RFC one (v13)
                     errorDescription =
-                            tr("Handshake: Server requests a version that we don't support: %1.")
+                            QWebSocket::tr("Handshake: Server requests a version that we don't support: %1.")
                             .arg(versions.join(QStringLiteral(", ")));
                     ok = false;
                 } else {
                     //we tried v13, but something different went wrong
                     errorDescription =
-                        tr("QWebSocketPrivate::processHandshake: Unknown error condition " \
-                           "encountered. Aborting connection.");
+                        QWebSocket::tr("QWebSocketPrivate::processHandshake: Unknown error condition encountered. Aborting connection.");
                     ok = false;
                 }
             }
         } else {
             errorDescription =
-                    tr("QWebSocketPrivate::processHandshake: Unhandled http status code: %1 (%2).")
-                    .arg(httpStatusCode).arg(httpStatusMessage);
+                    QWebSocket::tr("QWebSocketPrivate::processHandshake: Unhandled http status code: %1 (%2).")
+                        .arg(httpStatusCode).arg(httpStatusMessage);
             ok = false;
         }
 
@@ -976,9 +977,14 @@ void QWebSocketPrivate::processStateChanged(QAbstractSocket::SocketState socketS
                                                 % QStringLiteral(":")
                                                 % QString::number(m_requestUrl.port(80)),
                                            origin(),
-                                           QStringLiteral(""),
-                                           QStringLiteral(""),
+                                           QString(),
+                                           QString(),
                                            m_key);
+            if (handshake.isEmpty()) {
+                m_pSocket->abort();
+                Q_EMIT q->error(QAbstractSocket::ConnectionRefusedError);
+                return;
+            }
             m_pSocket->write(handshake.toLatin1());
         }
         break;
@@ -1024,24 +1030,25 @@ void QWebSocketPrivate::processData()
 /*!
  \internal
  */
-void QWebSocketPrivate::processPing(QByteArray data)
+void QWebSocketPrivate::processPing(const QByteArray &data)
 {
     Q_ASSERT(m_pSocket);
     quint32 maskingKey = 0;
     if (m_mustMask)
         maskingKey = generateMaskingKey();
-    m_pSocket->write(getFrameHeader(QWebSocketProtocol::OC_PONG, data.size(), maskingKey, true));
+    m_pSocket->write(getFrameHeader(QWebSocketProtocol::OpCodePong, data.size(), maskingKey, true));
     if (data.size() > 0) {
+        QByteArray maskedData = data;
         if (m_mustMask)
-            QWebSocketProtocol::mask(&data, maskingKey);
-        m_pSocket->write(data);
+            QWebSocketProtocol::mask(&maskedData, maskingKey);
+        m_pSocket->write(maskedData);
     }
 }
 
 /*!
  \internal
  */
-void QWebSocketPrivate::processPong(QByteArray data)
+void QWebSocketPrivate::processPong(const QByteArray &data)
 {
     Q_Q(QWebSocket);
     Q_EMIT q->pong(static_cast<quint64>(m_pingTimer.elapsed()), data);
@@ -1067,6 +1074,31 @@ QString QWebSocketPrivate::createHandShakeRequest(QString resourceName,
                                                   QByteArray key)
 {
     QStringList handshakeRequest;
+    if (resourceName.contains(QStringLiteral("\r\n"))) {
+        setErrorString(QWebSocket::tr("The resource name contains newlines. " \
+                                      "Possible attack detected."));
+        return QString();
+    }
+    if (host.contains(QStringLiteral("\r\n"))) {
+        setErrorString(QWebSocket::tr("The hostname contains newlines. " \
+                                      "Possible attack detected."));
+        return QString();
+    }
+    if (origin.contains(QStringLiteral("\r\n"))) {
+        setErrorString(QWebSocket::tr("The origin contains newlines. " \
+                                      "Possible attack detected."));
+        return QString();
+    }
+    if (extensions.contains(QStringLiteral("\r\n"))) {
+        setErrorString(QWebSocket::tr("The extensions attribute contains newlines. " \
+                                      "Possible attack detected."));
+        return QString();
+    }
+    if (protocols.contains(QStringLiteral("\r\n"))) {
+        setErrorString(QWebSocket::tr("The protocols attribute contains newlines. " \
+                                      "Possible attack detected."));
+        return QString();
+    }
 
     handshakeRequest << QStringLiteral("GET ") % resourceName % QStringLiteral(" HTTP/1.1") <<
                         QStringLiteral("Host: ") % host <<
@@ -1142,10 +1174,7 @@ quint16 QWebSocketPrivate::localPort() const
  */
 QAbstractSocket::PauseModes QWebSocketPrivate::pauseMode() const
 {
-    QAbstractSocket::PauseModes mode = QAbstractSocket::PauseNever;
-    if (Q_LIKELY(m_pSocket))
-        mode = m_pSocket->pauseMode();
-    return mode;
+    return m_pauseMode;
 }
 
 /*!
@@ -1203,59 +1232,58 @@ void QWebSocketPrivate::setProxy(const QNetworkProxy &networkProxy)
 /*!
     \internal
  */
-qint64 QWebSocketPrivate::readBufferSize() const
+void QWebSocketPrivate::setMaskGenerator(const QMaskGenerator *maskGenerator)
 {
-    qint64 size = 0;
-    if (Q_LIKELY(m_pSocket))
-        size = m_pSocket->readBufferSize();
-    return size;
+    if (!maskGenerator)
+        m_pMaskGenerator = &m_defaultMaskGenerator;
+    else if (maskGenerator != m_pMaskGenerator)
+        m_pMaskGenerator = const_cast<QMaskGenerator *>(maskGenerator);
 }
 
 /*!
     \internal
  */
-void QWebSocketPrivate::resume()
+const QMaskGenerator *QWebSocketPrivate::maskGenerator() const
 {
-    if (Q_LIKELY(m_pSocket))
-        m_pSocket->resume();
+    Q_ASSERT(m_pMaskGenerator);
+    return m_pMaskGenerator;
 }
 
 /*!
-  \internal
+    \internal
  */
-void QWebSocketPrivate::setPauseMode(QAbstractSocket::PauseModes pauseMode)
+qint64 QWebSocketPrivate::readBufferSize() const
 {
-    if (Q_LIKELY(m_pSocket))
-        m_pSocket->setPauseMode(pauseMode);
+    return m_readBufferSize;
 }
 
 /*!
     \internal
  */
-void QWebSocketPrivate::setReadBufferSize(qint64 size)
+void QWebSocketPrivate::resume()
 {
     if (Q_LIKELY(m_pSocket))
-        m_pSocket->setReadBufferSize(size);
+        m_pSocket->resume();
 }
 
 /*!
-    \internal
+  \internal
  */
-void QWebSocketPrivate::setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value)
+void QWebSocketPrivate::setPauseMode(QAbstractSocket::PauseModes pauseMode)
 {
+    m_pauseMode = pauseMode;
     if (Q_LIKELY(m_pSocket))
-        m_pSocket->setSocketOption(option, value);
+        m_pSocket->setPauseMode(m_pauseMode);
 }
 
 /*!
     \internal
  */
-QVariant QWebSocketPrivate::socketOption(QAbstractSocket::SocketOption option)
+void QWebSocketPrivate::setReadBufferSize(qint64 size)
 {
-    QVariant val;
+    m_readBufferSize = size;
     if (Q_LIKELY(m_pSocket))
-        val = m_pSocket->socketOption(option);
-    return val;
+        m_pSocket->setReadBufferSize(m_readBufferSize);
 }
 
 /*!
@@ -1263,7 +1291,8 @@ QVariant QWebSocketPrivate::socketOption(QAbstractSocket::SocketOption option)
  */
 bool QWebSocketPrivate::isValid() const
 {
-    return (m_pSocket && m_pSocket->isValid());
+    return (m_pSocket && m_pSocket->isValid() &&
+            (m_socketState == QAbstractSocket::ConnectedState));
 }
 
 QT_END_NAMESPACE