[Libreoffice-commits] online.git: loolwsd/ClientSession.cpp loolwsd/ClientSession.hpp loolwsd/LOOLWSD.cpp loolwsd/MasterProcessSession.cpp loolwsd/MasterProcessSession.hpp loolwsd/PrisonerSession.cpp loolwsd/PrisonerSession.hpp
Ashod Nakashian
ashod.nakashian at collabora.co.uk
Tue May 17 03:14:24 UTC 2016
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 <ashod.nakashian at collabora.co.uk>
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 <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
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.
More information about the Libreoffice-commits
mailing list