tdf#128502: Get rid of the static file-level variable 'document' in Kit.cpp
It is not a problem in the multi-process web-based Online, where the
variable exists separately in each KIT process (which handles exactly
one document). But in a mobile app, when we want to be able to handle
multiple document in the single process, we can't have such variables.
Change-Id: I1d3da48316eb3a8c72ff4957cc3fcba8f6870f16
Reviewed-on: https://gerrit.libreoffice.org/c/online/+/92582
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Tor Lillqvist <tml@collabora.com>
diff --git a/kit/ChildSession.cpp b/kit/ChildSession.cpp
index cfc7c8b..aa9f254 100644
--- a/kit/ChildSession.cpp
+++ b/kit/ChildSession.cpp
@@ -1464,7 +1464,7 @@
{
if (tokens[1] == ".uno:fakeDiskFull")
{
Util::alertAllUsers("internal", "diskfull");
_docManager->alertAllUsers("internal", "diskfull");
}
else
{
diff --git a/kit/ChildSession.hpp b/kit/ChildSession.hpp
index 5cb75d7..10f3dba 100644
--- a/kit/ChildSession.hpp
+++ b/kit/ChildSession.hpp
@@ -69,6 +69,8 @@
virtual std::shared_ptr<TileQueue>& getTileQueue() = 0;
virtual bool sendFrame(const char* buffer, int length, WSOpCode opCode = WSOpCode::Text) = 0;
virtual void alertAllUsers(const std::string& cmd, const std::string& kind) = 0;
};
struct RecordedEvent
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index dff8f08..142392f6 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -105,7 +105,6 @@
// We only host a single document in our lifetime.
class Document;
static std::shared_ptr<Document> document;
#ifndef BUILDING_TESTS
static bool AnonymizeUserData = false;
static uint64_t AnonymizationSalt = 82589933;
@@ -1197,6 +1196,11 @@
return false;
}
void alertAllUsers(const std::string& cmd, const std::string& kind)
{
alertAllUsers("errortoall: cmd=" + cmd + " kind=" + kind);
}
static void GlobalCallback(const int type, const char* p, void* data)
{
if (SigUtil::getTerminationFlag())
@@ -2035,6 +2039,11 @@
return _obfuscatedFileId;
}
void alertAllUsers(const std::string& msg)
{
sendTextFrame(msg);
}
private:
std::shared_ptr<lok::Office> _loKit;
const std::string _jailId;
@@ -2091,140 +2100,11 @@
return Document::_loKitDocument;
}
class KitWebSocketHandler final : public WebSocketHandler
{
std::shared_ptr<TileQueue> _queue;
std::string _socketName;
std::shared_ptr<lok::Office> _loKit;
std::string _jailId;
public:
KitWebSocketHandler(const std::string& socketName, const std::shared_ptr<lok::Office>& loKit, const std::string& jailId) :
WebSocketHandler(/* isClient = */ true, /* isMasking */ false),
_queue(std::make_shared<TileQueue>()),
_socketName(socketName),
_loKit(loKit),
_jailId(jailId)
{
}
protected:
void handleMessage(const std::vector<char>& data) override
{
std::string message(data.data(), data.size());
#if !MOBILEAPP
if (UnitKit::get().filterKitMessage(this, message))
return;
#endif
StringVector tokens = LOOLProtocol::tokenize(message);
Log::StreamLogger logger = Log::debug();
if (logger.enabled())
{
logger << _socketName << ": recv [";
for (const auto& token : tokens)
{
// Don't log user-data, there are anonymized versions that get logged instead.
if (Util::startsWith(tokens.getParam(token), "jail") ||
Util::startsWith(tokens.getParam(token), "author") ||
Util::startsWith(tokens.getParam(token), "name") ||
Util::startsWith(tokens.getParam(token), "url"))
continue;
logger << tokens.getParam(token) << ' ';
}
LOG_END(logger, true);
}
// Note: Syntax or parsing errors here are unexpected and fatal.
if (SigUtil::getTerminationFlag())
{
LOG_DBG("Too late, TerminationFlag is set, we're going down");
}
else if (tokens.equals(0, "session"))
{
const std::string& sessionId = tokens[1];
const std::string& docKey = tokens[2];
const std::string& docId = tokens[3];
const std::string fileId = Util::getFilenameFromURL(docKey);
Util::mapAnonymized(fileId, fileId); // Identity mapping, since fileId is already obfuscated
std::string url;
URI::decode(docKey, url);
LOG_INF("New session [" << sessionId << "] request on url [" << url << "].");
Util::setThreadName("kit_" + docId);
if (!document)
document = std::make_shared<Document>(
_loKit, _jailId, docKey, docId, url, _queue,
std::static_pointer_cast<WebSocketHandler>(shared_from_this()));
// Validate and create session.
if (!(url == document->getUrl() && document->createSession(sessionId)))
{
LOG_DBG("CreateSession failed.");
}
}
else if (tokens.equals(0, "exit"))
{
#if !MOBILEAPP
LOG_INF("Terminating immediately due to parent 'exit' command.");
Log::shutdown();
std::_Exit(EX_SOFTWARE);
#else
LOG_INF("Setting TerminationFlag due to 'exit' command.");
SigUtil::setTerminationFlag();
document.reset();
#endif
}
else if (tokens.equals(0, "tile") || tokens.equals(0, "tilecombine") || tokens.equals(0, "canceltiles") ||
tokens.equals(0, "paintwindow") || tokens.equals(0, "resizewindow") ||
LOOLProtocol::getFirstToken(tokens[0], '-') == "child")
{
if (document)
{
_queue->put(message);
}
else
{
LOG_WRN("No document while processing " << tokens[0] << " request.");
}
}
else if (tokens.size() == 3 && tokens.equals(0, "setconfig"))
{
#if !MOBILEAPP
// Currently only rlimit entries are supported.
if (!Rlimit::handleSetrlimitCommand(tokens))
{
LOG_ERR("Unknown setconfig command: " << message);
}
#endif
}
else
{
LOG_ERR("Bad or unknown token [" << tokens[0] << "]");
}
}
void onDisconnect() override
{
#if !MOBILEAPP
LOG_WRN("Kit connection lost without exit arriving from wsd. Setting TerminationFlag");
SigUtil::setTerminationFlag();
#endif
}
};
void documentViewCallback(const int type, const char* payload, void* data)
{
Document::ViewCallback(type, payload, data);
}
class KitSocketPoll : public SocketPoll
{
std::chrono::steady_clock::time_point _pollEnd;
std::shared_ptr<Document> _document;
public:
KitSocketPoll() :
SocketPoll("kit")
@@ -2234,8 +2114,8 @@
// process pending message-queue events.
void drainQueue(const std::chrono::steady_clock::time_point &now)
{
if (document)
document->drainQueue(now);
if (_document)
_document->drainQueue(now);
}
// called from inside poll, inside a wakeup
@@ -2286,7 +2166,7 @@
drainQueue(std::chrono::steady_clock::now());
#if !MOBILEAPP
if (document && document->purgeSessions() == 0)
if (_document && _document->purgeSessions() == 0)
{
LOG_INF("Last session discarded. Setting TerminationFlag");
SigUtil::setTerminationFlag();
@@ -2296,8 +2176,150 @@
// Report the number of events we processed.
return eventsSignalled;
}
void setDocument(std::shared_ptr<Document> document)
{
_document = document;
}
};
class KitWebSocketHandler final : public WebSocketHandler
{
std::shared_ptr<TileQueue> _queue;
std::string _socketName;
std::shared_ptr<lok::Office> _loKit;
std::string _jailId;
std::shared_ptr<Document> _document;
KitSocketPoll &_ksPoll;
public:
KitWebSocketHandler(const std::string& socketName, const std::shared_ptr<lok::Office>& loKit, const std::string& jailId, KitSocketPoll& ksPoll) :
WebSocketHandler(/* isClient = */ true, /* isMasking */ false),
_queue(std::make_shared<TileQueue>()),
_socketName(socketName),
_loKit(loKit),
_jailId(jailId),
_ksPoll(ksPoll)
{
}
protected:
void handleMessage(const std::vector<char>& data) override
{
std::string message(data.data(), data.size());
#if !MOBILEAPP
if (UnitKit::get().filterKitMessage(this, message))
return;
#endif
StringVector tokens = LOOLProtocol::tokenize(message);
Log::StreamLogger logger = Log::debug();
if (logger.enabled())
{
logger << _socketName << ": recv [";
for (const auto& token : tokens)
{
// Don't log user-data, there are anonymized versions that get logged instead.
if (Util::startsWith(tokens.getParam(token), "jail") ||
Util::startsWith(tokens.getParam(token), "author") ||
Util::startsWith(tokens.getParam(token), "name") ||
Util::startsWith(tokens.getParam(token), "url"))
continue;
logger << tokens.getParam(token) << ' ';
}
LOG_END(logger, true);
}
// Note: Syntax or parsing errors here are unexpected and fatal.
if (SigUtil::getTerminationFlag())
{
LOG_DBG("Too late, TerminationFlag is set, we're going down");
}
else if (tokens.equals(0, "session"))
{
const std::string& sessionId = tokens[1];
const std::string& docKey = tokens[2];
const std::string& docId = tokens[3];
const std::string fileId = Util::getFilenameFromURL(docKey);
Util::mapAnonymized(fileId, fileId); // Identity mapping, since fileId is already obfuscated
std::string url;
URI::decode(docKey, url);
LOG_INF("New session [" << sessionId << "] request on url [" << url << "].");
Util::setThreadName("kit_" + docId);
if (!_document)
{
_document = std::make_shared<Document>(
_loKit, _jailId, docKey, docId, url, _queue,
std::static_pointer_cast<WebSocketHandler>(shared_from_this()));
_ksPoll.setDocument(_document);
}
// Validate and create session.
if (!(url == _document->getUrl() && _document->createSession(sessionId)))
{
LOG_DBG("CreateSession failed.");
}
}
else if (tokens.equals(0, "exit"))
{
#if !MOBILEAPP
LOG_INF("Terminating immediately due to parent 'exit' command.");
Log::shutdown();
std::_Exit(EX_SOFTWARE);
#else
LOG_INF("Setting TerminationFlag due to 'exit' command.");
SigUtil::setTerminationFlag();
_document.reset();
#endif
}
else if (tokens.equals(0, "tile") || tokens.equals(0, "tilecombine") || tokens.equals(0, "canceltiles") ||
tokens.equals(0, "paintwindow") || tokens.equals(0, "resizewindow") ||
LOOLProtocol::getFirstToken(tokens[0], '-') == "child")
{
if (_document)
{
_queue->put(message);
}
else
{
LOG_WRN("No document while processing " << tokens[0] << " request.");
}
}
else if (tokens.size() == 3 && tokens.equals(0, "setconfig"))
{
#if !MOBILEAPP
// Currently only rlimit entries are supported.
if (!Rlimit::handleSetrlimitCommand(tokens))
{
LOG_ERR("Unknown setconfig command: " << message);
}
#endif
}
else
{
LOG_ERR("Bad or unknown token [" << tokens[0] << "]");
}
}
void onDisconnect() override
{
#if !MOBILEAPP
LOG_WRN("Kit connection lost without exit arriving from wsd. Setting TerminationFlag");
SigUtil::setTerminationFlag();
#endif
}
};
void documentViewCallback(const int type, const char* payload, void* data)
{
Document::ViewCallback(type, payload, data);
}
/// Called by LOK main-loop the central location for data processing.
int pollCallback(void* pData, int timeoutUs)
{
@@ -2660,8 +2682,9 @@
KitSocketPoll mainKit;
mainKit.runOnClientThread(); // We will do the polling on this thread.
std::shared_ptr<ProtocolHandlerInterface> websocketHandler =
std::make_shared<KitWebSocketHandler>("child_ws", loKit, jailId);
std::shared_ptr<KitWebSocketHandler> websocketHandler =
std::make_shared<KitWebSocketHandler>("child_ws", loKit, jailId, mainKit);
#if !MOBILEAPP
mainKit.insertNewUnixSocket(MasterLocation, pathAndQuery, websocketHandler);
#else
@@ -2827,23 +2850,6 @@
#endif
}
#if !defined(BUILDING_TESTS) && !defined(KIT_IN_PROCESS)
namespace Util
{
void alertAllUsers(const std::string& msg)
{
document->sendTextFrame(msg);
}
void alertAllUsers(const std::string& cmd, const std::string& kind)
{
alertAllUsers("errortoall: cmd=" + cmd + " kind=" + kind);
}
}
#endif
#endif // MOBILEAPP
#endif // !MOBILEAPP
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/test/WhiteBoxTests.cpp b/test/WhiteBoxTests.cpp
index 12112d1..66f3e89 100644
--- a/test/WhiteBoxTests.cpp
+++ b/test/WhiteBoxTests.cpp
@@ -561,6 +561,10 @@
{
return true;
}
void alertAllUsers(const std::string& /*cmd*/, const std::string& /*kind*/) override
{
}
};
void WhiteBoxTests::testEmptyCellCursor()