Blob Blame History Raw
diff --git a/src/websockets/qwebsocket.cpp b/src/websockets/qwebsocket.cpp
index ade1eb4..144268f 100644
--- a/src/websockets/qwebsocket.cpp
+++ b/src/websockets/qwebsocket.cpp
@@ -788,4 +788,115 @@ qint64 QWebSocket::bytesToWrite() const
     return d->m_pSocket ? d->m_pSocket->bytesToWrite() : 0;
 }
 
+/*!
+    \since 5.15
+    Sets the maximum allowed size of an incoming websocket frame to \a maxAllowedIncomingFrameSize.
+    If an incoming frame exceeds this limit, the peer gets disconnected.
+    The accepted range is between 0 and maxIncomingFrameSize(), default is maxIncomingFrameSize().
+    The purpose of this function is to avoid exhausting virtual memory.
+
+    \sa maxAllowedIncomingFrameSize()
+ */
+void QWebSocket::setMaxAllowedIncomingFrameSize(quint64 maxAllowedIncomingFrameSize)
+{
+    Q_D(QWebSocket);
+    d->setMaxAllowedIncomingFrameSize(maxAllowedIncomingFrameSize);
+}
+
+/*!
+    \since 5.15
+    Returns the maximum allowed size of an incoming websocket frame.
+
+    \sa setMaxAllowedIncomingFrameSize()
+ */
+quint64 QWebSocket::maxAllowedIncomingFrameSize() const
+{
+    Q_D(const QWebSocket);
+    return d->maxAllowedIncomingFrameSize();
+}
+
+/*!
+    \since 5.15
+    Sets the maximum allowed size of an incoming websocket message to \a maxAllowedIncomingMessageSize.
+    If an incoming message exceeds this limit, the peer gets disconnected.
+    The accepted range is between 0 and maxIncomingMessageSize(), default is maxIncomingMessageSize().
+    The purpose of this function is to avoid exhausting virtual memory.
+
+    \sa maxAllowedIncomingMessageSize()
+ */
+void QWebSocket::setMaxAllowedIncomingMessageSize(quint64 maxAllowedIncomingMessageSize)
+{
+    Q_D(QWebSocket);
+    d->setMaxAllowedIncomingMessageSize(maxAllowedIncomingMessageSize);
+}
+
+/*!
+    \since 5.15
+    Returns the maximum allowed size of an incoming websocket message.
+
+    \sa setMaxAllowedIncomingMessageSize()
+ */
+quint64 QWebSocket::maxAllowedIncomingMessageSize() const
+{
+    Q_D(const QWebSocket);
+    return d->maxAllowedIncomingMessageSize();
+}
+
+/*!
+    \since 5.15
+    Returns the maximum supported size of an incoming websocket message for this websocket
+    implementation.
+ */
+quint64 QWebSocket::maxIncomingMessageSize()
+{
+    return QWebSocketPrivate::maxIncomingMessageSize();
+}
+
+/*!
+    \since 5.15
+    Returns the maximum supported size of an incoming websocket frame for this websocket
+    implementation.
+ */
+quint64 QWebSocket::maxIncomingFrameSize()
+{
+    return QWebSocketPrivate::maxIncomingFrameSize();
+}
+
+/*!
+    \since 5.15
+    Sets the maximum size of an outgoing websocket frame to \a outgoingFrameSize.
+    The accepted range is between 0 and maxOutgoingFrameSize(), default is 512kB.
+    The purpose of this function is to adapt to the maximum allowed frame size
+    of the receiver.
+
+    \sa outgoingFrameSize()
+ */
+void QWebSocket::setOutgoingFrameSize(quint64 outgoingFrameSize)
+{
+    Q_D(QWebSocket);
+    d->setOutgoingFrameSize(outgoingFrameSize);
+}
+
+/*!
+    \since 5.15
+    Returns the maximum size of an outgoing websocket frame.
+
+    \sa setOutgoingFrameSize()
+ */
+quint64 QWebSocket::outgoingFrameSize() const
+{
+    Q_D(const QWebSocket);
+    return d->outgoingFrameSize();
+}
+
+/*!
+    \since 5.15
+    Returns the maximum supported size of an outgoing websocket frame for this websocket
+    implementation.
+ */
+quint64 QWebSocket::maxOutgoingFrameSize()
+{
+    return QWebSocketPrivate::maxOutgoingFrameSize();
+}
+
 QT_END_NAMESPACE
diff --git a/src/websockets/qwebsocket.h b/src/websockets/qwebsocket.h
index 4944689..fad565c 100644
--- a/src/websockets/qwebsocket.h
+++ b/src/websockets/qwebsocket.h
@@ -115,6 +115,17 @@ public:
 
     qint64 bytesToWrite() const;
 
+    void setMaxAllowedIncomingFrameSize(quint64 maxAllowedIncomingFrameSize);
+    quint64 maxAllowedIncomingFrameSize() const;
+    void setMaxAllowedIncomingMessageSize(quint64 maxAllowedIncomingMessageSize);
+    quint64 maxAllowedIncomingMessageSize() const;
+    static quint64 maxIncomingMessageSize();
+    static quint64 maxIncomingFrameSize();
+
+    void setOutgoingFrameSize(quint64 outgoingFrameSize);
+    quint64 outgoingFrameSize() const;
+    static quint64 maxOutgoingFrameSize();
+
 public Q_SLOTS:
     void close(QWebSocketProtocol::CloseCode closeCode = QWebSocketProtocol::CloseCodeNormal,
                const QString &reason = QString());
diff --git a/src/websockets/qwebsocket_p.cpp b/src/websockets/qwebsocket_p.cpp
index 8529538..5480ecf 100644
--- a/src/websockets/qwebsocket_p.cpp
+++ b/src/websockets/qwebsocket_p.cpp
@@ -69,7 +69,8 @@
 
 QT_BEGIN_NAMESPACE
 
-const quint64 FRAME_SIZE_IN_BYTES = 512 * 512 * 2;	//maximum size of a frame when sending a message
+const quint64 MAX_OUTGOING_FRAME_SIZE_IN_BYTES = std::numeric_limits<int>::max() - 1;
+const quint64 DEFAULT_OUTGOING_FRAME_SIZE_IN_BYTES = 512 * 512 * 2; //default size of a frame when sending a message
 
 QWebSocketConfiguration::QWebSocketConfiguration() :
 #ifndef QT_NO_SSL
