summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMårten Nordheim <marten.nordheim@qt.io>2018-08-02 16:54:49 +0200
committerMårten Nordheim <marten.nordheim@qt.io>2018-08-06 10:34:38 +0000
commitcf41cd16a1f156d68f9cb4a84dd77230f29d739f (patch)
treede92f94f7e59c51f59bc8d205f633e23be39d8f2
parentb2478bfb1f9cb48e077aeefd7a52be5d74de6437 (diff)
downloadqtwebsockets-cf41cd16a1f156d68f9cb4a84dd77230f29d739f.tar.gz
Limit Close frame to 125 bytes
All control frames should be limited to 125 frames. https://tools.ietf.org/html/rfc6455#section-5.5 Task-number: QTBUG-62949 Change-Id: Id9b5a431faab6ff6edf7dc2e5c3525e999bc04ea Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io> Reviewed-by: Jesus Fernandez <Jesus.Fernandez@qt.io>
-rw-r--r--src/websockets/qwebsocket.cpp5
-rw-r--r--src/websockets/qwebsocket_p.cpp10
-rw-r--r--tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp29
3 files changed, 40 insertions, 4 deletions
diff --git a/src/websockets/qwebsocket.cpp b/src/websockets/qwebsocket.cpp
index 1b0fc35..3472fe4 100644
--- a/src/websockets/qwebsocket.cpp
+++ b/src/websockets/qwebsocket.cpp
@@ -402,7 +402,10 @@ qint64 QWebSocket::sendBinaryMessage(const QByteArray &data)
Any data in the write buffer is flushed before the socket is closed.
The \a closeCode is a QWebSocketProtocol::CloseCode indicating the reason to close, and
- \a reason describes the reason of the closure more in detail
+ \a reason describes the reason of the closure more in detail. All control
+ frames, including the Close frame, are limited to 125 bytes. Since two of
+ these are used for \a closeCode the maximum length of \a reason is 123! If
+ \a reason exceeds this limit it will be truncated.
*/
void QWebSocket::close(QWebSocketProtocol::CloseCode closeCode, const QString &reason)
{
diff --git a/src/websockets/qwebsocket_p.cpp b/src/websockets/qwebsocket_p.cpp
index f4ed311..d233b66 100644
--- a/src/websockets/qwebsocket_p.cpp
+++ b/src/websockets/qwebsocket_p.cpp
@@ -334,12 +334,14 @@ void QWebSocketPrivate::close(QWebSocketProtocol::CloseCode closeCode, QString r
if (!m_isClosingHandshakeSent) {
Q_Q(QWebSocket);
m_closeCode = closeCode;
- m_closeReason = reason;
+ // 125 is the maximum length of a control frame, and 2 bytes are used for the close code:
+ const QByteArray reasonUtf8 = reason.toUtf8().left(123);
+ m_closeReason = QString::fromUtf8(reasonUtf8);
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 (!reasonUtf8.isEmpty())
+ payload.append(reasonUtf8);
quint32 maskingKey = 0;
if (m_mustMask) {
maskingKey = generateMaskingKey();
@@ -347,6 +349,8 @@ void QWebSocketPrivate::close(QWebSocketProtocol::CloseCode closeCode, QString r
}
QByteArray frame = getFrameHeader(QWebSocketProtocol::OpCodeClose,
payload.size(), maskingKey, true);
+
+ Q_ASSERT(payload.length() <= 125);
frame.append(payload);
m_pSocket->write(frame);
m_pSocket->flush();
diff --git a/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp b/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp
index ac54270..211ea25 100644
--- a/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp
+++ b/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp
@@ -143,6 +143,7 @@ private Q_SLOTS:
#ifndef QT_NO_NETWORKPROXY
void tst_setProxy();
#endif
+ void overlongCloseReason();
};
tst_QWebSocket::tst_QWebSocket()
@@ -724,6 +725,34 @@ void tst_QWebSocket::tst_setProxy()
socket.setProxy(proxy);
QCOMPARE(socket.proxy(), proxy);
}
+
+void tst_QWebSocket::overlongCloseReason()
+{
+ EchoServer echoServer;
+
+ QWebSocket socket;
+
+ //should return 0 because socket is not open yet
+ QCOMPARE(socket.sendTextMessage(QStringLiteral("1234")), 0);
+
+ QSignalSpy socketConnectedSpy(&socket, SIGNAL(connected()));
+ QSignalSpy socketDisconnectedSpy(&socket, SIGNAL(disconnected()));
+ QSignalSpy serverConnectedSpy(&echoServer, SIGNAL(newConnection(QUrl)));
+
+ 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);
+
+ const QString reason(200, QChar::fromLatin1('a'));
+ socket.close(QWebSocketProtocol::CloseCodeGoingAway, reason);
+ QCOMPARE(socket.closeCode(), QWebSocketProtocol::CloseCodeGoingAway);
+ // Max length of a control frame is 125, but 2 bytes are used for the close code:
+ QCOMPARE(socket.closeReason().length(), 123);
+ QCOMPARE(socket.closeReason(), reason.leftRef(123));
+ QTRY_COMPARE(socketDisconnectedSpy.count(), 1);
+}
#endif // QT_NO_NETWORKPROXY
QTEST_MAIN(tst_QWebSocket)