[Libreoffice-commits] online.git: 2 commits - wsd/ClientSession.cpp wsd/ClientSession.hpp wsd/PrisonerSession.cpp
Ashod Nakashian
ashod.nakashian at collabora.co.uk
Mon Jan 23 05:54:37 UTC 2017
wsd/ClientSession.cpp | 244 +++++++++++++++++++++++++++++++++++++++++++++++-
wsd/ClientSession.hpp | 22 +++-
wsd/PrisonerSession.cpp | 7 -
3 files changed, 257 insertions(+), 16 deletions(-)
New commits:
commit e584a514434e733fac1edc16a5d64842d5a61683
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date: Sat Jan 21 21:38:11 2017 -0500
wsd: merge PrisonerSession into ClientSession
Change-Id: I8ae924a7afae61b9c6e25e15ace187918d1e006b
Reviewed-on: https://gerrit.libreoffice.org/33433
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp
index 63ca129..d36705c 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -25,6 +25,7 @@
using namespace LOOLProtocol;
+using Poco::Path;
using Poco::StringTokenizer;
ClientSession::ClientSession(const std::string& id,
@@ -43,7 +44,6 @@ ClientSession::ClientSession(const std::string& id,
{
LOG_INF("ClientSession ctor [" << getName() << "].");
- _peer = std::make_shared<PrisonerSession>(*this, docBroker);
_senderThread = std::thread([this]{ senderThread(); });
}
@@ -60,7 +60,7 @@ ClientSession::~ClientSession()
bool ClientSession::isLoaded() const
{
- return _isLoadRequested && _peer && _peer->gotStatus();
+ return _isLoadRequested && gotStatus();
}
bool ClientSession::_handleInput(const char *buffer, int length)
@@ -481,9 +481,245 @@ void ClientSession::senderThread()
LOG_DBG(getName() << " SenderThread finished");
}
-bool ClientSession::handleKitToClientMessage(const char* data, const int size)
+bool ClientSession::handleKitToClientMessage(const char* buffer, const int length)
{
- return _peer->handleInput(data, size);
+ LOG_TRC(getName() + ": handling [" << getAbbreviatedMessage(buffer, length) << "].");
+ const std::string firstLine = getFirstLine(buffer, length);
+ StringTokenizer tokens(firstLine, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
+
+ const auto docBroker = _docBroker.lock();
+ if (!docBroker)
+ {
+ LOG_ERR("No DocBroker to handle kit-to-client message: " << firstLine);
+ return false;
+ }
+
+ LOOLWSD::dumpOutgoingTrace(docBroker->getJailId(), getId(), firstLine);
+
+ if (tokens[0] == "unocommandresult:")
+ {
+ const std::string stringMsg(buffer, length);
+ LOG_INF(getName() << ": Command: " << stringMsg);
+ const auto index = stringMsg.find_first_of('{');
+ if (index != std::string::npos)
+ {
+ const std::string stringJSON = stringMsg.substr(index);
+ Poco::JSON::Parser parser;
+ const auto parsedJSON = parser.parse(stringJSON);
+ const auto& object = parsedJSON.extract<Poco::JSON::Object::Ptr>();
+ if (object->get("commandName").toString() == ".uno:Save")
+ {
+ bool success = object->get("success").toString() == "true";
+ std::string result;
+ if (object->has("result"))
+ {
+ const auto parsedResultJSON = object->get("result");
+ const auto& resultObj = parsedResultJSON.extract<Poco::JSON::Object::Ptr>();
+ if (resultObj->get("type").toString() == "string")
+ result = resultObj->get("value").toString();
+ }
+
+ // Save to Storage and log result.
+ docBroker->save(getId(), success, result);
+ return true;
+ }
+ }
+ else
+ {
+ LOG_WRN("Expected json unocommandresult. Ignoring: " << stringMsg);
+ }
+ }
+ else if (tokens[0] == "error:")
+ {
+ std::string errorCommand;
+ std::string errorKind;
+ if (getTokenString(tokens[1], "cmd", errorCommand) &&
+ getTokenString(tokens[2], "kind", errorKind) )
+ {
+ if (errorCommand == "load")
+ {
+ if (errorKind == "passwordrequired:to-view" ||
+ errorKind == "passwordrequired:to-modify" ||
+ errorKind == "wrongpassword")
+ {
+ const auto payload = std::make_shared<Message>(buffer, length,
+ Message::Dir::Out,
+ Message::Type::Text);
+ forwardToClient(payload);
+ LOG_WRN("Document load failed: " << errorKind);
+ return false;
+ }
+ }
+ }
+ }
+ else if (tokens[0] == "curpart:" && tokens.count() == 2)
+ {
+ //TODO: Should forward to client?
+ int curPart;
+ return getTokenInteger(tokens[1], "part", curPart);
+ }
+ else if (tokens.count() == 2 && tokens[0] == "saveas:")
+ {
+ std::string url;
+ if (!getTokenString(tokens[1], "url", url))
+ {
+ LOG_ERR("Bad syntax for: " << firstLine);
+ return false;
+ }
+
+ // Save-as completed, inform the ClientSession.
+ const std::string filePrefix("file:///");
+ if (url.find(filePrefix) == 0)
+ {
+ // Rewrite file:// URLs, as they are visible to the outside world.
+ const Path path(docBroker->getJailRoot(), url.substr(filePrefix.length()));
+ if (Poco::File(path).exists())
+ {
+ url = filePrefix + path.toString().substr(1);
+ }
+ else
+ {
+ // Blank for failure.
+ LOG_DBG("SaveAs produced no output, producing blank url.");
+ url.clear();
+ }
+ }
+
+ setSaveAsUrl(url);
+ return true;
+ }
+ else if (tokens.count() == 2 && tokens[0] == "statechanged:")
+ {
+ if (docBroker)
+ {
+ StringTokenizer stateTokens(tokens[1], "=", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
+ if (stateTokens.count() == 2 && stateTokens[0] == ".uno:ModifiedStatus")
+ {
+ docBroker->setModified(stateTokens[1] == "true");
+ }
+ }
+ }
+
+ if (!_isDocPasswordProtected)
+ {
+ if (tokens[0] == "tile:")
+ {
+ assert(false && "Tile traffic should go through the DocumentBroker-LoKit WS.");
+ }
+ else if (tokens[0] == "status:")
+ {
+ _gotStatus = true;
+ docBroker->setLoaded();
+
+ // Forward the status response to the client.
+ const auto payload = std::make_shared<Message>(buffer, length,
+ Message::Dir::Out,
+ Message::Type::Text);
+ return forwardToClient(payload);
+ }
+ else if (tokens[0] == "commandvalues:")
+ {
+ const std::string stringMsg(buffer, length);
+ const auto index = stringMsg.find_first_of('{');
+ if (index != std::string::npos)
+ {
+ const std::string stringJSON = stringMsg.substr(index);
+ Poco::JSON::Parser parser;
+ const auto result = parser.parse(stringJSON);
+ const auto& object = result.extract<Poco::JSON::Object::Ptr>();
+ const std::string commandName = object->has("commandName") ? object->get("commandName").toString() : "";
+ if (commandName == ".uno:CharFontName" ||
+ commandName == ".uno:StyleApply")
+ {
+ // other commands should not be cached
+ docBroker->tileCache().saveTextFile(stringMsg, "cmdValues" + commandName + ".txt");
+ }
+ }
+ }
+ else if (tokens[0] == "partpagerectangles:")
+ {
+ if (tokens.count() > 1 && !tokens[1].empty())
+ {
+ docBroker->tileCache().saveTextFile(std::string(buffer, length), "partpagerectangles.txt");
+ }
+ }
+ else if (tokens[0] == "invalidatetiles:")
+ {
+ assert(firstLine.size() == static_cast<std::string::size_type>(length));
+ docBroker->invalidateTiles(firstLine);
+ }
+ else if (tokens[0] == "invalidatecursor:")
+ {
+ assert(firstLine.size() == static_cast<std::string::size_type>(length));
+ StringTokenizer firstLineTokens(firstLine, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
+ int x = 0, y = 0, w = 0, h = 0;
+ if (firstLineTokens.count() > 2 &&
+ stringToInteger(firstLineTokens[1], x) &&
+ stringToInteger(firstLineTokens[2], y))
+ {
+ if (firstLineTokens.count() > 3)
+ {
+ stringToInteger(firstLineTokens[3], w);
+ stringToInteger(firstLineTokens[4], h);
+ }
+ docBroker->invalidateCursor(x, y, w, h);
+ }
+ else
+ {
+ LOG_ERR("Unable to parse " << firstLine);
+ }
+ }
+ else if (tokens[0] == "renderfont:")
+ {
+ std::string font, text;
+ if (tokens.count() < 3 ||
+ !getTokenString(tokens[1], "font", font))
+ {
+ LOG_ERR("Bad syntax for: " << firstLine);
+ return false;
+ }
+
+ getTokenString(tokens[2], "char", text);
+ assert(firstLine.size() < static_cast<std::string::size_type>(length));
+ docBroker->tileCache().saveRendering(font+text, "font", buffer + firstLine.size() + 1, length - firstLine.size() - 1);
+ const auto payload = std::make_shared<Message>(buffer, length,
+ Message::Dir::Out,
+ Message::Type::Binary);
+ return forwardToClient(payload);
+ }
+ }
+ else
+ {
+ LOG_INF("Ignoring notification on password protected document: " << firstLine);
+ }
+
+ // Detect json messages, since we must send those as text even though they are multiline.
+ // If not, the UI will read the first line of a binary payload, assuming that's the only
+ // text part and the rest is binary.
+ const bool isBinary = buffer[length - 1] != '}' && firstLine.find('{') == std::string::npos;
+
+ // Forward everything else.
+ const auto payload = std::make_shared<Message>(buffer, length,
+ Message::Dir::Out,
+ isBinary ? Message::Type::Binary
+ : Message::Type::Text);
+ return forwardToClient(payload);
+}
+
+bool ClientSession::forwardToClient(const std::shared_ptr<Message>& payload)
+{
+ const auto& message = payload->abbr();
+
+ if (isCloseFrame())
+ {
+ LOG_TRC(getName() << ": peer began the closing handshake. Dropping forward message [" << message << "].");
+ return true;
+ }
+
+ LOG_TRC(getName() << " enqueue to client: " << message);
+ enqueueSendMessage(payload);
+
+ return true;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/wsd/ClientSession.hpp b/wsd/ClientSession.hpp
index f2656e8..e53a414 100644
--- a/wsd/ClientSession.hpp
+++ b/wsd/ClientSession.hpp
@@ -35,6 +35,9 @@ public:
void setReadOnly();
bool isReadOnly() const { return _isReadOnly; }
+ /// Returns true if we've got status message.
+ bool gotStatus() const { return _gotStatus; }
+
bool isLoaded() const;
const std::string getUserId() const { return _userId; }
@@ -140,6 +143,8 @@ private:
bool forwardToChild(const std::string& message,
const std::shared_ptr<DocumentBroker>& docBroker);
+ bool forwardToClient(const std::shared_ptr<Message>& payload);
+
/// Returns true if given message from the client should be allowed or not
/// Eg. in readonly mode only few messages should be allowed
bool filterMessage(const std::string& msg) const;
@@ -158,15 +163,13 @@ private:
/// Whether this session is the owner of currently opened document
bool _isDocumentOwner;
- /// Our peer that connects us to the child.
- std::shared_ptr<PrisonerSession> _peer;
-
/// Store URLs of completed 'save as' documents.
MessageQueue _saveAsQueue;
int _loadPart;
bool _isLoadRequested;
+ bool _gotStatus;
/// Wopi FileInfo object
std::unique_ptr<WopiStorage::WOPIFileInfo> _wopiFileInfo;
commit c7e2a4cc8892d9593018b862eba0bdb0a083f021
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date: Sat Jan 21 20:59:45 2017 -0500
wsd: move headless check in enqueue function
Change-Id: I2a09d2c5e5c1705e5caeb8563babcd939384a583
Reviewed-on: https://gerrit.libreoffice.org/33432
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
diff --git a/wsd/ClientSession.hpp b/wsd/ClientSession.hpp
index b6211a7..f2656e8 100644
--- a/wsd/ClientSession.hpp
+++ b/wsd/ClientSession.hpp
@@ -68,8 +68,17 @@ public:
void enqueueSendMessage(const std::shared_ptr<Message>& data)
{
- LOG_TRC(getName() << " enqueueing client message: " << data->abbr());
- _senderQueue.enqueue(data);
+ if (isHeadless())
+ {
+ // Fail silently and return as there is no actual websocket
+ // connection in this case.
+ LOG_INF(getName() << ": Headless peer, not forwarding message [" << data->abbr() << "].");
+ }
+ else
+ {
+ LOG_TRC(getName() << " enqueueing client message: " << data->abbr());
+ _senderQueue.enqueue(data);
+ }
}
bool stopping() const { return _stop || _senderQueue.stopping(); }
diff --git a/wsd/PrisonerSession.cpp b/wsd/PrisonerSession.cpp
index 9a2b0cf..c4188d9 100644
--- a/wsd/PrisonerSession.cpp
+++ b/wsd/PrisonerSession.cpp
@@ -275,13 +275,6 @@ bool PrisonerSession::forwardToPeer(const std::shared_ptr<Message>& payload)
LOG_TRC(getName() << ": peer began the closing handshake. Dropping forward message [" << message << "].");
return true;
}
- else if (_peer.isHeadless())
- {
- // Fail silently and return as there is no actual websocket
- // connection in this case.
- LOG_INF(getName() << ": Headless peer, not forwarding message [" << message << "].");
- return true;
- }
LOG_TRC(getName() << " -> " << _peer.getName() << ": " << message);
_peer.enqueueSendMessage(payload);
More information about the Libreoffice-commits
mailing list