@@ -111,7 +112,8 @@ QWebSocketPrivate::QWebSocketPrivate(const QString &origin, QWebSocketProtocol::
     m_configuration(),
     m_pMaskGenerator(&m_defaultMaskGenerator),
     m_defaultMaskGenerator(),
-    m_handshakeState(NothingDoneState)
+    m_handshakeState(NothingDoneState),
+    m_outgoingFrameSize(DEFAULT_OUTGOING_FRAME_SIZE_IN_BYTES)
 {
 }
 
@@ -142,7 +144,8 @@ QWebSocketPrivate::QWebSocketPrivate(QTcpSocket *pTcpSocket, QWebSocketProtocol:
     m_configuration(),
     m_pMaskGenerator(&m_defaultMaskGenerator),
     m_defaultMaskGenerator(),
-    m_handshakeState(NothingDoneState)
+    m_handshakeState(NothingDoneState),
+    m_outgoingFrameSize(DEFAULT_OUTGOING_FRAME_SIZE_IN_BYTES)
 {
 }
 
@@ -565,7 +568,7 @@ void QWebSocketPrivate::enableMasking(bool enable)
 /*!
  * \internal
  */
-void QWebSocketPrivate::makeConnections(const QTcpSocket *pTcpSocket)
+void QWebSocketPrivate::makeConnections(QTcpSocket *pTcpSocket)
 {
     Q_ASSERT(pTcpSocket);
     Q_Q(QWebSocket);
@@ -632,6 +635,10 @@ void QWebSocketPrivate::makeConnections(const QTcpSocket *pTcpSocket)
                             &QWebSocketPrivate::processPong);
     QObjectPrivate::connect(&m_dataProcessor, &QWebSocketDataProcessor::closeReceived, this,
                             &QWebSocketPrivate::processClose);
+
+    //fire readyread, in case we already have data inside the tcpSocket
+    if (pTcpSocket->bytesAvailable())
+        Q_EMIT pTcpSocket->readyRead();
 }
 
 /*!
@@ -768,11 +775,11 @@ qint64 QWebSocketPrivate::doWriteFrames(const QByteArray &data, bool isBinary)
     const QWebSocketProtocol::OpCode firstOpCode = isBinary ?
                 QWebSocketProtocol::OpCodeBinary : QWebSocketProtocol::OpCodeText;
 
-    int numFrames = data.size() / int(FRAME_SIZE_IN_BYTES);
+    int numFrames = data.size() / int(outgoingFrameSize());
     QByteArray tmpData(data);
     tmpData.detach();
     char *payload = tmpData.data();
-    quint64 sizeLeft = quint64(data.size()) % FRAME_SIZE_IN_BYTES;
+    quint64 sizeLeft = quint64(data.size()) % outgoingFrameSize();
     if (Q_LIKELY(sizeLeft))
         ++numFrames;
 
@@ -791,7 +798,7 @@ qint64 QWebSocketPrivate::doWriteFrames(const QByteArray &data, bool isBinary)
         const bool isLastFrame = (i == (numFrames - 1));
         const bool isFirstFrame = (i == 0);
 
-        const quint64 size = qMin(bytesLeft, FRAME_SIZE_IN_BYTES);
+        const quint64 size = qMin(bytesLeft, outgoingFrameSize());
         const QWebSocketProtocol::OpCode opcode = isFirstFrame ? firstOpCode
                                                                : QWebSocketProtocol::OpCodeContinue;
 
@@ -1174,10 +1181,10 @@ void QWebSocketPrivate::processData()
     while (m_pSocket->bytesAvailable()) {
         if (state() == QAbstractSocket::ConnectingState) {
             if (!m_pSocket->canReadLine())
-                break;
+                return;
             processHandshake(m_pSocket);
-        } else {
-            m_dataProcessor.process(m_pSocket);
+        } else if (!m_dataProcessor.process(m_pSocket)) {
+            return;
         }
     }
 }
@@ -1301,6 +1308,80 @@ void QWebSocketPrivate::setSocketState(QAbstractSocket::SocketState state)
     }
 }
 
+/*!
+    \internal
+ */
+void QWebSocketPrivate::setMaxAllowedIncomingFrameSize(quint64 maxAllowedIncomingFrameSize)
+{
+    m_dataProcessor.setMaxAllowedFrameSize(maxAllowedIncomingFrameSize);
+}
+
+/*!
+    \internal
+ */
+quint64 QWebSocketPrivate::maxAllowedIncomingFrameSize() const
+{
+    return m_dataProcessor.maxAllowedFrameSize();
+}
+
+/*!
+    \internal
+ */
+void QWebSocketPrivate::setMaxAllowedIncomingMessageSize(quint64 maxAllowedIncomingMessageSize)
+{
+    m_dataProcessor.setMaxAllowedMessageSize(maxAllowedIncomingMessageSize);
+}
+
+/*!
+    \internal
+ */
+quint64 QWebSocketPrivate::maxAllowedIncomingMessageSize() const
+{
+    return m_dataProcessor.maxAllowedMessageSize();
+}
+
+/*!
+    \internal
+ */
+quint64 QWebSocketPrivate::maxIncomingMessageSize()
+{
+    return QWebSocketDataProcessor::maxMessageSize();
+}
+
+/*!
+    \internal
+ */
+quint64 QWebSocketPrivate::maxIncomingFrameSize()
+{
+    return QWebSocketDataProcessor::maxFrameSize();
+}
+
+/*!
+    \internal
+ */
+void QWebSocketPrivate::setOutgoingFrameSize(quint64 outgoingFrameSize)
+{
+    if (outgoingFrameSize <= maxOutgoingFrameSize())
+        m_outgoingFrameSize = outgoingFrameSize;
+}
+
+/*!
+    \internal
+ */
+quint64 QWebSocketPrivate::outgoingFrameSize() const
+{
+    return m_outgoingFrameSize;
+}
+
+/*!
+    \internal
+ */
+quint64 QWebSocketPrivate::maxOutgoingFrameSize()
+{
+    return MAX_OUTGOING_FRAME_SIZE_IN_BYTES;
+}
+
+
 /*!
     \internal
  */
diff --git a/src/websockets/qwebsocket_p.h b/src/websockets/qwebsocket_p.h
index 4b39dfc..c3f170d 100644
--- a/src/websockets/qwebsocket_p.h
+++ b/src/websockets/qwebsocket_p.h
@@ -160,6 +160,17 @@ public:
     void ping(const QByteArray &payload);
     void setSocketState(QAbstractSocket::SocketState state);
 
+    void setMaxAllowedIncomingFrameSize(quint64 maxAllowedIncomingFrameSize);
+    quint64 maxAllowedIncomingFrameSize() const;
+    void setMaxAllowedIncomingMessageSize(quint64 maxAllowedIncomingMessageSize);
+    quint64 maxAllowedIncomingMessageSize() const;
+    static quint64 maxIncomingMessageSize();
+    static quint64 maxIncomingFrameSize();
+
+    void setOutgoingFrameSize(quint64 outgoingFrameSize);
+    quint64 outgoingFrameSize() const;
+    static quint64 maxOutgoingFrameSize();
+
 private:
     QWebSocketPrivate(QTcpSocket *pTcpSocket, QWebSocketProtocol::Version version);
     void setVersion(QWebSocketProtocol::Version version);
@@ -182,7 +193,7 @@ private:
 
     Q_REQUIRED_RESULT qint64 doWriteFrames(const QByteArray &data, bool isBinary);
 
-    void makeConnections(const QTcpSocket *pTcpSocket);
+    void makeConnections(QTcpSocket *pTcpSocket);
     void releaseConnections(const QTcpSocket *pTcpSocket);
 
     QByteArray getFrameHeader(QWebSocketProtocol::OpCode opCode, quint64 payloadLength,
@@ -250,6 +261,8 @@ private:
     QString m_httpStatusMessage;
     QMap<QString, QString> m_headers;
 
+    quint64 m_outgoingFrameSize;
+
     friend class QWebSocketServerPrivate;
 #ifdef Q_OS_WASM
     emscripten::val socketContext = emscripten::val::null();
diff --git a/src/websockets/qwebsocketdataprocessor.cpp b/src/websockets/qwebsocketdataprocessor.cpp
index 4f81222..4110f2a 100644
--- a/src/websockets/qwebsocketdataprocessor.cpp
+++ b/src/websockets/qwebsocketdataprocessor.cpp
@@ -87,6 +87,10 @@ QWebSocketDataProcessor::QWebSocketDataProcessor(QObject *parent) :
     m_pTextCodec(QTextCodec::codecForName("UTF-8"))
 {
     clear();
+    // initialize the internal timeout timer
+    waitTimer.setInterval(5000);
+    waitTimer.setSingleShot(true);
+    waitTimer.callOnTimeout(this, &QWebSocketDataProcessor::timeout);
 }
 
 /*!
@@ -101,6 +105,33 @@ QWebSocketDataProcessor::~QWebSocketDataProcessor()
     }
 }
 
+void QWebSocketDataProcessor::setMaxAllowedFrameSize(quint64 maxAllowedFrameSize)
+{
+    frame.setMaxAllowedFrameSize(maxAllowedFrameSize);
+}
+
+quint64 QWebSocketDataProcessor::maxAllowedFrameSize() const
+{
+    return frame.maxAllowedFrameSize();
+}
+
+/*!
+    \internal
+ */
+void QWebSocketDataProcessor::setMaxAllowedMessageSize(quint64 maxAllowedMessageSize)
+{
+    if (maxAllowedMessageSize <= maxMessageSize())
+        m_maxAllowedMessageSize = maxAllowedMessageSize;
+}
+
+/*!
+    \internal
+ */
+quint64 QWebSocketDataProcessor::maxAllowedMessageSize() const
+{
+    return m_maxAllowedMessageSize;
+}
+
 /*!
     \internal
  */
@@ -114,19 +145,28 @@ quint64 QWebSocketDataProcessor::maxMessageSize()
  */
 quint64 QWebSocketDataProcessor::maxFrameSize()
 {
-    return MAX_FRAME_SIZE_IN_BYTES;
+   return QWebSocketFrame::maxFrameSize();
 }
 
 /*!
     \internal
+
+    Returns \c true if a complete websocket frame has been processed;
+    otherwise returns \c false.
  */
-void QWebSocketDataProcessor::process(QIODevice *pIoDevice)
+bool QWebSocketDataProcessor::process(QIODevice *pIoDevice)
 {
     bool isDone = false;
 
     while (!isDone) {
-        QWebSocketFrame frame = QWebSocketFrame::readFrame(pIoDevice);
-        if (Q_LIKELY(frame.isValid())) {
+        frame.readFrame(pIoDevice);
+        if (!frame.isDone()) {
+            // waiting for more data available
+            QObject::connect(pIoDevice, &QIODevice::readyRead,
+                             &waitTimer, &QTimer::stop, Qt::UniqueConnection);
+            waitTimer.start();
+            return false;
+        } else if (Q_LIKELY(frame.isValid())) {
             if (frame.isControlFrame()) {
                 isDone = processControlFrame(frame);
             } else {
@@ -136,7 +176,7 @@ void QWebSocketDataProcessor::process(QIODevice *pIoDevice)
                     Q_EMIT errorEncountered(QWebSocketProtocol::CloseCodeProtocolError,
                                             tr("Received Continuation frame, while there is " \
                                                "nothing to continue."));
-                    return;
+                    return true;
                 }
                 if (Q_UNLIKELY(m_isFragmented && frame.isDataFrame() &&
                                !frame.isContinuationFrame())) {
@@ -144,7 +184,7 @@ void QWebSocketDataProcessor::process(QIODevice *pIoDevice)
                     Q_EMIT errorEncountered(QWebSocketProtocol::CloseCodeProtocolError,
                                             tr("All data frames after the initial data frame " \
                                                "must have opcode 0 (continuation)."));
-                    return;
+                    return true;
                 }
                 if (!frame.isContinuationFrame()) {
                     m_opCode = frame.opCode();
@@ -154,11 +194,11 @@ void QWebSocketDataProcessor::process(QIODevice *pIoDevice)
                         ? quint64(m_textMessage.length())
                         : quint64(m_binaryMessage.length());
                 if (Q_UNLIKELY((messageLength + quint64(frame.payload().length())) >
-                               MAX_MESSAGE_SIZE_IN_BYTES)) {
+                               maxAllowedMessageSize())) {
                     clear();
                     Q_EMIT errorEncountered(QWebSocketProtocol::CloseCodeTooMuchData,
                                             tr("Received message is too big."));
-                    return;
+                    return true;
                 }
 
                 if (m_opCode == QWebSocketProtocol::OpCodeText) {
@@ -171,7 +211,7 @@ void QWebSocketDataProcessor::process(QIODevice *pIoDevice)
                         clear();
                         Q_EMIT errorEncountered(QWebSocketProtocol::CloseCodeWrongDatatype,
                                                 tr("Invalid UTF-8 code encountered."));
-                        return;
+                        return true;
                     } else {
                         m_textMessage.append(frameTxt);
                         Q_EMIT textFrameReceived(frameTxt, frame.isFinalFrame());
@@ -199,7 +239,9 @@ void QWebSocketDataProcessor::process(QIODevice *pIoDevice)
             clear();
             isDone = true;
         }
+        frame.clear();
     }
+    return true;
 }
 
 /*!
@@ -301,4 +343,14 @@ bool QWebSocketDataProcessor::processControlFrame(const QWebSocketFrame &frame)
     return mustStopProcessing;
 }
 
+/*!
+    \internal
+ */
+void QWebSocketDataProcessor::timeout()
+{
+    clear();
+    Q_EMIT errorEncountered(QWebSocketProtocol::CloseCodeGoingAway,
+                            tr("Timeout when reading data from socket."));
+}
+
 QT_END_NAMESPACE
diff --git a/src/websockets/qwebsocketdataprocessor_p.h b/src/websockets/qwebsocketdataprocessor_p.h
index e80a843..62a2dc0 100644
--- a/src/websockets/qwebsocketdataprocessor_p.h
+++ b/src/websockets/qwebsocketdataprocessor_p.h
@@ -55,6 +55,8 @@
 #include <QtCore/QByteArray>
 #include <QtCore/QString>
 #include <QtCore/QTextCodec>
+#include <QTimer>
+#include "qwebsocketframe_p.h"
 #include "qwebsocketprotocol.h"
 #include "qwebsocketprotocol_p.h"
 
@@ -63,6 +65,8 @@ QT_BEGIN_NAMESPACE
 class QIODevice;
 class QWebSocketFrame;
 
+const quint64 MAX_MESSAGE_SIZE_IN_BYTES = std::numeric_limits<int>::max() - 1;
+
 class Q_AUTOTEST_EXPORT QWebSocketDataProcessor : public QObject
 {
     Q_OBJECT
@@ -72,6 +76,10 @@ public:
     explicit QWebSocketDataProcessor(QObject *parent = nullptr);
     ~QWebSocketDataProcessor() override;
 
+    void setMaxAllowedFrameSize(quint64 maxAllowedFrameSize);
+    quint64 maxAllowedFrameSize() const;
+    void setMaxAllowedMessageSize(quint64 maxAllowedMessageSize);
+    quint64 maxAllowedMessageSize() const;
     static quint64 maxMessageSize();
     static quint64 maxFrameSize();
 
@@ -86,7 +94,7 @@ Q_SIGNALS:
     void errorEncountered(QWebSocketProtocol::CloseCode code, const QString &description);
 
 public Q_SLOTS:
-    void process(QIODevice *pIoDevice);
+    bool process(QIODevice *pIoDevice);
     void clear();
 
 private:
@@ -111,8 +119,12 @@ private:
     quint64 m_payloadLength;
     QTextCodec::ConverterState *m_pConverterState;
     QTextCodec *m_pTextCodec;
+    QWebSocketFrame frame;
+    QTimer waitTimer;
+    quint64 m_maxAllowedMessageSize = MAX_MESSAGE_SIZE_IN_BYTES;
 
     bool processControlFrame(const QWebSocketFrame &frame);
+    void timeout();
 };
 
 QT_END_NAMESPACE
diff --git a/src/websockets/qwebsocketframe.cpp b/src/websockets/qwebsocketframe.cpp
index 041302e..716aebd 100644
--- a/src/websockets/qwebsocketframe.cpp
+++ b/src/websockets/qwebsocketframe.cpp
@@ -64,118 +64,26 @@ QT_BEGIN_NAMESPACE
 /*!
     \internal
  */
-QWebSocketFrame::QWebSocketFrame() :
-    m_closeCode(QWebSocketProtocol::CloseCodeNormal),
-    m_closeReason(),
-    m_mask(0),
-    m_opCode(QWebSocketProtocol::OpCodeReservedC),
-    m_length(0),
-    m_payload(),
-    m_isFinalFrame(true),
-    m_rsv1(false),
-    m_rsv2(false),
-    m_rsv3(false),
-    m_isValid(false)
+void QWebSocketFrame::setMaxAllowedFrameSize(quint64 maxAllowedFrameSize)
 {
+    if (maxAllowedFrameSize <= maxFrameSize())
+        m_maxAllowedFrameSize = maxAllowedFrameSize;
 }
 
 /*!
     \internal
  */
-QWebSocketFrame::QWebSocketFrame(const QWebSocketFrame &other) :
-    m_closeCode(other.m_closeCode),
-    m_closeReason(other.m_closeReason),
-    m_mask(other.m_mask),
-    m_opCode(other.m_opCode),
-    m_length(other.m_length),
-    m_payload(other.m_payload),
-    m_isFinalFrame(other.m_isFinalFrame),
-    m_rsv1(other.m_rsv1),
-    m_rsv2(other.m_rsv2),
-    m_rsv3(other.m_rsv3),
-    m_isValid(other.m_isValid)
+quint64 QWebSocketFrame::maxAllowedFrameSize() const
 {
+    return m_maxAllowedFrameSize;
 }
 
 /*!
     \internal
  */
-QWebSocketFrame &QWebSocketFrame::operator =(const QWebSocketFrame &other)
+quint64 QWebSocketFrame::maxFrameSize()
 {
-    m_closeCode = other.m_closeCode;
-    m_closeReason = other.m_closeReason;
-    m_isFinalFrame = other.m_isFinalFrame;
-    m_mask = other.m_mask;
-    m_rsv1 = other.m_rsv1;
-    m_rsv2 = other.m_rsv2;
-    m_rsv3 = other.m_rsv3;
-    m_opCode = other.m_opCode;
-    m_length = other.m_length;
-    m_payload = other.m_payload;
-    m_isValid = other.m_isValid;
-
-    return *this;
-}
-
-#ifdef Q_COMPILER_RVALUE_REFS
-/*!
-    \internal
- */
-QWebSocketFrame::QWebSocketFrame(QWebSocketFrame &&other) :
-    m_closeCode(qMove(other.m_closeCode)),
-    m_closeReason(qMove(other.m_closeReason)),
-    m_mask(qMove(other.m_mask)),
-    m_opCode(qMove(other.m_opCode)),
-    m_length(qMove(other.m_length)),
-    m_payload(qMove(other.m_payload)),
-    m_isFinalFrame(qMove(other.m_isFinalFrame)),
-    m_rsv1(qMove(other.m_rsv1)),
-    m_rsv2(qMove(other.m_rsv2)),
-    m_rsv3(qMove(other.m_rsv3)),
-    m_isValid(qMove(other.m_isValid))
-{}
-
-
-/*!
-    \internal
- */
-QWebSocketFrame &QWebSocketFrame::operator =(QWebSocketFrame &&other)
-{
-    qSwap(m_closeCode, other.m_closeCode);
-    qSwap(m_closeReason, other.m_closeReason);
-    qSwap(m_isFinalFrame, other.m_isFinalFrame);
-    qSwap(m_mask, other.m_mask);
-    qSwap(m_rsv1, other.m_rsv1);
-    qSwap(m_rsv2, other.m_rsv2);
-    qSwap(m_rsv3, other.m_rsv3);
-    qSwap(m_opCode, other.m_opCode);
-    qSwap(m_length, other.m_length);
-    qSwap(m_payload, other.m_payload);
-    qSwap(m_isValid, other.m_isValid);
-
-    return *this;
-}
-
-#endif
-
-/*!
-    \internal
- */
-void QWebSocketFrame::swap(QWebSocketFrame &other)
-{
-    if (&other != this) {
-        qSwap(m_closeCode, other.m_closeCode);
-        qSwap(m_closeReason, other.m_closeReason);
-        qSwap(m_isFinalFrame, other.m_isFinalFrame);
-        qSwap(m_mask, other.m_mask);
-        qSwap(m_rsv1, other.m_rsv1);
-        qSwap(m_rsv2, other.m_rsv2);
-        qSwap(m_rsv3, other.m_rsv3);
-        qSwap(m_opCode, other.m_opCode);
-        qSwap(m_length, other.m_length);
-        qSwap(m_payload, other.m_payload);
-        qSwap(m_isValid, other.m_isValid);
-    }
+    return MAX_FRAME_SIZE_IN_BYTES;
 }
 
 /*!
@@ -183,7 +91,7 @@ void QWebSocketFrame::swap(QWebSocketFrame &other)
  */
 QWebSocketProtocol::CloseCode QWebSocketFrame::closeCode() const
 {
-    return m_closeCode;
+    return isDone() ? m_closeCode : QWebSocketProtocol::CloseCodeGoingAway;
 }
 
 /*!
@@ -191,7 +99,7 @@ QWebSocketProtocol::CloseCode QWebSocketFrame::closeCode() const
  */
 QString QWebSocketFrame::closeReason() const
 {
-    return m_closeReason;
+    return isDone() ? m_closeReason : tr("Waiting for more data from socket.");
 }
 
 /*!
@@ -276,6 +184,7 @@ void QWebSocketFrame::clear()
     m_length = 0;
     m_payload.clear();
     m_isValid = false;
+    m_processingState = PS_READ_HEADER;
 }
 
 /*!
@@ -283,215 +192,211 @@ void QWebSocketFrame::clear()
  */
 bool QWebSocketFrame::isValid() const
 {
-    return m_isValid;
+    return isDone() && m_isValid;
 }
 
-#define WAIT_FOR_MORE_DATA(dataSizeInBytes)  \
-    { returnState = processingState; \
-      processingState = PS_WAIT_FOR_MORE_DATA; dataWaitSize = dataSizeInBytes; }
+/*!
+    \internal
+ */
+bool QWebSocketFrame::isDone() const
+{
+    return m_processingState == PS_DISPATCH_RESULT;
+}
 
 /*!
     \internal
  */
-QWebSocketFrame QWebSocketFrame::readFrame(QIODevice *pIoDevice)
+void QWebSocketFrame::readFrame(QIODevice *pIoDevice)
 {
-    bool isDone = false;
-    qint64 bytesRead = 0;
-    QWebSocketFrame frame;
-    quint64 dataWaitSize = 0;
-    Q_UNUSED(dataWaitSize); // value is used in MACRO, Q_UNUSED to avoid compiler warnings
-    ProcessingState processingState = PS_READ_HEADER;
-    ProcessingState returnState = PS_READ_HEADER;
-    bool hasMask = false;
-    quint64 payloadLength = 0;
-
-    while (!isDone)
+    while (true)
     {
-        switch (processingState) {
-        case PS_WAIT_FOR_MORE_DATA:
-            //TODO: waitForReadyRead should really be changed
-            //now, when a WebSocket is used in a GUI thread
-            //the GUI will hang for at most 5 seconds
-            //maybe, a QStateMachine should be used
-            if (!pIoDevice->waitForReadyRead(5000)) {
-                frame.setError(QWebSocketProtocol::CloseCodeGoingAway,
-                               tr("Timeout when reading data from socket."));
-                processingState = PS_DISPATCH_RESULT;
-            } else {
-                processingState = returnState;
-            }
-            break;
-
+        switch (m_processingState) {
         case PS_READ_HEADER:
-            if (Q_LIKELY(pIoDevice->bytesAvailable() >= 2)) {
-                //FIN, RSV1-3, Opcode
-                char header[2] = {0};
-                bytesRead = pIoDevice->read(header, 2);
-                frame.m_isFinalFrame = (header[0] & 0x80) != 0;
-                frame.m_rsv1 = (header[0] & 0x40);
-                frame.m_rsv2 = (header[0] & 0x20);
-                frame.m_rsv3 = (header[0] & 0x10);
-                frame.m_opCode = static_cast<QWebSocketProtocol::OpCode>(header[0] & 0x0F);
-
-                //Mask, PayloadLength
-                hasMask = (header[1] & 0x80) != 0;
-                frame.m_length = (header[1] & 0x7F);
-
-                switch (frame.m_length)
-                {
-                    case 126:
-                    {
-                        processingState = PS_READ_PAYLOAD_LENGTH;
-                        break;
-                    }
-                    case 127:
-                    {
-                        processingState = PS_READ_BIG_PAYLOAD_LENGTH;
-                        break;
-                    }
-                    default:
-                    {
-                        payloadLength = frame.m_length;
-                        processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
-                        break;
-                    }
-                }
-                if (!frame.checkValidity())
-                    processingState = PS_DISPATCH_RESULT;
-            } else {
-                WAIT_FOR_MORE_DATA(2);
+            m_processingState = readFrameHeader(pIoDevice);
+            if (m_processingState == PS_WAIT_FOR_MORE_DATA) {
+                m_processingState = PS_READ_HEADER;
+                return;
             }
             break;
 
         case PS_READ_PAYLOAD_LENGTH:
-            if (Q_LIKELY(pIoDevice->bytesAvailable() >= 2)) {
-                uchar length[2] = {0};
-                bytesRead = pIoDevice->read(reinterpret_cast<char *>(length), 2);
-                if (Q_UNLIKELY(bytesRead == -1)) {
-                    frame.setError(QWebSocketProtocol::CloseCodeGoingAway,
-                                   tr("Error occurred while reading from the network: %1")
-                                        .arg(pIoDevice->errorString()));
-                    processingState = PS_DISPATCH_RESULT;
-                } else {
-                    payloadLength = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(length));
-                    if (Q_UNLIKELY(payloadLength < 126)) {
-                        //see http://tools.ietf.org/html/rfc6455#page-28 paragraph 5.2
-                        //"in all cases, the minimal number of bytes MUST be used to encode
-                        //the length, for example, the length of a 124-byte-long string
-                        //can't be encoded as the sequence 126, 0, 124"
-                        frame.setError(QWebSocketProtocol::CloseCodeProtocolError,
-                                       tr("Lengths smaller than 126 " \
-                                                   "must be expressed as one byte."));
-                        processingState = PS_DISPATCH_RESULT;
-                    } else {
-                        processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
-                    }
-                }
-            } else {
-                WAIT_FOR_MORE_DATA(2);
+            m_processingState = readFramePayloadLength(pIoDevice);
+            if (m_processingState == PS_WAIT_FOR_MORE_DATA) {
+                m_processingState = PS_READ_PAYLOAD_LENGTH;
+                return;
             }
             break;
 
-        case PS_READ_BIG_PAYLOAD_LENGTH:
-            if (Q_LIKELY(pIoDevice->bytesAvailable() >= 8)) {
-                uchar length[8] = {0};
-                bytesRead = pIoDevice->read(reinterpret_cast<char *>(length), 8);
-                if (Q_UNLIKELY(bytesRead < 8)) {
-                    frame.setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
-                                   tr("Something went wrong during "\
-                                               "reading from the network."));
-                    processingState = PS_DISPATCH_RESULT;
-                } else {
-                    //Most significant bit must be set to 0 as
-                    //per http://tools.ietf.org/html/rfc6455#section-5.2
-                    payloadLength = qFromBigEndian<quint64>(length);
-                    if (Q_UNLIKELY(payloadLength & (quint64(1) << 63))) {
-                        frame.setError(QWebSocketProtocol::CloseCodeProtocolError,
-                                       tr("Highest bit of payload length is not 0."));
-                        processingState = PS_DISPATCH_RESULT;
-                    } else if (Q_UNLIKELY(payloadLength <= 0xFFFFu)) {
-                        //see http://tools.ietf.org/html/rfc6455#page-28 paragraph 5.2
-                        //"in all cases, the minimal number of bytes MUST be used to encode
-                        //the length, for example, the length of a 124-byte-long string
-                        //can't be encoded as the sequence 126, 0, 124"
-                        frame.setError(QWebSocketProtocol::CloseCodeProtocolError,
-                                       tr("Lengths smaller than 65536 (2^16) " \
-                                                   "must be expressed as 2 bytes."));
-                        processingState = PS_DISPATCH_RESULT;
-                    } else {
-                        processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
-                    }
-                }
-            } else {
-                WAIT_FOR_MORE_DATA(8);
-            }
-
-            break;
-
         case PS_READ_MASK:
-            if (Q_LIKELY(pIoDevice->bytesAvailable() >= 4)) {
-                bytesRead = pIoDevice->read(reinterpret_cast<char *>(&frame.m_mask),
-                                            sizeof(frame.m_mask));
-                if (bytesRead == -1) {
-                    frame.setError(QWebSocketProtocol::CloseCodeGoingAway,
-                                   tr("Error while reading from the network: %1.")
-                                        .arg(pIoDevice->errorString()));
-                    processingState = PS_DISPATCH_RESULT;
-                } else {
-                    frame.m_mask = qFromBigEndian(frame.m_mask);
-                    processingState = PS_READ_PAYLOAD;
-                }
-            } else {
-                WAIT_FOR_MORE_DATA(4);
+            m_processingState = readFrameMask(pIoDevice);
+            if (m_processingState == PS_WAIT_FOR_MORE_DATA) {
+                m_processingState = PS_READ_MASK;
+                return;
             }
             break;
 
         case PS_READ_PAYLOAD:
-            if (!payloadLength) {
-                processingState = PS_DISPATCH_RESULT;
-            } else if (Q_UNLIKELY(payloadLength > MAX_FRAME_SIZE_IN_BYTES)) {
-                frame.setError(QWebSocketProtocol::CloseCodeTooMuchData,
-                               tr("Maximum framesize exceeded."));
-                processingState = PS_DISPATCH_RESULT;
-            } else {
-                quint64 bytesAvailable = quint64(pIoDevice->bytesAvailable());
-                if (bytesAvailable >= payloadLength) {
-                    frame.m_payload = pIoDevice->read(int(payloadLength));
-                    //payloadLength can be safely cast to an integer,
-                    //because MAX_FRAME_SIZE_IN_BYTES = MAX_INT
-                    if (Q_UNLIKELY(frame.m_payload.length() != int(payloadLength))) {
-                        //some error occurred; refer to the Qt documentation of QIODevice::read()
-                        frame.setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
-                                       tr("Some serious error occurred " \
-                                                   "while reading from the network."));
-                        processingState = PS_DISPATCH_RESULT;
-                    } else {
-                        if (hasMask)
-                            QWebSocketProtocol::mask(&frame.m_payload, frame.m_mask);
-                        processingState = PS_DISPATCH_RESULT;
-                    }
-                } else {
-                    //if payload is too big, then this will timeout
-                    WAIT_FOR_MORE_DATA(payloadLength);
-                }
+            m_processingState = readFramePayload(pIoDevice);
+            if (m_processingState == PS_WAIT_FOR_MORE_DATA) {
+                m_processingState = PS_READ_PAYLOAD;
+                return;
             }
             break;
 
         case PS_DISPATCH_RESULT:
-            processingState = PS_READ_HEADER;
-            isDone = true;
-            break;
+            return;
 
         default:
-            //should not come here
-            qWarning() << "DataProcessor::process: Found invalid state. This should not happen!";
-            frame.clear();
-            isDone = true;
-            break;
-        }	//end switch
+            Q_UNREACHABLE();
+            return;
+        }
     }
+}
 
-    return frame;
+/*!
+    \internal
+ */
+QWebSocketFrame::ProcessingState QWebSocketFrame::readFrameHeader(QIODevice *pIoDevice)
+{
+    if (Q_LIKELY(pIoDevice->bytesAvailable() >= 2)) {
+        // FIN, RSV1-3, Opcode
+        char header[2] = {0};
+        if (Q_UNLIKELY(pIoDevice->read(header, 2) < 2)) {
+            setError(QWebSocketProtocol::CloseCodeGoingAway,
+                     tr("Error occurred while reading header from the network: %1")
+                        .arg(pIoDevice->errorString()));
+            return PS_DISPATCH_RESULT;
+        }
+        m_isFinalFrame = (header[0] & 0x80) != 0;
+        m_rsv1 = (header[0] & 0x40);
+        m_rsv2 = (header[0] & 0x20);
+        m_rsv3 = (header[0] & 0x10);
+        m_opCode = static_cast<QWebSocketProtocol::OpCode>(header[0] & 0x0F);
+
+        // Mask
+        // Use zero as mask value to mean there's no mask to read.
+        // When the mask value is read, it over-writes this non-zero value.
+        m_mask = header[1] & 0x80;
+        // PayloadLength
+        m_length = (header[1] & 0x7F);
+
+        if (!checkValidity())
+            return PS_DISPATCH_RESULT;
+
+        switch (m_length) {
+        case 126:
+        case 127:
+            return PS_READ_PAYLOAD_LENGTH;
+        default:
+            return hasMask() ? PS_READ_MASK : PS_READ_PAYLOAD;
+        }
+    }
+    return PS_WAIT_FOR_MORE_DATA;
+}
+
+/*!
+    \internal
+ */
+QWebSocketFrame::ProcessingState QWebSocketFrame::readFramePayloadLength(QIODevice *pIoDevice)
+{
+    // see http://tools.ietf.org/html/rfc6455#page-28 paragraph 5.2
+    // in all cases, the minimal number of bytes MUST be used to encode the length,
+    // for example, the length of a 124-byte-long string can't be encoded as the
+    // sequence 126, 0, 124"
+    switch (m_length) {
+    case 126:
+        if (Q_LIKELY(pIoDevice->bytesAvailable() >= 2)) {
+            uchar length[2] = {0};
+            if (Q_UNLIKELY(pIoDevice->read(reinterpret_cast<char *>(length), 2) < 2)) {
+                setError(QWebSocketProtocol::CloseCodeGoingAway,
+                         tr("Error occurred while reading from the network: %1")
+                            .arg(pIoDevice->errorString()));
+                return PS_DISPATCH_RESULT;
+            }
+            m_length = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(length));
+            if (Q_UNLIKELY(m_length < 126)) {
+
+                setError(QWebSocketProtocol::CloseCodeProtocolError,
+                            tr("Lengths smaller than 126 must be expressed as one byte."));
+                return PS_DISPATCH_RESULT;
+            }
+            return hasMask() ? PS_READ_MASK : PS_READ_PAYLOAD;
+        }
+        break;
+    case 127:
+        if (Q_LIKELY(pIoDevice->bytesAvailable() >= 8)) {
+            uchar length[8] = {0};
+            if (Q_UNLIKELY(pIoDevice->read(reinterpret_cast<char *>(length), 8) < 8)) {
+                setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
+                         tr("Something went wrong during reading from the network."));
+                return PS_DISPATCH_RESULT;
+            }
+            // Most significant bit must be set to 0 as
+            // per http://tools.ietf.org/html/rfc6455#section-5.2
+            m_length = qFromBigEndian<quint64>(length);
+            if (Q_UNLIKELY(m_length & (quint64(1) << 63))) {
+                setError(QWebSocketProtocol::CloseCodeProtocolError,
+                            tr("Highest bit of payload length is not 0."));
+                return PS_DISPATCH_RESULT;
+            }
+            if (Q_UNLIKELY(m_length <= 0xFFFFu)) {
+                setError(QWebSocketProtocol::CloseCodeProtocolError,
+                            tr("Lengths smaller than 65536 (2^16) must be expressed as 2 bytes."));
+                return PS_DISPATCH_RESULT;
+            }
+            return hasMask() ? PS_READ_MASK : PS_READ_PAYLOAD;
+        }
+        break;
+    default:
+        Q_UNREACHABLE();
+        break;
+    }
+    return PS_WAIT_FOR_MORE_DATA;
+}
+
+/*!
+    \internal
+ */
+QWebSocketFrame::ProcessingState QWebSocketFrame::readFrameMask(QIODevice *pIoDevice)
+{
+    if (Q_LIKELY(pIoDevice->bytesAvailable() >= 4)) {
+        if (Q_UNLIKELY(pIoDevice->read(reinterpret_cast<char *>(&m_mask), sizeof(m_mask)) < 4)) {
+            setError(QWebSocketProtocol::CloseCodeGoingAway,
+                     tr("Error while reading from the network: %1.").arg(pIoDevice->errorString()));
+            return PS_DISPATCH_RESULT;
+        }
+        m_mask = qFromBigEndian(m_mask);
+        return PS_READ_PAYLOAD;
+    }
+    return PS_WAIT_FOR_MORE_DATA;
+}
+
+/*!
+    \internal
+ */
+QWebSocketFrame::ProcessingState QWebSocketFrame::readFramePayload(QIODevice *pIoDevice)
+{
+    if (!m_length)
+        return PS_DISPATCH_RESULT;
+
+    if (Q_UNLIKELY(m_length > maxAllowedFrameSize())) {
+        setError(QWebSocketProtocol::CloseCodeTooMuchData, tr("Maximum framesize exceeded."));
+        return PS_DISPATCH_RESULT;
+    }
+    if (quint64(pIoDevice->bytesAvailable()) >= m_length) {
+        m_payload = pIoDevice->read(int(m_length));
+        // m_length can be safely cast to an integer,
+        // because MAX_FRAME_SIZE_IN_BYTES = MAX_INT
+        if (Q_UNLIKELY(m_payload.length() != int(m_length))) {
+            // some error occurred; refer to the Qt documentation of QIODevice::read()
+            setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
+                     tr("Some serious error occurred while reading from the network."));
+        } else if (hasMask()) {
+            QWebSocketProtocol::mask(&m_payload, mask());
+        }
+        return PS_DISPATCH_RESULT;
+    }
+    return PS_WAIT_FOR_MORE_DATA;
 }
 
 /*!
diff --git a/src/websockets/qwebsocketframe_p.h b/src/websockets/qwebsocketframe_p.h
index 5c3a7df..992379a 100644
--- a/src/websockets/qwebsocketframe_p.h
+++ b/src/websockets/qwebsocketframe_p.h
@@ -54,7 +54,7 @@
 #include <QtCore/QString>
 #include <QtCore/QByteArray>
 #include <QtCore/QCoreApplication>
-#include <limits.h>
+#include <limits>
 
 #include "qwebsockets_global.h"
 #include "qwebsocketprotocol.h"
@@ -64,25 +64,18 @@ QT_BEGIN_NAMESPACE
 
 class QIODevice;
 
-const quint64 MAX_FRAME_SIZE_IN_BYTES = INT_MAX - 1;
-const quint64 MAX_MESSAGE_SIZE_IN_BYTES = INT_MAX - 1;
+const quint64 MAX_FRAME_SIZE_IN_BYTES = std::numeric_limits<int>::max() - 1;
 
 class Q_AUTOTEST_EXPORT QWebSocketFrame
 {
     Q_DECLARE_TR_FUNCTIONS(QWebSocketFrame)
 
 public:
-    QWebSocketFrame();
-    QWebSocketFrame(const QWebSocketFrame &other);
+    QWebSocketFrame() = default;
 
-    QWebSocketFrame &operator =(const QWebSocketFrame &other);
-
-#ifdef Q_COMPILER_RVALUE_REFS
-    QWebSocketFrame(QWebSocketFrame &&other);
-    QWebSocketFrame &operator =(QWebSocketFrame &&other);
-#endif
-
-    void swap(QWebSocketFrame &other);
+    void setMaxAllowedFrameSize(quint64 maxAllowedFrameSize);
+    quint64 maxAllowedFrameSize() const;
+    static quint64 maxFrameSize();
 
     QWebSocketProtocol::CloseCode closeCode() const;
     QString closeReason() const;
@@ -101,33 +94,39 @@ public:
     void clear();
 
     bool isValid() const;
+    bool isDone() const;
 
-    static QWebSocketFrame readFrame(QIODevice *pIoDevice);
+    void readFrame(QIODevice *pIoDevice);
 
 private:
-    QWebSocketProtocol::CloseCode m_closeCode;
     QString m_closeReason;
-    quint32 m_mask;
-    QWebSocketProtocol::OpCode m_opCode;
-    quint8 m_length;
     QByteArray m_payload;
-
-    bool m_isFinalFrame;
-    bool m_rsv1;
-    bool m_rsv2;
-    bool m_rsv3;
-    bool m_isValid;
+    quint64 m_length = 0;
+    quint32 m_mask = 0;
+    QWebSocketProtocol::CloseCode m_closeCode = QWebSocketProtocol::CloseCodeNormal;
+    QWebSocketProtocol::OpCode m_opCode = QWebSocketProtocol::OpCodeReservedC;
 
     enum ProcessingState
     {
         PS_READ_HEADER,
         PS_READ_PAYLOAD_LENGTH,
-        PS_READ_BIG_PAYLOAD_LENGTH,
         PS_READ_MASK,
         PS_READ_PAYLOAD,
         PS_DISPATCH_RESULT,
         PS_WAIT_FOR_MORE_DATA
-    };
+    } m_processingState = PS_READ_HEADER;
+
+    bool m_isFinalFrame = true;
+    bool m_rsv1 = false;
+    bool m_rsv2 = false;
+    bool m_rsv3 = false;
+    bool m_isValid = false;
+    quint64 m_maxAllowedFrameSize = MAX_FRAME_SIZE_IN_BYTES;
+
+    ProcessingState readFrameHeader(QIODevice *pIoDevice);
+    ProcessingState readFramePayloadLength(QIODevice *pIoDevice);
+    ProcessingState readFrameMask(QIODevice *pIoDevice);
+    ProcessingState readFramePayload(QIODevice *pIoDevice);
 
     void setError(QWebSocketProtocol::CloseCode code, const QString &closeReason);
     bool checkValidity();
diff --git a/src/websockets/qwebsocketserver_p.cpp b/src/websockets/qwebsocketserver_p.cpp
index f3e7eac..d9d79d9 100644
--- a/src/websockets/qwebsocketserver_p.cpp
+++ b/src/websockets/qwebsocketserver_p.cpp
@@ -416,9 +416,25 @@ void QWebSocketServerPrivate::handshakeReceived()
     //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()) {
+    // According to RFC822 the body is separated from the headers by a null line (CRLF)
+    const QByteArray& endOfHeaderMarker = QByteArrayLiteral("\r\n\r\n");
+
+    const qint64 byteAvailable = pTcpSocket->bytesAvailable();
+    QByteArray header = pTcpSocket->peek(byteAvailable);
+    const int endOfHeaderIndex = header.indexOf(endOfHeaderMarker);
+    if (endOfHeaderIndex < 0) {
+        //then we don't have our header complete yet
+        //check that no one is trying to exhaust our virtual memory
+        const qint64 maxHeaderLength = MAX_HEADERLINE_LENGTH * MAX_HEADERLINES + endOfHeaderMarker.size();
+        if (byteAvailable > maxHeaderLength) {
+            pTcpSocket->close();
+            setError(QWebSocketProtocol::CloseCodeTooMuchData,
+                 QWebSocketServer::tr("Header is too large."));
+        }
         return;
     }
+    const int headerSize = endOfHeaderIndex + endOfHeaderMarker.size();
+
     disconnect(pTcpSocket, &QTcpSocket::readyRead,
                this, &QWebSocketServerPrivate::handshakeReceived);
     Q_Q(QWebSocketServer);
@@ -433,8 +449,20 @@ void QWebSocketServerPrivate::handshakeReceived()
         return;
     }
 
+    //don't read past the header
+    header.resize(headerSize);
+    //remove our header from the tcpSocket
+    qint64 skippedSize = pTcpSocket->skip(headerSize);
+
+    if (skippedSize != headerSize) {
+        pTcpSocket->close();
+        setError(QWebSocketProtocol::CloseCodeProtocolError,
+                 QWebSocketServer::tr("Read handshake request header failed."));
+        return;
+    }
+
     QWebSocketHandshakeRequest request(pTcpSocket->peerPort(), isSecure);
-    QTextStream textStream(pTcpSocket);
+    QTextStream textStream(header, QIODevice::ReadOnly);
     request.readHandshake(textStream, MAX_HEADERLINE_LENGTH, MAX_HEADERLINES);
 
     if (request.isValid()) {
@@ -487,11 +515,13 @@ void QWebSocketServerPrivate::handleConnection(QTcpSocket *pTcpSocket) const
         QObjectPrivate::connect(pTcpSocket, &QTcpSocket::readyRead,
                                 this, &QWebSocketServerPrivate::handshakeReceived,
                                 Qt::QueuedConnection);
-        if (pTcpSocket->canReadLine()) {
-            // We received some data! We must emit now to be sure that handshakeReceived is called
-            // since the data could have been received before the signal and slot was connected.
-            emit pTcpSocket->readyRead();
+
+        // We received some data! We must emit now to be sure that handshakeReceived is called
+        // since the data could have been received before the signal and slot was connected.
+        if (pTcpSocket->bytesAvailable()) {
+            Q_EMIT pTcpSocket->readyRead();
         }
+
         QObjectPrivate::connect(pTcpSocket, &QTcpSocket::disconnected,
                                 this, &QWebSocketServerPrivate::onSocketDisconnected);
     }
diff --git a/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp b/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp
index f9a91d5..5390ff0 100644
--- a/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp
+++ b/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp
@@ -193,7 +193,7 @@ private:
     //sequences
     void nonCharacterSequence(const char *sequence);
 
-    void doTest();
+    void doTest(int timeout = 0);
     void doCloseFrameTest();
 
     QString opCodeToString(quint8 opCode);
@@ -744,6 +744,7 @@ void tst_DataProcessor::frameTooSmall()
 
     dataProcessor.process(&buffer);
 
+    QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000);
     QCOMPARE(errorSpy.count(), 1);
     QCOMPARE(closeSpy.count(), 0);
     QCOMPARE(pingMessageSpy.count(), 0);
@@ -776,6 +777,7 @@ void tst_DataProcessor::frameTooSmall()
 
     dataProcessor.process(&buffer);
 
+    QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000);
     QCOMPARE(errorSpy.count(), 1);
     QCOMPARE(closeSpy.count(), 0);
     QCOMPARE(pingMessageSpy.count(), 0);
@@ -808,6 +810,24 @@ void tst_DataProcessor::frameTooSmall()
 
         dataProcessor.process(&buffer);
 
+        QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000);
+        QCOMPARE(errorSpy.count(), 1);
+        QCOMPARE(closeSpy.count(), 0);
+        QCOMPARE(pingMessageSpy.count(), 0);
+        QCOMPARE(pongMessageSpy.count(), 0);
+        QCOMPARE(textMessageSpy.count(), 0);
+        QCOMPARE(binaryMessageSpy.count(), 0);
+        QCOMPARE(textFrameSpy.count(), 1);
+        QCOMPARE(binaryFrameSpy.count(), 0);
+
+        errorSpy.clear();
+        closeSpy.clear();
+        pingMessageSpy.clear();
+        pongMessageSpy.clear();
+        textMessageSpy.clear();
+        binaryMessageSpy.clear();
+        textFrameSpy.clear();
+        binaryFrameSpy.clear();
         buffer.close();
         data.clear();
 
@@ -816,17 +836,16 @@ void tst_DataProcessor::frameTooSmall()
         //meaning the socket will be closed
         buffer.setData(data);
         buffer.open(QIODevice::ReadOnly);
-        QSignalSpy errorSpy(&dataProcessor,
-                            SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
         dataProcessor.process(&buffer);
 
+        QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000);
         QCOMPARE(errorSpy.count(), 1);
         QCOMPARE(closeSpy.count(), 0);
         QCOMPARE(pingMessageSpy.count(), 0);
         QCOMPARE(pongMessageSpy.count(), 0);
         QCOMPARE(textMessageSpy.count(), 0);
         QCOMPARE(binaryMessageSpy.count(), 0);
-        QCOMPARE(textFrameSpy.count(), 1);
+        QCOMPARE(textFrameSpy.count(), 0);
         QCOMPARE(binaryFrameSpy.count(), 0);
 
         QList<QVariant> arguments = errorSpy.takeFirst();
@@ -849,6 +868,7 @@ void tst_DataProcessor::frameTooSmall()
         buffer.open(QIODevice::ReadOnly);
         dataProcessor.process(&buffer);
 
+        QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000);
         QCOMPARE(errorSpy.count(), 1);
         QCOMPARE(closeSpy.count(), 0);
         QCOMPARE(pingMessageSpy.count(), 0);
@@ -877,6 +897,7 @@ void tst_DataProcessor::frameTooSmall()
         buffer.open(QIODevice::ReadOnly);
 
         dataProcessor.process(&buffer);
+        QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000);
         QCOMPARE(errorSpy.count(), 1);
         QCOMPARE(closeSpy.count(), 0);
         QCOMPARE(pingMessageSpy.count(), 0);
@@ -1400,7 +1421,7 @@ void tst_DataProcessor::incompletePayload_data()
 
 void tst_DataProcessor::incompletePayload()
 {
-    doTest();
+    doTest(7000);
 }
 
 void tst_DataProcessor::incompleteSizeField_data()
@@ -1430,13 +1451,13 @@ void tst_DataProcessor::incompleteSizeField_data()
 
 void tst_DataProcessor::incompleteSizeField()
 {
-    doTest();
+    doTest(7000);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
 /// HELPER FUNCTIONS
 //////////////////////////////////////////////////////////////////////////////////////////
-void tst_DataProcessor::doTest()
+void tst_DataProcessor::doTest(int timeout)
 {
     QFETCH(quint8, firstByte);
     QFETCH(quint8, secondByte);
@@ -1465,6 +1486,7 @@ void tst_DataProcessor::doTest()
     buffer.setData(data);
     buffer.open(QIODevice::ReadOnly);
     dataProcessor.process(&buffer);
+    QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), timeout);
     QCOMPARE(errorSpy.count(), 1);
     QCOMPARE(textMessageSpy.count(), 0);
     QCOMPARE(binaryMessageSpy.count(), 0);
diff --git a/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp b/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp
index 2bb5d16..aca3f40 100644
--- a/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp
+++ b/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp
@@ -39,7 +39,9 @@ class EchoServer : public QObject
 {
     Q_OBJECT
 public:
-    explicit EchoServer(QObject *parent = nullptr);
+    explicit EchoServer(QObject *parent = nullptr,
+        quint64 maxAllowedIncomingMessageSize = QWebSocket::maxIncomingMessageSize(),
+        quint64 maxAllowedIncomingFrameSize = QWebSocket::maxIncomingFrameSize());
     ~EchoServer();
 
     QHostAddress hostAddress() const { return m_pWebSocketServer->serverAddress(); }
@@ -57,13 +59,17 @@ private Q_SLOTS:
 
 private:
     QWebSocketServer *m_pWebSocketServer;
+    quint64 m_maxAllowedIncomingMessageSize;
+    quint64 m_maxAllowedIncomingFrameSize;
     QList<QWebSocket *> m_clients;
 };
 
-EchoServer::EchoServer(QObject *parent) :
+EchoServer::EchoServer(QObject *parent, quint64 maxAllowedIncomingMessageSize, quint64 maxAllowedIncomingFrameSize) :
     QObject(parent),
     m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Echo Server"),
                                             QWebSocketServer::NonSecureMode, this)),
+    m_maxAllowedIncomingMessageSize(maxAllowedIncomingMessageSize),
+    m_maxAllowedIncomingFrameSize(maxAllowedIncomingFrameSize),
     m_clients()
 {
     if (m_pWebSocketServer->listen(QHostAddress(QStringLiteral("127.0.0.1")))) {
@@ -82,6 +88,9 @@ void EchoServer::onNewConnection()
 {
     QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();
 
+    pSocket->setMaxAllowedIncomingFrameSize(m_maxAllowedIncomingFrameSize);
+    pSocket->setMaxAllowedIncomingMessageSize(m_maxAllowedIncomingMessageSize);
+
     Q_EMIT newConnection(pSocket->requestUrl());
     Q_EMIT newConnection(pSocket->request());
 
@@ -144,6 +153,9 @@ private Q_SLOTS:
     void tst_setProxy();
 #endif
     void overlongCloseReason();
+    void incomingMessageTooLong();
+    void incomingFrameTooLong();
+    void testingFrameAndMessageSizeApi();
 };
 
 tst_QWebSocket::tst_QWebSocket()
@@ -457,12 +469,46 @@ void tst_QWebSocket::tst_sendTextMessage()
     QVERIFY(isLastFrame);
 
     socket.close();
+    socketConnectedSpy.clear();
+    textMessageReceived.clear();
+    textFrameReceived.clear();
 
-    //QTBUG-36762: QWebSocket emits multiplied signals when socket was reopened
+    // QTBUG-74464 QWebsocket doesn't receive text (binary) message with size > 32 kb
+    socket.open(url);
+
+    QTRY_COMPARE(socketConnectedSpy.count(), 1);
+    QCOMPARE(socketError.count(), 0);
+    QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
+    arguments = serverConnectedSpy.takeFirst();
+    urlConnected = arguments.at(0).toUrl();
+    QCOMPARE(urlConnected, url);
+    QCOMPARE(socket.bytesToWrite(), 0);
+
+    // transmit a long text message with 1 MB
+    QString longString(0x100000, 'a');
+    socket.sendTextMessage(longString);
+    QVERIFY(socket.bytesToWrite() > longString.length());
+    QVERIFY(textMessageReceived.wait());
+    QCOMPARE(socket.bytesToWrite(), 0);
+
+    QCOMPARE(textMessageReceived.count(), 1);
+    QCOMPARE(binaryMessageReceived.count(), 0);
+    QCOMPARE(binaryFrameReceived.count(), 0);
+    arguments = textMessageReceived.takeFirst();
+    messageReceived = arguments.at(0).toString();
+    QCOMPARE(messageReceived.length(), longString.length());
+    QCOMPARE(messageReceived, longString);
+
+    arguments = textFrameReceived.takeLast();
+    isLastFrame = arguments.at(1).toBool();
+    QVERIFY(isLastFrame);
+
+    socket.close();
     socketConnectedSpy.clear();
     textMessageReceived.clear();
     textFrameReceived.clear();
 
+    //QTBUG-36762: QWebSocket emits multiplied signals when socket was reopened
     socket.open(QUrl(QStringLiteral("ws://") + echoServer.hostAddress().toString() +
                      QStringLiteral(":") + QString::number(echoServer.port())));
 
@@ -761,6 +807,80 @@ void tst_QWebSocket::overlongCloseReason()
     QCOMPARE(socket.closeReason(), reason.leftRef(123));
     QTRY_COMPARE(socketDisconnectedSpy.count(), 1);
 }
+
+void tst_QWebSocket::incomingMessageTooLong()
+{
+//QTBUG-70693
+    quint64 maxAllowedIncomingMessageSize = 1024;
+    quint64 maxAllowedIncomingFrameSize = QWebSocket::maxIncomingFrameSize();
+
+    EchoServer echoServer(nullptr, maxAllowedIncomingMessageSize, maxAllowedIncomingFrameSize);
+
+    QWebSocket socket;
+
+    QSignalSpy socketConnectedSpy(&socket, &QWebSocket::connected);
+    QSignalSpy serverConnectedSpy(&echoServer, QOverload<QUrl>::of(&EchoServer::newConnection));
+    QSignalSpy socketDisconnectedSpy(&socket, &QWebSocket::disconnected);
+
+    QUrl url = QUrl(QStringLiteral("ws://") + echoServer.hostAddress().toString() +
+                    QStringLiteral(":") + QString::number(echoServer.port()));
+    socket.open(url);
+    QTRY_COMPARE(socketConnectedSpy.count(), 1);
+    QTRY_COMPARE(serverConnectedSpy.count(), 1);
+
+    QString payload(maxAllowedIncomingMessageSize+1, 'a');
+    QCOMPARE(socket.sendTextMessage(payload), payload.size());
+
+    QTRY_COMPARE(socketDisconnectedSpy.count(), 1);
+    QCOMPARE(socket.closeCode(), QWebSocketProtocol::CloseCodeTooMuchData);
+}
+
+void tst_QWebSocket::incomingFrameTooLong()
+{
+//QTBUG-70693
+    quint64 maxAllowedIncomingMessageSize = QWebSocket::maxIncomingMessageSize();
+    quint64 maxAllowedIncomingFrameSize = 1024;
+
+    EchoServer echoServer(nullptr, maxAllowedIncomingMessageSize, maxAllowedIncomingFrameSize);
+
+    QWebSocket socket;
+    socket.setOutgoingFrameSize(maxAllowedIncomingFrameSize+1);
+
+    QSignalSpy socketConnectedSpy(&socket, &QWebSocket::connected);
+    QSignalSpy serverConnectedSpy(&echoServer, QOverload<QUrl>::of(&EchoServer::newConnection));
+    QSignalSpy socketDisconnectedSpy(&socket, &QWebSocket::disconnected);
+
+    QUrl url = QUrl(QStringLiteral("ws://") + echoServer.hostAddress().toString() +
+                    QStringLiteral(":") + QString::number(echoServer.port()));
+    socket.open(url);
+    QTRY_COMPARE(socketConnectedSpy.count(), 1);
+    QTRY_COMPARE(serverConnectedSpy.count(), 1);
+
+    QString payload(maxAllowedIncomingFrameSize+1, 'a');
+    QCOMPARE(socket.sendTextMessage(payload), payload.size());
+
+    QTRY_COMPARE(socketDisconnectedSpy.count(), 1);
+    QCOMPARE(socket.closeCode(), QWebSocketProtocol::CloseCodeTooMuchData);
+}
+
+void tst_QWebSocket::testingFrameAndMessageSizeApi()
+{
+//requested by André Hartmann, QTBUG-70693
+    QWebSocket socket;
+
+    const quint64 outgoingFrameSize = 5;
+    socket.setOutgoingFrameSize(outgoingFrameSize);
+    QTRY_COMPARE(outgoingFrameSize, socket.outgoingFrameSize());
+
+    const quint64 maxAllowedIncomingFrameSize = 9;
+    socket.setMaxAllowedIncomingFrameSize(maxAllowedIncomingFrameSize);
+    QTRY_COMPARE(maxAllowedIncomingFrameSize, socket.maxAllowedIncomingFrameSize());
+
+    const quint64 maxAllowedIncomingMessageSize = 889;
+    socket.setMaxAllowedIncomingMessageSize(maxAllowedIncomingMessageSize);
+    QTRY_COMPARE(maxAllowedIncomingMessageSize, socket.maxAllowedIncomingMessageSize());
+}
+
 #endif // QT_NO_NETWORKPROXY
 
 QTEST_MAIN(tst_QWebSocket)
diff --git a/tests/auto/websockets/websocketframe/tst_websocketframe.cpp b/tests/auto/websockets/websocketframe/tst_websocketframe.cpp
index 5614df8..7046657 100644
--- a/tests/auto/websockets/websocketframe/tst_websocketframe.cpp
+++ b/tests/auto/websockets/websocketframe/tst_websocketframe.cpp
@@ -197,11 +197,12 @@ void tst_WebSocketFrame::tst_copyConstructorAndAssignment()
     QBuffer buffer(&payload);
     buffer.open(QIODevice::ReadOnly);
 
-    QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer);
+    QWebSocketFrame frame;
+    frame.readFrame(&buffer);
     buffer.close();
 
+    auto compareFrames = [](const QWebSocketFrame &other, const QWebSocketFrame &frame)
     {
-        QWebSocketFrame other(frame);
         QCOMPARE(other.closeCode(), frame.closeCode());
         QCOMPARE(other.closeReason(), frame.closeReason());
         QCOMPARE(other.hasMask(), frame.hasMask());
@@ -216,24 +217,20 @@ void tst_WebSocketFrame::tst_copyConstructorAndAssignment()
         QCOMPARE(other.rsv1(), frame.rsv1());
         QCOMPARE(other.rsv2(), frame.rsv2());
         QCOMPARE(other.rsv3(), frame.rsv3());
+    };
+
+    {
+        QWebSocketFrame other(frame);
+        compareFrames(other, frame);
     }
     {
         QWebSocketFrame other;
         other = frame;
-        QCOMPARE(other.closeCode(), frame.closeCode());
-        QCOMPARE(other.closeReason(), frame.closeReason());
-        QCOMPARE(other.hasMask(), frame.hasMask());
-        QCOMPARE(other.isContinuationFrame(), frame.isContinuationFrame());
-        QCOMPARE(other.isControlFrame(), frame.isControlFrame());
-        QCOMPARE(other.isDataFrame(), frame.isDataFrame());
-        QCOMPARE(other.isFinalFrame(), frame.isFinalFrame());
-        QCOMPARE(other.isValid(), frame.isValid());
-        QCOMPARE(other.mask(), frame.mask());
-        QCOMPARE(other.opCode(), frame.opCode());
-        QCOMPARE(other.payload(), frame.payload());
-        QCOMPARE(other.rsv1(), frame.rsv1());
-        QCOMPARE(other.rsv2(), frame.rsv2());
-        QCOMPARE(other.rsv3(), frame.rsv3());
+        compareFrames(other, frame);
+        QWebSocketFrame other2 = std::move(other);
+        compareFrames(other2, frame);
+        QWebSocketFrame other3(std::move(other2));
+        compareFrames(other3, frame);
     }
 }
 
@@ -330,7 +327,8 @@ void tst_WebSocketFrame::tst_goodFrames()
     QBuffer buffer;
     buffer.setData(wireRepresentation);
     buffer.open(QIODevice::ReadOnly);
-    QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer);
+    QWebSocketFrame frame;
+    frame.readFrame(&buffer);
     buffer.close();
     QVERIFY(frame.isValid());
     QCOMPARE(frame.rsv1(), rsv1);
@@ -495,7 +493,8 @@ void tst_WebSocketFrame::tst_invalidFrames()
     QBuffer buffer;
     buffer.setData(wireRepresentation);
     buffer.open(QIODevice::ReadOnly);
-    QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer);
+    QWebSocketFrame frame;
+    frame.readFrame(&buffer);
     buffer.close();
 
     QVERIFY(!frame.isValid());
@@ -542,7 +541,7 @@ void tst_WebSocketFrame::tst_malformedFrames_data()
     //too much data
     {
         const char bigpayloadIndicator = char(127);
-        const quint64 payloadSize = MAX_FRAME_SIZE_IN_BYTES + 1;
+        const quint64 payloadSize = QWebSocketFrame::maxFrameSize() + 1;
         uchar swapped[8] = {0};
         qToBigEndian<quint64>(payloadSize, swapped);
         QTest::newRow("Frame too big")
@@ -606,7 +605,8 @@ void tst_WebSocketFrame::tst_malformedFrames()
     QBuffer buffer;
     buffer.setData(payload);
     buffer.open(QIODevice::ReadOnly);
-    QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer);
+    QWebSocketFrame frame;
+    frame.readFrame(&buffer);
     buffer.close();
 
     QVERIFY(!frame.isValid());