mirror of
https://github.com/qt/qtmqtt.git
synced 2026-10-25 16:16:26 +00:00
Protect topic from overflow
While QString can store longer content, a topic only can hold 2 byte long names. For publishing, truncate the message topic to allow sending. In case a subscription uses wildcards, it is still able to receive it. For subscriptions forbid long topic names and return null. Change-Id: I914c03210b22a2d521d4d10f4a4f643201183137 Reviewed-by: Maurice Kalinowski <maurice.kalinowski@qt.io>
This commit is contained in:
parent
760b868f21
commit
8413dc4ade
@ -247,7 +247,13 @@ qint32 QMqttConnection::sendControlPublish(const QString &topic, const QByteArra
|
||||
|
||||
QSharedPointer<QMqttControlPacket> packet(new QMqttControlPacket(header));
|
||||
|
||||
packet->append(topic.toUtf8());
|
||||
QByteArray topicArray = topic.toUtf8();
|
||||
if (topicArray.size() > UINT16_MAX) {
|
||||
qWarning("Published topic is too long. Need to truncate");
|
||||
topicArray.truncate(UINT16_MAX);
|
||||
}
|
||||
|
||||
packet->append(topicArray);
|
||||
quint16 identifier = 0;
|
||||
if (qos > 0) {
|
||||
// Add Packet Identifier
|
||||
@ -320,7 +326,14 @@ QSharedPointer<QMqttSubscription> QMqttConnection::sendControlSubscribe(const QS
|
||||
const quint16 identifier = qrand();
|
||||
packet.append(identifier);
|
||||
|
||||
packet.append(topic.toUtf8());
|
||||
// Overflow protection
|
||||
QByteArray topicArray = topic.toUtf8();
|
||||
if (topicArray.size() > UINT16_MAX) {
|
||||
qWarning("Subscribed topic is too long.");
|
||||
return QSharedPointer<QMqttSubscription>();
|
||||
}
|
||||
|
||||
packet.append(topicArray);
|
||||
|
||||
switch (qos) {
|
||||
case 0: packet.append(char(0x0)); break;
|
||||
@ -330,7 +343,7 @@ QSharedPointer<QMqttSubscription> QMqttConnection::sendControlSubscribe(const QS
|
||||
}
|
||||
|
||||
QSharedPointer<QMqttSubscription> result(new QMqttSubscription);
|
||||
result->setTopic(topic);
|
||||
result->setTopic(topicArray);
|
||||
result->setClient(m_client);
|
||||
result->setQos(qos);
|
||||
result->setState(QMqttSubscription::SubscriptionPending);
|
||||
|
||||
@ -46,6 +46,9 @@ private Q_SLOTS:
|
||||
void sendReceive();
|
||||
void retainMessage();
|
||||
void willMessage();
|
||||
void longTopic_data();
|
||||
void longTopic();
|
||||
void subscribeLongTopic();
|
||||
private:
|
||||
QString m_testBroker;
|
||||
quint16 m_port{1883};
|
||||
@ -263,6 +266,74 @@ void Tst_QMqttClient::willMessage()
|
||||
}
|
||||
}
|
||||
|
||||
void Tst_QMqttClient::longTopic_data()
|
||||
{
|
||||
QTest::addColumn<QString>("topic");
|
||||
QTest::newRow("simple") << QString::fromLatin1("topic");
|
||||
QTest::newRow("subPath") << QString::fromLatin1("topic/subtopic");
|
||||
// ### TODO: This test does not work as socket::read() is not able to handle such large buffers.
|
||||
// For this we need to redo th whole reading part.
|
||||
// QString l;
|
||||
// l.fill(QLatin1Char('T'), UINT16_MAX);
|
||||
// QTest::newRow("maxSize") << l;
|
||||
// l.fill(QLatin1Char('M'), 2 * UINT16_MAX);
|
||||
// QTest::newRow("overflow") << l;
|
||||
}
|
||||
|
||||
void Tst_QMqttClient::longTopic()
|
||||
{
|
||||
QFETCH(QString, topic);
|
||||
QString truncTopic = topic;
|
||||
truncTopic.truncate(UINT16_MAX);
|
||||
|
||||
QMqttClient publisher;
|
||||
publisher.setClientId(QLatin1String("publisher"));
|
||||
publisher.setHostname(m_testBroker);
|
||||
publisher.setPort(m_port);
|
||||
|
||||
publisher.connectToHost();
|
||||
QTRY_COMPARE(publisher.state(), QMqttClient::Connected);
|
||||
|
||||
QMqttClient subscriber;
|
||||
subscriber.setClientId(QLatin1String("subscriber"));
|
||||
subscriber.setHostname(m_testBroker);
|
||||
subscriber.setPort(m_port);
|
||||
|
||||
subscriber.connectToHost();
|
||||
QTRY_COMPARE(subscriber.state(), QMqttClient::Connected);
|
||||
|
||||
bool received = false;
|
||||
bool verified = false;
|
||||
connect(&subscriber, &QMqttClient::messageReceived, [&](const QByteArray &, const QString &t) {
|
||||
received = true;
|
||||
verified = t == truncTopic;
|
||||
});
|
||||
|
||||
auto client1Sub = subscriber.subscribe(truncTopic, 1);
|
||||
QTRY_COMPARE(client1Sub->state(), QMqttSubscription::Subscribed);
|
||||
|
||||
publisher.publish(topic, QByteArray("Msgs"), 1);
|
||||
|
||||
QTRY_VERIFY2(received, "Subscriber did not receive message");
|
||||
QVERIFY2(verified, "Subscriber received different message");
|
||||
}
|
||||
|
||||
void Tst_QMqttClient::subscribeLongTopic()
|
||||
{
|
||||
QMqttClient subscriber;
|
||||
subscriber.setClientId(QLatin1String("subscriber"));
|
||||
subscriber.setHostname(m_testBroker);
|
||||
subscriber.setPort(m_port);
|
||||
|
||||
subscriber.connectToHost();
|
||||
QTRY_COMPARE(subscriber.state(), QMqttClient::Connected);
|
||||
|
||||
QString topic;
|
||||
topic.fill(QLatin1Char('s'), 2 * UINT16_MAX);
|
||||
auto sub = subscriber.subscribe(topic);
|
||||
QVERIFY(sub.isNull());
|
||||
}
|
||||
|
||||
QTEST_MAIN(Tst_QMqttClient)
|
||||
|
||||
#include "tst_qmqttclient.moc"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user