From 350f40d07943a32319182bac6a21adf456642075 Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Sat, 29 Jan 2022 16:12:22 +0100 Subject: SyncData: expect self-contained /sync response SyncData can load room objects out-of-line. This is only expected when loading data from the cache (and since quite long ago, the cache always saves room objects out of line, avoiding too large JSON payloads that Qt parser chokes on). However, the code processed /sync response in the same way; in particular, this meant that SyncData filled the vector of unresolved room ids even when it came from /sync. SyncJob then looked at this vector and entered an error state if it was not empty. Well, payloads from the wire can be weird and it ultimately came to pass that a homeserver returned a non-object against a given room key, triggering the unresolved rooms branch in SyncJob - and stalling the whole sync loop as a result (https://invent.kde.org/network/neochat/-/issues/500). With this commit SyncData only fills unresolvedRoomIds when loading rooms from the cache (with the implied fallback of discarding the cache and loading from /sync anew instead). Respectively, SyncJob must never end up with SyncData that has unresolved rooms (even if those occur in the actual payload like in the mentioned issue, those rooms will be completely empty instead); the added assertion only guards for internal consistency. --- lib/syncdata.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'lib/syncdata.cpp') diff --git a/lib/syncdata.cpp b/lib/syncdata.cpp index 396e77eb..b0cd8e4d 100644 --- a/lib/syncdata.cpp +++ b/lib/syncdata.cpp @@ -185,14 +185,18 @@ void SyncData::parseJson(const QJsonObject& json, const QString& baseDir) // We have a Qt container on the right and an STL one on the left roomData.reserve(roomData.size() + static_cast(rs.size())); for (auto roomIt = rs.begin(); roomIt != rs.end(); ++roomIt) { - auto roomJson = - roomIt->isObject() - ? roomIt->toObject() - : loadJson(baseDir + fileNameForRoom(roomIt.key())); - if (roomJson.isEmpty()) { - unresolvedRoomIds.push_back(roomIt.key()); - continue; - } + QJsonObject roomJson; + if (!baseDir.isEmpty()) { + // Loading data from the local cache, with room objects saved in + // individual files rather than inline + roomJson = loadJson(baseDir + fileNameForRoom(roomIt.key())); + if (roomJson.isEmpty()) { + unresolvedRoomIds.push_back(roomIt.key()); + continue; + } + } else // When loading from /sync response, everything is inline + roomJson = roomIt->toObject(); + roomData.emplace_back(roomIt.key(), joinState, roomJson); const auto& r = roomData.back(); totalEvents += r.state.size() + r.ephemeral.size() -- cgit v1.2.3