[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