summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIevgenii Meshcheriakov <ievgenii.meshcheriakov@qt.io>2023-06-19 16:09:30 +0200
committerIevgenii Meshcheriakov <ievgenii.meshcheriakov@qt.io>2023-06-20 19:53:47 +0200
commit2509fc508a76600d9e090df1583711197e337339 (patch)
treec50989322997e5f85a1167514dec6ccd6d4dc0f4
parent666ce51d4eb6b5dd312f98e2d7a18c54b59945e4 (diff)
QDBus: Transform fallback interface names according to the spec
ACE-encode the domain names, replace dashes with underscores, prepend underscore to domain name parts that start with a digit. Add a regression test into tst_qdbusinterface. Fixes: QTBUG-71674 Change-Id: I92e0c6889163c0eccc4c833f2058d759631f562c Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
-rw-r--r--src/dbus/qdbusmisc.cpp50
-rw-r--r--tests/auto/dbus/qdbusinterface/tst_qdbusinterface.cpp60
2 files changed, 95 insertions, 15 deletions
diff --git a/src/dbus/qdbusmisc.cpp b/src/dbus/qdbusmisc.cpp
index 502624cd66..5a9d8f548f 100644
--- a/src/dbus/qdbusmisc.cpp
+++ b/src/dbus/qdbusmisc.cpp
@@ -8,6 +8,7 @@
#include <QtCore/qlist.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qvariant.h>
+#include <private/qurl_p.h>
#include "qdbusutil_p.h"
#include "qdbusconnection_p.h"
@@ -58,23 +59,42 @@ QString qDBusInterfaceFromMetaObject(const QMetaObject *mo)
} else if (!QCoreApplication::instance()||
QCoreApplication::instance()->applicationName().isEmpty()) {
interface.prepend("local."_L1);
- } else {
- interface.prepend(u'.').prepend(QCoreApplication::instance()->applicationName());
+ } else {
+ QString domainName = QCoreApplication::instance()->applicationName();
const QString organizationDomain = QCoreApplication::instance()->organizationDomain();
- const auto domainName = QStringView{organizationDomain}.split(u'.', Qt::SkipEmptyParts);
- if (domainName.isEmpty()) {
- interface.prepend("local."_L1);
- } else {
- QString composedDomain;
- // + 1 for additional dot, e.g. organizationDomain equals "example.com",
- // then composedDomain will be equal "com.example."
- composedDomain.reserve(organizationDomain.size() + 1);
- for (auto it = domainName.rbegin(), end = domainName.rend(); it != end; ++it)
- composedDomain += *it + u'.';
-
- interface.prepend(composedDomain);
+ if (organizationDomain.isEmpty())
+ domainName.append(".local"_L1);
+ else
+ domainName.append(u'.').append(organizationDomain);
+
+ // Domain names used to produce interface names should be IDN-encoded.
+ QString encodedDomainName = qt_ACE_do(domainName, ToAceOnly, ForbidLeadingDot);
+ if (encodedDomainName.isEmpty()) {
+ interface.prepend("local."_L1);
+ return interface;
}
- }
+
+ // Hyphens are not allowed in interface names and should be replaced
+ // by underscores.
+ encodedDomainName.replace(u'-', u'_');
+
+ auto nameParts = QStringView{ encodedDomainName }.split(u'.', Qt::SkipEmptyParts);
+
+ QString composedDomain;
+ // + 1 for additional dot, e.g. domainName equals "App.example.com",
+ // then composedDomain will be equal "com.example.App."
+ composedDomain.reserve(encodedDomainName.size() + nameParts.size() + 1);
+ for (auto it = nameParts.rbegin(), end = nameParts.rend(); it != end; ++it) {
+ // An interface name cannot start with a digit, and cannot
+ // contain digits immediately following a period. Prefix such
+ // digits with underscores.
+ if (it->first().isDigit())
+ composedDomain += u'_';
+ composedDomain += *it + u'.';
+ }
+
+ interface.prepend(composedDomain);
+ }
}
return interface;
diff --git a/tests/auto/dbus/qdbusinterface/tst_qdbusinterface.cpp b/tests/auto/dbus/qdbusinterface/tst_qdbusinterface.cpp
index d4b61d27dd..b5e2aa9599 100644
--- a/tests/auto/dbus/qdbusinterface/tst_qdbusinterface.cpp
+++ b/tests/auto/dbus/qdbusinterface/tst_qdbusinterface.cpp
@@ -20,6 +20,8 @@
#include "../qdbusmarshall/common.h"
#include "myobject.h"
+using namespace Qt::StringLiterals;
+
#define TEST_INTERFACE_NAME "org.qtproject.QtDBus.MyObject"
#define TEST_SIGNAL_NAME "somethingHappened"
@@ -198,6 +200,10 @@ private slots:
void complexPropertyWritePeer();
void interactiveAuthorizationRequired();
+
+ void interfaceNameFallback_data();
+ void interfaceNameFallback();
+
private:
QProcess proc;
};
@@ -1147,6 +1153,60 @@ void tst_QDBusInterface::interactiveAuthorizationRequired()
QVERIFY(reply.arguments().at(0).toBool());
}
+class TestObject : public QObject
+{
+ Q_OBJECT
+public Q_SLOTS:
+ void test() { }
+};
+
+void tst_QDBusInterface::interfaceNameFallback_data()
+{
+ QTest::addColumn<QString>("appName");
+ QTest::addColumn<QString>("orgDomain");
+ QTest::addColumn<QString>("interfaceName");
+
+ QTest::addRow("empty.empty") << "" << "" << "local.tst_qdbusinterface";
+ QTest::addRow("with-domain") << "" << "qt-project.org" << "org.qt_project.tst_qdbusinterface";
+ QTest::addRow("numbers") << "prog42" << "7-zip.org" << "org._7_zip.prog42";
+ QTest::addRow("non-latin1") << u"\u00e6"_s << u"\u00e5"_s << "xn__5ca.xn__6ca";
+}
+
+void tst_QDBusInterface::interfaceNameFallback()
+{
+ QFETCH(QString, appName);
+ QFETCH(QString, orgDomain);
+ QFETCH(QString, interfaceName);
+
+ auto app = QCoreApplication::instance();
+ auto oldApplicationName = app->applicationName();
+ auto oldOrganizationDomain = app->organizationDomain();
+
+ app->setApplicationName(appName);
+ app->setOrganizationDomain(orgDomain);
+ auto obj = new TestObject;
+
+ auto cleanup = qScopeGuard([&] {
+ obj->deleteLater();
+ app->setApplicationName(oldApplicationName);
+ app->setOrganizationDomain(oldOrganizationDomain);
+ });
+
+ auto con = QDBusConnection::sessionBus();
+ const QString path = "/interfaceNameFallback"_L1;
+
+ QVERIFY(con.registerObject(path, obj, QDBusConnection::ExportAllContents));
+
+ QDBusInterface interface(con.baseService(), path, "org.freedesktop.DBus.Introspectable"_L1,
+ con);
+ auto reply = interface.call("Introspect");
+
+ QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
+ QString tag = u"<interface name=\"%1.TestObject\">"_s.arg(interfaceName);
+ auto result = reply.arguments().at(0).toString();
+ QVERIFY2(result.contains(tag), qUtf8Printable(u"Tag '%1' not found\n%2"_s.arg(tag, result)));
+}
+
QTEST_MAIN(tst_QDBusInterface)
#include "tst_qdbusinterface.moc"