loolwsd/ClientSession.cpp | 145 +++++++++++++ loolwsd/ClientSession.hpp | 41 ++- loolwsd/LOOLWSD.cpp | 2 loolwsd/MasterProcessSession.cpp | 313 ----------------------------- loolwsd/MasterProcessSession.hpp | 12 - loolwsd/PrisonerSession.cpp | 411 ++++++++++++++------------------------- loolwsd/PrisonerSession.hpp | 23 -- 7 files changed, 326 insertions(+), 621 deletions(-)
New commits: commit 2cecb669981b91513431f5ebdd9743c056806487 Author: Ashod Nakashian <[email protected]> Date: Mon May 16 19:05:22 2016 -0400 loolwsd: MasterProcessSession splitting: moved message handler Change-Id: Ibc0c4f3f37213461a66fba7fb27a5996d0914776 Reviewed-on: https://gerrit.libreoffice.org/25040 Reviewed-by: Ashod Nakashian <[email protected]> Tested-by: Ashod Nakashian <[email protected]> diff --git a/loolwsd/ClientSession.cpp b/loolwsd/ClientSession.cpp index b266e9d..36e3185 100644 --- a/loolwsd/ClientSession.cpp +++ b/loolwsd/ClientSession.cpp @@ -20,6 +20,7 @@ #include "LOOLSession.hpp" #include "LOOLWSD.hpp" #include "ClientSession.hpp" +#include "PrisonerSession.hpp" #include "MasterProcessSession.hpp" #include "Rectangle.hpp" #include "Storage.hpp" @@ -27,6 +28,150 @@ #include "IoUtil.hpp" #include "Util.hpp" +using namespace LOOLProtocol; + +using Poco::Path; +using Poco::StringTokenizer; + +ClientSession::~ClientSession() +{ + Log::info("~PrisonerSession dtor [" + getName() + "]."); + + // Release the save-as queue. + _saveAsQueue.put(""); +} + +bool ClientSession::_handleInput(const char *buffer, int length) +{ + const std::string firstLine = getFirstLine(buffer, length); + StringTokenizer tokens(firstLine, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); + Log::trace(getName() + ": handling [" + firstLine + "]."); + + if (LOOLProtocol::tokenIndicatesUserInteraction(tokens[0])) + { + // Keep track of timestamps of incoming client messages that indicate user activity. + updateLastActivityTime(); + } + + if (tokens[0] == "loolclient") + { + const auto versionTuple = ParseVersion(tokens[1]); + if (std::get<0>(versionTuple) != ProtocolMajorVersionNumber || + std::get<1>(versionTuple) != ProtocolMinorVersionNumber) + { + sendTextFrame("error: cmd=loolclient kind=badversion"); + return false; + } + + sendTextFrame("loolserver " + GetProtocolVersion()); + return true; + } + + if (tokens[0] == "takeedit") + { + _docBroker->takeEditLock(getId()); + return true; + } + else if (tokens[0] == "load") + { + if (_docURL != "") + { + sendTextFrame("error: cmd=load kind=docalreadyloaded"); + return false; + } + return loadDocument(buffer, length, tokens); + } + else if (tokens[0] != "canceltiles" && + tokens[0] != "clientzoom" && + tokens[0] != "clientvisiblearea" && + tokens[0] != "commandvalues" && + tokens[0] != "downloadas" && + tokens[0] != "getchildid" && + tokens[0] != "gettextselection" && + tokens[0] != "paste" && + tokens[0] != "insertfile" && + tokens[0] != "key" && + tokens[0] != "mouse" && + tokens[0] != "partpagerectangles" && + tokens[0] != "renderfont" && + tokens[0] != "requestloksession" && + tokens[0] != "resetselection" && + tokens[0] != "saveas" && + tokens[0] != "selectgraphic" && + tokens[0] != "selecttext" && + tokens[0] != "setclientpart" && + tokens[0] != "setpage" && + tokens[0] != "status" && + tokens[0] != "tile" && + tokens[0] != "tilecombine" && + tokens[0] != "uno" && + tokens[0] != "useractive" && + tokens[0] != "userinactive") + { + sendTextFrame("error: cmd=" + tokens[0] + " kind=unknown"); + return false; + } + else if (_docURL == "") + { + sendTextFrame("error: cmd=" + tokens[0] + " kind=nodocloaded"); + return false; + } + else if (tokens[0] == "canceltiles") + { + if (!_peer.expired()) + forwardToPeer(buffer, length); + } + else if (tokens[0] == "commandvalues") + { + return getCommandValues(buffer, length, tokens); + } + else if (tokens[0] == "partpagerectangles") + { + return getPartPageRectangles(buffer, length); + } + else if (tokens[0] == "renderfont") + { + sendFontRendering(buffer, length, tokens); + } + else if (tokens[0] == "status") + { + return getStatus(buffer, length); + } + else if (tokens[0] == "tile") + { + sendTile(buffer, length, tokens); + } + else if (tokens[0] == "tilecombine") + { + sendCombinedTiles(buffer, length, tokens); + } + else + { + // All other commands are such that they always require a + // LibreOfficeKitDocument session, i.e. need to be handled in + // a child process. + + if (_peer.expired()) + { + Log::trace("Dispatching child to handle [" + tokens[0] + "]."); + dispatchChild(); + } + + // Allow 'downloadas' for all kinds of views irrespective of editlock + if (!isEditLocked() && tokens[0] != "downloadas" && + tokens[0] != "userinactive" && tokens[0] != "useractive") + { + std::string dummyFrame = "dummymsg"; + forwardToPeer(dummyFrame.c_str(), dummyFrame.size()); + } + else if (tokens[0] != "requestloksession") + { + forwardToPeer(buffer, length); + } + } + return true; +} + /* void ClientSession::setEditLock(const bool value) { diff --git a/loolwsd/ClientSession.hpp b/loolwsd/ClientSession.hpp index 8cc0b6a..980b26f 100644 --- a/loolwsd/ClientSession.hpp +++ b/loolwsd/ClientSession.hpp @@ -26,12 +26,32 @@ class ClientSession final : public MasterProcessSession//, public std::enable_sh public: using MasterProcessSession::MasterProcessSession; + virtual ~ClientSession(); + //void setEditLock(const bool value); //void markEditLock(const bool value) { _bEditLock = value; } //bool isEditLocked() const { return _bEditLock; } + void setPeer(const std::shared_ptr<PrisonerSession>& peer) { MasterProcessSession::_peer = _peer = peer; } - //void setPeer(const std::shared_ptr<PrisonerSession>& peer) { _peer = peer; } + /** + * Return the URL of the saved-as document when it's ready. If called + * before it's ready, the call blocks till then. + */ + std::string getSaveAsUrl() + { + const auto payload = _saveAsQueue.get(); + return std::string(payload.data(), payload.size()); + } + + void setSaveAsUrl(const std::string& url) + { + _saveAsQueue.put(url); + } + +private: + + virtual bool _handleInput(const char *buffer, int length) override; private: @@ -39,8 +59,10 @@ private: // An edit lock will only allow the current session to make edits, // while other session opening the same document can only see bool _bEditLock = false; - //std::weak_ptr<PrisonerSession> _peer; + std::weak_ptr<PrisonerSession> _peer; + /// Store URLs of completed 'save as' documents. + MessageQueue _saveAsQueue; #if 0 public: MasterProcessSession(const std::string& id, @@ -66,8 +88,6 @@ private: std::shared_ptr<BasicTileQueue> getQueue() const { return _queue; } - void setPeer(const std::shared_ptr<MasterProcessSession>& peer) { _peer = peer; } - bool shutdownPeer(Poco::UInt16 statusCode, const std::string& message); public: @@ -87,21 +107,8 @@ public: void dispatchChild(); void forwardToPeer(const char *buffer, int length); - // If _kind==ToPrisoner and the child process has started and completed its handshake with the - // parent process: Points to the WebSocketSession for the child process handling the document in - // question, if any. - - // In the session to the child process, points to the LOOLSession for the LOOL client. This will - // obvious have to be rethought when we add collaboration and there can be several LOOL clients - // per document being edited (i.e., per child process). - std::weak_ptr<MasterProcessSession> _peer; - - virtual bool _handleInput(const char *buffer, int length) override; - int _curPart; int _loadPart; - /// Kind::ToClient instances store URLs of completed 'save as' documents. - MessageQueue _saveAsQueue; std::shared_ptr<DocumentBroker> _docBroker; std::shared_ptr<BasicTileQueue> _queue; #endif diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp index f6a6fe6..0c923eb 100644 --- a/loolwsd/LOOLWSD.cpp +++ b/loolwsd/LOOLWSD.cpp @@ -414,7 +414,7 @@ private: // Send it back to the client. //TODO: Should have timeout to avoid waiting forever. - Poco::URI resultURL(session->getSaveAs()); + Poco::URI resultURL(session->getSaveAsUrl()); if (!resultURL.getPath().empty()) { const std::string mimeType = "application/octet-stream"; diff --git a/loolwsd/MasterProcessSession.cpp b/loolwsd/MasterProcessSession.cpp index afc864d..91c0997 100644 --- a/loolwsd/MasterProcessSession.cpp +++ b/loolwsd/MasterProcessSession.cpp @@ -47,313 +47,6 @@ MasterProcessSession::MasterProcessSession(const std::string& id, MasterProcessSession::~MasterProcessSession() { - Log::info("~MasterProcessSession dtor [" + getName() + "]."); - - // Release the save-as queue. - _saveAsQueue.put(""); -} - -bool MasterProcessSession::_handleInput(const char *buffer, int length) -{ - const std::string firstLine = getFirstLine(buffer, length); - StringTokenizer tokens(firstLine, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); - Log::trace(getName() + ": handling [" + firstLine + "]."); - - if (LOOLProtocol::tokenIndicatesUserInteraction(tokens[0])) - { - // Keep track of timestamps of incoming client messages that indicate user activity. - updateLastActivityTime(); - } - - if (tokens[0] == "loolclient") - { - const auto versionTuple = ParseVersion(tokens[1]); - if (std::get<0>(versionTuple) != ProtocolMajorVersionNumber || - std::get<1>(versionTuple) != ProtocolMinorVersionNumber) - { - sendTextFrame("error: cmd=loolclient kind=badversion"); - return false; - } - - sendTextFrame("loolserver " + GetProtocolVersion()); - return true; - } - - if (_kind == Kind::ToPrisoner) - { - // Note that this handles both forwarding requests from the client to the child process, and - // forwarding replies from the child process to the client. Or does it? - - // Snoop at some messages and manipulate tile cache information as needed - auto peer = _peer.lock(); - - { - if (!peer) - { - throw Poco::ProtocolException("The session has not been assigned a peer."); - } - - if (tokens[0] == "unocommandresult:") - { - const std::string stringMsg(buffer, length); - Log::info(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 result = parser.parse(stringJSON); - const auto& object = result.extract<Poco::JSON::Object::Ptr>(); - if (object->get("commandName").toString() == ".uno:Save" && - object->get("success").toString() == "true") - { - _docBroker->save(); - return true; - } - } - } - - 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") - { - forwardToPeer(buffer, length); - peer->_bLoadError = true; - return false; - } - } - } - } - - if (tokens[0] == "curpart:" && - tokens.count() == 2 && - getTokenInteger(tokens[1], "part", _curPart)) - { - return true; - } - - if (tokens.count() == 2 && tokens[0] == "saveas:") - { - std::string url; - if (!getTokenString(tokens[1], "url", url)) - return true; - - if (peer) - { - // Save as completed, inform the other (Kind::ToClient) - // MasterProcessSession about it. - - 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())); - url = filePrefix + path.toString().substr(1); - } - peer->_saveAsQueue.put(url); - } - - return true; - } - else if (tokens.count() == 2 && tokens[0] == "statechanged:") - { - StringTokenizer stateTokens(tokens[1], "=", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); - if (stateTokens.count() == 2 && stateTokens[0] == ".uno:ModifiedStatus") - { - if (_docBroker) - { - _docBroker->setModified(stateTokens[1] == "true"); - } - } - } - } - - if (peer && !_isDocPasswordProtected) - { - if (tokens[0] == "tile:") - { - assert(!"Tile traffic should go through the DocumentBroker-LoKit WS."); - } - else if (tokens[0] == "status:") - { - _docBroker->setLoaded(); - _docBroker->tileCache().saveTextFile(std::string(buffer, length), "status.txt"); - - // Forward the status response to the client. - forwardToPeer(buffer, length); - - // And let clients know if they hold the edit lock. - std::string message = "editlock: "; - message += std::to_string(peer->isEditLocked()); - Log::debug("Forwarding [" + message + "] in response to status."); - forwardToPeer(message.c_str(), message.size()); - return true; - } - 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->get("commandName").toString(); - if (commandName.find(".uno:CharFontName") != std::string::npos || - commandName.find(".uno:StyleApply") != std::string::npos) - { - // 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->tileCache().invalidateTiles(firstLine); - } - else if (tokens[0] == "renderfont:") - { - std::string font; - if (tokens.count() < 2 || - !getTokenString(tokens[1], "font", font)) - assert(false); - - assert(firstLine.size() < static_cast<std::string::size_type>(length)); - _docBroker->tileCache().saveRendering(font, "font", buffer + firstLine.size() + 1, length - firstLine.size() - 1); - } - } - - forwardToPeer(buffer, length); - return true; - } - - if (_kind == Kind::ToPrisoner) - { - // Message from child process to be forwarded to client. - - // I think we should never get here - Log::error(getName() + ": Unexpected request [" + tokens[0] + "]."); - assert(false); - } - else if (tokens[0] == "takeedit") - { - _docBroker->takeEditLock(getId()); - return true; - } - else if (tokens[0] == "load") - { - if (_docURL != "") - { - sendTextFrame("error: cmd=load kind=docalreadyloaded"); - return false; - } - return loadDocument(buffer, length, tokens); - } - else if (tokens[0] != "canceltiles" && - tokens[0] != "clientzoom" && - tokens[0] != "clientvisiblearea" && - tokens[0] != "commandvalues" && - tokens[0] != "downloadas" && - tokens[0] != "getchildid" && - tokens[0] != "gettextselection" && - tokens[0] != "paste" && - tokens[0] != "insertfile" && - tokens[0] != "key" && - tokens[0] != "mouse" && - tokens[0] != "partpagerectangles" && - tokens[0] != "renderfont" && - tokens[0] != "requestloksession" && - tokens[0] != "resetselection" && - tokens[0] != "saveas" && - tokens[0] != "selectgraphic" && - tokens[0] != "selecttext" && - tokens[0] != "setclientpart" && - tokens[0] != "setpage" && - tokens[0] != "status" && - tokens[0] != "tile" && - tokens[0] != "tilecombine" && - tokens[0] != "uno" && - tokens[0] != "useractive" && - tokens[0] != "userinactive") - { - sendTextFrame("error: cmd=" + tokens[0] + " kind=unknown"); - return false; - } - else if (_docURL == "") - { - sendTextFrame("error: cmd=" + tokens[0] + " kind=nodocloaded"); - return false; - } - else if (tokens[0] == "canceltiles") - { - if (!_peer.expired()) - forwardToPeer(buffer, length); - } - else if (tokens[0] == "commandvalues") - { - return getCommandValues(buffer, length, tokens); - } - else if (tokens[0] == "partpagerectangles") - { - return getPartPageRectangles(buffer, length); - } - else if (tokens[0] == "renderfont") - { - sendFontRendering(buffer, length, tokens); - } - else if (tokens[0] == "status") - { - return getStatus(buffer, length); - } - else if (tokens[0] == "tile") - { - sendTile(buffer, length, tokens); - } - else if (tokens[0] == "tilecombine") - { - sendCombinedTiles(buffer, length, tokens); - } - else - { - // All other commands are such that they always require a - // LibreOfficeKitDocument session, i.e. need to be handled in - // a child process. - - if (_peer.expired()) - { - Log::trace("Dispatching child to handle [" + tokens[0] + "]."); - dispatchChild(); - } - - // Allow 'downloadas' for all kinds of views irrespective of editlock - if (_kind == Kind::ToClient && !isEditLocked() && tokens[0] != "downloadas" && - tokens[0] != "userinactive" && tokens[0] != "useractive") - { - std::string dummyFrame = "dummymsg"; - forwardToPeer(dummyFrame.c_str(), dummyFrame.size()); - } - else if (tokens[0] != "requestloksession") - { - forwardToPeer(buffer, length); - } - } - return true; } bool MasterProcessSession::loadDocument(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens) @@ -455,12 +148,6 @@ bool MasterProcessSession::getPartPageRectangles(const char *buffer, int length) return true; } -std::string MasterProcessSession::getSaveAs() -{ - const auto payload = _saveAsQueue.get(); - return std::string(payload.data(), payload.size()); -} - void MasterProcessSession::sendFontRendering(const char *buffer, int length, StringTokenizer& tokens) { std::string font; diff --git a/loolwsd/MasterProcessSession.hpp b/loolwsd/MasterProcessSession.hpp index fbdc41f..5dc3b46 100644 --- a/loolwsd/MasterProcessSession.hpp +++ b/loolwsd/MasterProcessSession.hpp @@ -35,18 +35,10 @@ class MasterProcessSession : public LOOLSession, public std::enable_shared_from_ virtual bool getPartPageRectangles(const char *buffer, int length) override; - /** - * Return the URL of the saved-as document when it's ready. If called - * before it's ready, the call blocks till then. - */ - std::string getSaveAs(); - std::shared_ptr<DocumentBroker> getDocumentBroker() const { return _docBroker; } std::shared_ptr<BasicTileQueue> getQueue() const { return _queue; } - void setPeer(const std::shared_ptr<MasterProcessSession>& peer) { _peer = peer; } - void setEditLock(const bool value); void markEditLock(const bool value) { _bEditLock = value; } bool isEditLocked() const { return _bEditLock; } @@ -78,12 +70,8 @@ public: // per document being edited (i.e., per child process). std::weak_ptr<MasterProcessSession> _peer; - virtual bool _handleInput(const char *buffer, int length) override; - int _curPart; int _loadPart; - /// Kind::ToClient instances store URLs of completed 'save as' documents. - MessageQueue _saveAsQueue; std::shared_ptr<DocumentBroker> _docBroker; std::shared_ptr<BasicTileQueue> _queue; diff --git a/loolwsd/PrisonerSession.cpp b/loolwsd/PrisonerSession.cpp index 6da51ec..9257616 100644 --- a/loolwsd/PrisonerSession.cpp +++ b/loolwsd/PrisonerSession.cpp @@ -19,41 +19,26 @@ #include "LOOLProtocol.hpp" #include "LOOLSession.hpp" #include "LOOLWSD.hpp" +#include "ClientSession.hpp" +#include "PrisonerSession.hpp" #include "MasterProcessSession.hpp" #include "Rectangle.hpp" #include "Storage.hpp" #include "TileCache.hpp" #include "IoUtil.hpp" #include "Util.hpp" -#if 0 + using namespace LOOLProtocol; using Poco::Path; using Poco::StringTokenizer; -MasterProcessSession::MasterProcessSession(const std::string& id, - const Kind kind, - std::shared_ptr<Poco::Net::WebSocket> ws, - std::shared_ptr<DocumentBroker> docBroker, - std::shared_ptr<BasicTileQueue> queue) : - LOOLSession(id, kind, ws), - _curPart(0), - _loadPart(-1), - _docBroker(docBroker), - _queue(queue) +PrisonerSession::~PrisonerSession() { - Log::info("MasterProcessSession ctor [" + getName() + "]."); + Log::info("~PrisonerSession dtor [" + getName() + "]."); } -MasterProcessSession::~MasterProcessSession() -{ - Log::info("~MasterProcessSession dtor [" + getName() + "]."); - - // Release the save-as queue. - _saveAsQueue.put(""); -} - -bool MasterProcessSession::_handleInput(const char *buffer, int length) +bool PrisonerSession::_handleInput(const char *buffer, int length) { const std::string firstLine = getFirstLine(buffer, length); StringTokenizer tokens(firstLine, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); @@ -65,297 +50,197 @@ bool MasterProcessSession::_handleInput(const char *buffer, int length) updateLastActivityTime(); } - if (tokens[0] == "loolclient") - { - const auto versionTuple = ParseVersion(tokens[1]); - if (std::get<0>(versionTuple) != ProtocolMajorVersionNumber || - std::get<1>(versionTuple) != ProtocolMinorVersionNumber) - { - sendTextFrame("error: cmd=loolclient kind=badversion"); - return false; - } + // Note that this handles both forwarding requests from the client to the child process, and + // forwarding replies from the child process to the client. Or does it? - sendTextFrame("loolserver " + GetProtocolVersion()); - return true; - } + // Snoop at some messages and manipulate tile cache information as needed + auto peer = _peer.lock(); - if (_kind == Kind::ToPrisoner) { - // Note that this handles both forwarding requests from the client to the child process, and - // forwarding replies from the child process to the client. Or does it? - - // Snoop at some messages and manipulate tile cache information as needed - auto peer = _peer.lock(); - + if (!peer) { - if (!peer) - { - throw Poco::ProtocolException("The session has not been assigned a peer."); - } + throw Poco::ProtocolException("The session has not been assigned a peer."); + } - if (tokens[0] == "unocommandresult:") + if (tokens[0] == "unocommandresult:") + { + const std::string stringMsg(buffer, length); + Log::info(getName() + "Command: " + stringMsg); + const auto index = stringMsg.find_first_of('{'); + if (index != std::string::npos) { - const std::string stringMsg(buffer, length); - Log::info(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 result = parser.parse(stringJSON); + const auto& object = result.extract<Poco::JSON::Object::Ptr>(); + if (object->get("commandName").toString() == ".uno:Save" && + object->get("success").toString() == "true") { - 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>(); - if (object->get("commandName").toString() == ".uno:Save" && - object->get("success").toString() == "true") - { - _docBroker->save(); - return true; - } + _docBroker->save(); + return true; } } + } - if (tokens[0] == "error:") + if (tokens[0] == "error:") + { + std::string errorCommand; + std::string errorKind; + if (getTokenString(tokens[1], "cmd", errorCommand) && + getTokenString(tokens[2], "kind", errorKind) ) { - std::string errorCommand; - std::string errorKind; - if (getTokenString(tokens[1], "cmd", errorCommand) && - getTokenString(tokens[2], "kind", errorKind) ) + if (errorCommand == "load") { - if (errorCommand == "load") + if (errorKind == "passwordrequired:to-view" || + errorKind == "passwordrequired:to-modify" || + errorKind == "wrongpassword") { - if (errorKind == "passwordrequired:to-view" || - errorKind == "passwordrequired:to-modify" || - errorKind == "wrongpassword") - { - forwardToPeer(buffer, length); - peer->_bLoadError = true; - return false; - } + forwardToPeer(buffer, length); + peer->_bLoadError = true; + return false; } } } + } - if (tokens[0] == "curpart:" && - tokens.count() == 2 && - getTokenInteger(tokens[1], "part", _curPart)) - { + if (tokens[0] == "curpart:" && + tokens.count() == 2 && + getTokenInteger(tokens[1], "part", _curPart)) + { + return true; + } + + if (tokens.count() == 2 && tokens[0] == "saveas:") + { + std::string url; + if (!getTokenString(tokens[1], "url", url)) return true; - } - if (tokens.count() == 2 && tokens[0] == "saveas:") + if (peer) { - std::string url; - if (!getTokenString(tokens[1], "url", url)) - return true; + // Save as completed, inform the other (Kind::ToClient) + // MasterProcessSession about it. - if (peer) + const std::string filePrefix("file:///"); + if (url.find(filePrefix) == 0) { - // Save as completed, inform the other (Kind::ToClient) - // MasterProcessSession about it. - - 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())); - url = filePrefix + path.toString().substr(1); - } - peer->_saveAsQueue.put(url); + // Rewrite file:// URLs, as they are visible to the outside world. + const Path path(_docBroker->getJailRoot(), url.substr(filePrefix.length())); + url = filePrefix + path.toString().substr(1); } - return true; - } - else if (tokens.count() == 2 && tokens[0] == "statechanged:") - { - StringTokenizer stateTokens(tokens[1], "=", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); - if (stateTokens.count() == 2 && stateTokens[0] == ".uno:ModifiedStatus") - { - if (_docBroker) - { - _docBroker->setModified(stateTokens[1] == "true"); - } - } + peer->setSaveAsUrl(url); } - } - if (peer && !_isDocPasswordProtected) + return true; + } + else if (tokens.count() == 2 && tokens[0] == "statechanged:") { - if (tokens[0] == "tile:") - { - assert(!"Tile traffic should go through the DocumentBroker-LoKit WS."); - } - else if (tokens[0] == "status:") - { - _docBroker->setLoaded(); - _docBroker->tileCache().saveTextFile(std::string(buffer, length), "status.txt"); - - // Forward the status response to the client. - forwardToPeer(buffer, length); - - // And let clients know if they hold the edit lock. - std::string message = "editlock: "; - message += std::to_string(peer->isEditLocked()); - Log::debug("Forwarding [" + message + "] in response to status."); - forwardToPeer(message.c_str(), message.size()); - return true; - } - else if (tokens[0] == "commandvalues:") + StringTokenizer stateTokens(tokens[1], "=", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); + if (stateTokens.count() == 2 && stateTokens[0] == ".uno:ModifiedStatus") { - const std::string stringMsg(buffer, length); - const auto index = stringMsg.find_first_of('{'); - if (index != std::string::npos) + if (_docBroker) { - 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->get("commandName").toString(); - if (commandName.find(".uno:CharFontName") != std::string::npos || - commandName.find(".uno:StyleApply") != std::string::npos) - { - // other commands should not be cached - _docBroker->tileCache().saveTextFile(stringMsg, "cmdValues" + commandName + ".txt"); - } + _docBroker->setModified(stateTokens[1] == "true"); } } - 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->tileCache().invalidateTiles(firstLine); - } - else if (tokens[0] == "renderfont:") - { - std::string font; - if (tokens.count() < 2 || - !getTokenString(tokens[1], "font", font)) - assert(false); - - assert(firstLine.size() < static_cast<std::string::size_type>(length)); - _docBroker->tileCache().saveRendering(font, "font", buffer + firstLine.size() + 1, length - firstLine.size() - 1); - } } - - forwardToPeer(buffer, length); - return true; } - if (_kind == Kind::ToPrisoner) - { - // Message from child process to be forwarded to client. - - // I think we should never get here - Log::error(getName() + ": Unexpected request [" + tokens[0] + "]."); - assert(false); - } - else if (tokens[0] == "takeedit") + if (peer && !_isDocPasswordProtected) { - _docBroker->takeEditLock(getId()); - return true; - } - else if (tokens[0] == "load") - { - if (_docURL != "") + if (tokens[0] == "tile:") { - sendTextFrame("error: cmd=load kind=docalreadyloaded"); - return false; + assert(!"Tile traffic should go through the DocumentBroker-LoKit WS."); } - return loadDocument(buffer, length, tokens); - } - else if (tokens[0] != "canceltiles" && - tokens[0] != "clientzoom" && - tokens[0] != "clientvisiblearea" && - tokens[0] != "commandvalues" && - tokens[0] != "downloadas" && - tokens[0] != "getchildid" && - tokens[0] != "gettextselection" && - tokens[0] != "paste" && - tokens[0] != "insertfile" && - tokens[0] != "key" && - tokens[0] != "mouse" && - tokens[0] != "partpagerectangles" && - tokens[0] != "renderfont" && - tokens[0] != "requestloksession" && - tokens[0] != "resetselection" && - tokens[0] != "saveas" && - tokens[0] != "selectgraphic" && - tokens[0] != "selecttext" && - tokens[0] != "setclientpart" && - tokens[0] != "setpage" && - tokens[0] != "status" && - tokens[0] != "tile" && - tokens[0] != "tilecombine" && - tokens[0] != "uno" && - tokens[0] != "useractive" && - tokens[0] != "userinactive") - { - sendTextFrame("error: cmd=" + tokens[0] + " kind=unknown"); - return false; - } - else if (_docURL == "") - { - sendTextFrame("error: cmd=" + tokens[0] + " kind=nodocloaded"); - return false; - } - else if (tokens[0] == "canceltiles") - { - if (!_peer.expired()) + else if (tokens[0] == "status:") + { + _docBroker->setLoaded(); + _docBroker->tileCache().saveTextFile(std::string(buffer, length), "status.txt"); + + // Forward the status response to the client. forwardToPeer(buffer, length); - } - else if (tokens[0] == "commandvalues") - { - return getCommandValues(buffer, length, tokens); - } - else if (tokens[0] == "partpagerectangles") - { - return getPartPageRectangles(buffer, length); - } - else if (tokens[0] == "renderfont") - { - sendFontRendering(buffer, length, tokens); - } - else if (tokens[0] == "status") - { - return getStatus(buffer, length); - } - else if (tokens[0] == "tile") - { - sendTile(buffer, length, tokens); - } - else if (tokens[0] == "tilecombine") - { - sendCombinedTiles(buffer, length, tokens); - } - else - { - // All other commands are such that they always require a - // LibreOfficeKitDocument session, i.e. need to be handled in - // a child process. - if (_peer.expired()) + // And let clients know if they hold the edit lock. + std::string message = "editlock: "; + message += std::to_string(peer->isEditLocked()); + Log::debug("Forwarding [" + message + "] in response to status."); + forwardToPeer(message.c_str(), message.size()); + return true; + } + else if (tokens[0] == "commandvalues:") { - Log::trace("Dispatching child to handle [" + tokens[0] + "]."); - dispatchChild(); + 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->get("commandName").toString(); + if (commandName.find(".uno:CharFontName") != std::string::npos || + commandName.find(".uno:StyleApply") != std::string::npos) + { + // other commands should not be cached + _docBroker->tileCache().saveTextFile(stringMsg, "cmdValues" + commandName + ".txt"); + } + } } - - // Allow 'downloadas' for all kinds of views irrespective of editlock - if (_kind == Kind::ToClient && !isEditLocked() && tokens[0] != "downloadas" && - tokens[0] != "userinactive" && tokens[0] != "useractive") + else if (tokens[0] == "partpagerectangles:") { - std::string dummyFrame = "dummymsg"; - forwardToPeer(dummyFrame.c_str(), dummyFrame.size()); + if (tokens.count() > 1 && !tokens[1].empty()) + _docBroker->tileCache().saveTextFile(std::string(buffer, length), "partpagerectangles.txt"); } - else if (tokens[0] != "requestloksession") + else if (tokens[0] == "invalidatetiles:") { - forwardToPeer(buffer, length); + assert(firstLine.size() == static_cast<std::string::size_type>(length)); + _docBroker->tileCache().invalidateTiles(firstLine); + } + else if (tokens[0] == "renderfont:") + { + std::string font; + if (tokens.count() < 2 || + !getTokenString(tokens[1], "font", font)) + assert(false); + + assert(firstLine.size() < static_cast<std::string::size_type>(length)); + _docBroker->tileCache().saveRendering(font, "font", buffer + firstLine.size() + 1, length - firstLine.size() - 1); } } + + forwardToPeer(buffer, length); return true; } +#if 0 +using namespace LOOLProtocol; + +using Poco::Path; +using Poco::StringTokenizer; + +MasterProcessSession::MasterProcessSession(const std::string& id, + const Kind kind, + std::shared_ptr<Poco::Net::WebSocket> ws, + std::shared_ptr<DocumentBroker> docBroker, + std::shared_ptr<BasicTileQueue> queue) : + LOOLSession(id, kind, ws), + _curPart(0), + _loadPart(-1), + _docBroker(docBroker), + _queue(queue) +{ + Log::info("MasterProcessSession ctor [" + getName() + "]."); +} + +MasterProcessSession::~MasterProcessSession() +{ + Log::info("~MasterProcessSession dtor [" + getName() + "]."); + + // Release the save-as queue. + _saveAsQueue.put(""); +} + bool MasterProcessSession::loadDocument(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens) { if (tokens.count() < 2) diff --git a/loolwsd/PrisonerSession.hpp b/loolwsd/PrisonerSession.hpp index 3cbbe33..65418ee 100644 --- a/loolwsd/PrisonerSession.hpp +++ b/loolwsd/PrisonerSession.hpp @@ -26,11 +26,17 @@ class PrisonerSession final : public MasterProcessSession//, public std::enable_ public: using MasterProcessSession::MasterProcessSession; - //void setPeer(const std::shared_ptr<ClientSession>& peer) { _peer = peer; } + virtual ~PrisonerSession(); + + void setPeer(const std::shared_ptr<ClientSession>& peer) { MasterProcessSession::_peer = _peer = peer; } + +private: + + virtual bool _handleInput(const char *buffer, int length) override; private: - //std::weak_ptr<ClientSession> _peer; + std::weak_ptr<ClientSession> _peer; #if 0 public: MasterProcessSession(const std::string& id, @@ -56,8 +62,6 @@ private: std::shared_ptr<BasicTileQueue> getQueue() const { return _queue; } - void setPeer(const std::shared_ptr<MasterProcessSession>& peer) { _peer = peer; } - bool shutdownPeer(Poco::UInt16 statusCode, const std::string& message); public: @@ -77,17 +81,6 @@ public: void dispatchChild(); void forwardToPeer(const char *buffer, int length); - // If _kind==ToPrisoner and the child process has started and completed its handshake with the - // parent process: Points to the WebSocketSession for the child process handling the document in - // question, if any. - - // In the session to the child process, points to the LOOLSession for the LOOL client. This will - // obvious have to be rethought when we add collaboration and there can be several LOOL clients - // per document being edited (i.e., per child process). - std::weak_ptr<MasterProcessSession> _peer; - - virtual bool _handleInput(const char *buffer, int length) override; - int _curPart; int _loadPart; /// Kind::ToClient instances store URLs of completed 'save as' documents. _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
