2016-05-16 06:37:02 -05:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
|
|
|
/*
|
|
|
|
* This file is part of the LibreOffice project.
|
|
|
|
*
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
*/
|
|
|
|
|
loolwsd: include cleanup and organization
A source file (.cpp) must include its own header first.
This insures that the header is self-contained and
doesn't depend on arbitrary (and accidental) includes
before it to compile.
Furthermore, system headers should go next, followed by
C then C++ headers, then libraries (Poco, etc) and, finally,
project headers come last.
This makes sure that headers and included in the same dependency
order to avoid side-effects. For example, Poco should never rely on
anything from our project in the same way that a C header should
never rely on anything in C++, Poco, or project headers.
Also, includes ought to be sorted where possible, to improve
readability and avoid accidental duplicates (of which there
were a few).
Change-Id: I62cc1343e4a091d69195e37ed659dba20cfcb1ef
Reviewed-on: https://gerrit.libreoffice.org/25262
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-21 09:23:07 -05:00
|
|
|
#include "ClientSession.hpp"
|
2016-05-16 06:37:02 -05:00
|
|
|
#include "config.h"
|
|
|
|
|
loolwsd: include cleanup and organization
A source file (.cpp) must include its own header first.
This insures that the header is self-contained and
doesn't depend on arbitrary (and accidental) includes
before it to compile.
Furthermore, system headers should go next, followed by
C then C++ headers, then libraries (Poco, etc) and, finally,
project headers come last.
This makes sure that headers and included in the same dependency
order to avoid side-effects. For example, Poco should never rely on
anything from our project in the same way that a C header should
never rely on anything in C++, Poco, or project headers.
Also, includes ought to be sorted where possible, to improve
readability and avoid accidental duplicates (of which there
were a few).
Change-Id: I62cc1343e4a091d69195e37ed659dba20cfcb1ef
Reviewed-on: https://gerrit.libreoffice.org/25262
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-21 09:23:07 -05:00
|
|
|
#include <fstream>
|
|
|
|
|
2016-05-16 06:37:02 -05:00
|
|
|
#include <Poco/FileStream.h>
|
|
|
|
#include <Poco/JSON/Object.h>
|
|
|
|
#include <Poco/JSON/Parser.h>
|
|
|
|
#include <Poco/URI.h>
|
|
|
|
#include <Poco/URIStreamOpener.h>
|
|
|
|
|
|
|
|
#include "Common.hpp"
|
loolwsd: include cleanup and organization
A source file (.cpp) must include its own header first.
This insures that the header is self-contained and
doesn't depend on arbitrary (and accidental) includes
before it to compile.
Furthermore, system headers should go next, followed by
C then C++ headers, then libraries (Poco, etc) and, finally,
project headers come last.
This makes sure that headers and included in the same dependency
order to avoid side-effects. For example, Poco should never rely on
anything from our project in the same way that a C header should
never rely on anything in C++, Poco, or project headers.
Also, includes ought to be sorted where possible, to improve
readability and avoid accidental duplicates (of which there
were a few).
Change-Id: I62cc1343e4a091d69195e37ed659dba20cfcb1ef
Reviewed-on: https://gerrit.libreoffice.org/25262
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-21 09:23:07 -05:00
|
|
|
#include "IoUtil.hpp"
|
2016-05-16 06:37:02 -05:00
|
|
|
#include "LOOLProtocol.hpp"
|
|
|
|
#include "LOOLSession.hpp"
|
|
|
|
#include "LOOLWSD.hpp"
|
loolwsd: include cleanup and organization
A source file (.cpp) must include its own header first.
This insures that the header is self-contained and
doesn't depend on arbitrary (and accidental) includes
before it to compile.
Furthermore, system headers should go next, followed by
C then C++ headers, then libraries (Poco, etc) and, finally,
project headers come last.
This makes sure that headers and included in the same dependency
order to avoid side-effects. For example, Poco should never rely on
anything from our project in the same way that a C header should
never rely on anything in C++, Poco, or project headers.
Also, includes ought to be sorted where possible, to improve
readability and avoid accidental duplicates (of which there
were a few).
Change-Id: I62cc1343e4a091d69195e37ed659dba20cfcb1ef
Reviewed-on: https://gerrit.libreoffice.org/25262
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
2016-05-21 09:23:07 -05:00
|
|
|
#include "Log.hpp"
|
2016-05-16 18:05:22 -05:00
|
|
|
#include "PrisonerSession.hpp"
|
2016-05-16 06:37:02 -05:00
|
|
|
#include "Rectangle.hpp"
|
|
|
|
#include "Storage.hpp"
|
|
|
|
#include "TileCache.hpp"
|
|
|
|
#include "Util.hpp"
|
2016-05-16 17:22:41 -05:00
|
|
|
|
2016-05-16 18:05:22 -05:00
|
|
|
using namespace LOOLProtocol;
|
|
|
|
|
|
|
|
using Poco::StringTokenizer;
|
|
|
|
|
2016-05-16 19:49:36 -05:00
|
|
|
ClientSession::ClientSession(const std::string& id,
|
|
|
|
std::shared_ptr<Poco::Net::WebSocket> ws,
|
|
|
|
std::shared_ptr<DocumentBroker> docBroker,
|
2016-10-16 11:40:52 -05:00
|
|
|
const Poco::URI& uriPublic,
|
|
|
|
const bool readOnly) :
|
2016-05-16 21:48:33 -05:00
|
|
|
LOOLSession(id, Kind::ToClient, ws),
|
2016-07-15 07:46:47 -05:00
|
|
|
_docBroker(std::move(docBroker)),
|
2016-10-16 11:40:52 -05:00
|
|
|
_uriPublic(uriPublic),
|
2016-07-11 02:45:10 -05:00
|
|
|
_isReadOnly(readOnly),
|
2016-05-16 20:03:45 -05:00
|
|
|
_loadPart(-1)
|
2016-05-16 19:49:36 -05:00
|
|
|
{
|
|
|
|
Log::info("ClientSession ctor [" + getName() + "].");
|
|
|
|
}
|
|
|
|
|
2016-05-16 18:05:22 -05:00
|
|
|
ClientSession::~ClientSession()
|
|
|
|
{
|
2016-05-17 17:33:37 -05:00
|
|
|
Log::info("~ClientSession dtor [" + getName() + "].");
|
2016-05-16 18:05:22 -05:00
|
|
|
|
|
|
|
// 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 + "].");
|
|
|
|
|
2016-08-03 07:15:04 -05:00
|
|
|
LOOLWSD::dumpIncomingTrace(_docBroker->getJailId(), getId(), firstLine);
|
2016-07-30 22:06:12 -05:00
|
|
|
|
2016-05-16 18:05:22 -05:00
|
|
|
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)
|
|
|
|
{
|
2016-06-20 13:58:00 -05:00
|
|
|
sendTextFrame("error: cmd=loolclient kind=badprotocolversion");
|
2016-05-16 18:05:22 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-06-20 13:58:00 -05:00
|
|
|
// Send LOOL version information
|
|
|
|
std::string version, hash;
|
|
|
|
Util::getVersionInfo(version, hash);
|
2016-06-21 11:41:33 -05:00
|
|
|
std::string versionStr =
|
|
|
|
"{ \"Version\": \"" + version + "\", " +
|
|
|
|
"\"Hash\": \"" + hash + "\", " +
|
|
|
|
"\"Protocol\": \"" + GetProtocolVersion() + "\" }";
|
|
|
|
sendTextFrame("loolserver " + versionStr);
|
2016-06-20 13:58:00 -05:00
|
|
|
// Send LOKit version information
|
|
|
|
sendTextFrame("lokitversion " + LOOLWSD::LOKitVersion);
|
|
|
|
|
|
|
|
return true;
|
2016-05-16 18:05:22 -05:00
|
|
|
}
|
|
|
|
|
2016-09-20 02:46:39 -05:00
|
|
|
if (tokens[0] == "load")
|
2016-05-16 18:05:22 -05:00
|
|
|
{
|
|
|
|
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" &&
|
2016-09-27 13:22:09 -05:00
|
|
|
tokens[0] != "ping" &&
|
2016-05-16 18:05:22 -05:00
|
|
|
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")
|
|
|
|
{
|
2016-08-30 22:15:44 -05:00
|
|
|
_docBroker->cancelTileRequests(shared_from_this());
|
|
|
|
return true;
|
2016-05-16 18:05:22 -05:00
|
|
|
}
|
|
|
|
else if (tokens[0] == "commandvalues")
|
|
|
|
{
|
|
|
|
return getCommandValues(buffer, length, tokens);
|
|
|
|
}
|
|
|
|
else if (tokens[0] == "partpagerectangles")
|
|
|
|
{
|
|
|
|
return getPartPageRectangles(buffer, length);
|
|
|
|
}
|
2016-09-27 13:22:09 -05:00
|
|
|
else if (tokens[0] == "ping")
|
|
|
|
{
|
2016-10-11 07:39:56 -05:00
|
|
|
std::string count = std::to_string(_docBroker->getRenderedTileCount());
|
|
|
|
sendTextFrame("pong rendercount=" + count);
|
2016-09-27 13:22:09 -05:00
|
|
|
return true;
|
|
|
|
}
|
2016-05-16 18:05:22 -05:00
|
|
|
else if (tokens[0] == "renderfont")
|
|
|
|
{
|
2016-05-20 18:25:38 -05:00
|
|
|
return sendFontRendering(buffer, length, tokens);
|
2016-05-16 18:05:22 -05:00
|
|
|
}
|
|
|
|
else if (tokens[0] == "status")
|
|
|
|
{
|
|
|
|
return getStatus(buffer, length);
|
|
|
|
}
|
|
|
|
else if (tokens[0] == "tile")
|
|
|
|
{
|
2016-05-20 18:25:38 -05:00
|
|
|
return sendTile(buffer, length, tokens);
|
2016-05-16 18:05:22 -05:00
|
|
|
}
|
|
|
|
else if (tokens[0] == "tilecombine")
|
|
|
|
{
|
2016-05-20 18:25:38 -05:00
|
|
|
return sendCombinedTiles(buffer, length, tokens);
|
2016-05-16 18:05:22 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-09-19 02:03:31 -05:00
|
|
|
// Allow 'downloadas' for all kinds of views
|
|
|
|
if ( (isReadOnly()) && tokens[0] != "downloadas" &&
|
2016-07-10 23:50:25 -05:00
|
|
|
tokens[0] != "userinactive" && tokens[0] != "useractive")
|
2016-05-16 18:05:22 -05:00
|
|
|
{
|
|
|
|
std::string dummyFrame = "dummymsg";
|
2016-10-08 17:21:35 -05:00
|
|
|
return forwardToChild(dummyFrame.c_str(), dummyFrame.size());
|
2016-05-16 18:05:22 -05:00
|
|
|
}
|
|
|
|
else if (tokens[0] != "requestloksession")
|
|
|
|
{
|
2016-10-08 17:21:35 -05:00
|
|
|
return forwardToChild(buffer, length);
|
2016-05-20 18:25:38 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(tokens[0] == "requestloksession");
|
|
|
|
return true;
|
2016-05-16 18:05:22 -05:00
|
|
|
}
|
|
|
|
}
|
2016-05-20 18:25:38 -05:00
|
|
|
|
|
|
|
return false;
|
2016-05-16 18:05:22 -05:00
|
|
|
}
|
|
|
|
|
2016-05-16 18:11:34 -05:00
|
|
|
bool ClientSession::loadDocument(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
|
|
|
|
{
|
|
|
|
if (tokens.count() < 2)
|
|
|
|
{
|
2016-05-20 18:25:38 -05:00
|
|
|
// Failed loading ends connection.
|
2016-05-16 18:11:34 -05:00
|
|
|
sendTextFrame("error: cmd=load kind=syntax");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-05-20 14:25:42 -05:00
|
|
|
Log::info("Requesting document load from child.");
|
2016-05-16 18:11:34 -05:00
|
|
|
try
|
|
|
|
{
|
|
|
|
std::string timestamp;
|
|
|
|
parseDocOptions(tokens, _loadPart, timestamp);
|
|
|
|
|
2016-05-20 14:25:42 -05:00
|
|
|
std::ostringstream oss;
|
|
|
|
oss << "load";
|
|
|
|
oss << " url=" << _docBroker->getPublicUri().toString();
|
|
|
|
oss << " jail=" << _docBroker->getJailedUri().toString();
|
2016-05-16 18:11:34 -05:00
|
|
|
|
2016-08-29 13:08:01 -05:00
|
|
|
if (!_userName.empty())
|
2016-08-30 01:08:07 -05:00
|
|
|
{
|
|
|
|
std::string encodedUserName;
|
|
|
|
Poco::URI::encode(_userName, "", encodedUserName);
|
|
|
|
oss << " author=" + encodedUserName;
|
|
|
|
}
|
2016-08-29 13:08:01 -05:00
|
|
|
|
2016-05-20 14:25:42 -05:00
|
|
|
if (_loadPart >= 0)
|
|
|
|
oss << " part=" + std::to_string(_loadPart);
|
|
|
|
|
|
|
|
if (_haveDocPassword)
|
|
|
|
oss << " password=" << _docPassword;
|
|
|
|
|
|
|
|
if (!_docOptions.empty())
|
|
|
|
oss << " options=" << _docOptions;
|
|
|
|
|
|
|
|
const auto loadRequest = oss.str();
|
2016-10-08 17:21:35 -05:00
|
|
|
return forwardToChild(loadRequest.c_str(), loadRequest.size());
|
2016-05-16 18:11:34 -05:00
|
|
|
}
|
|
|
|
catch (const Poco::SyntaxException&)
|
|
|
|
{
|
|
|
|
sendTextFrame("error: cmd=load kind=uriinvalid");
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-05-16 18:20:35 -05:00
|
|
|
bool ClientSession::getStatus(const char *buffer, int length)
|
2016-05-16 06:37:02 -05:00
|
|
|
{
|
2016-10-08 17:21:35 -05:00
|
|
|
return forwardToChild(buffer, length);
|
2016-05-16 06:37:02 -05:00
|
|
|
}
|
2016-05-16 18:44:15 -05:00
|
|
|
|
2016-05-16 18:20:35 -05:00
|
|
|
bool ClientSession::getCommandValues(const char *buffer, int length, StringTokenizer& tokens)
|
2016-05-16 06:37:02 -05:00
|
|
|
{
|
|
|
|
std::string command;
|
|
|
|
if (tokens.count() != 2 || !getTokenString(tokens[1], "command", command))
|
|
|
|
{
|
2016-05-20 18:25:38 -05:00
|
|
|
return sendTextFrame("error: cmd=commandvalues kind=syntax");
|
2016-05-16 06:37:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
const std::string cmdValues = _docBroker->tileCache().getTextFile("cmdValues" + command + ".txt");
|
|
|
|
if (cmdValues.size() > 0)
|
|
|
|
{
|
2016-05-20 18:25:38 -05:00
|
|
|
return sendTextFrame(cmdValues);
|
2016-05-16 06:37:02 -05:00
|
|
|
}
|
|
|
|
|
2016-10-08 17:21:35 -05:00
|
|
|
return forwardToChild(buffer, length);
|
2016-05-16 06:37:02 -05:00
|
|
|
}
|
|
|
|
|
2016-05-16 18:20:35 -05:00
|
|
|
bool ClientSession::getPartPageRectangles(const char *buffer, int length)
|
2016-05-16 06:37:02 -05:00
|
|
|
{
|
|
|
|
const std::string partPageRectangles = _docBroker->tileCache().getTextFile("partpagerectangles.txt");
|
|
|
|
if (partPageRectangles.size() > 0)
|
|
|
|
{
|
2016-05-20 18:25:38 -05:00
|
|
|
return sendTextFrame(partPageRectangles);
|
2016-05-16 06:37:02 -05:00
|
|
|
}
|
|
|
|
|
2016-10-08 17:21:35 -05:00
|
|
|
return forwardToChild(buffer, length);
|
2016-05-16 06:37:02 -05:00
|
|
|
}
|
|
|
|
|
2016-05-20 18:25:38 -05:00
|
|
|
bool ClientSession::sendFontRendering(const char *buffer, int length, StringTokenizer& tokens)
|
2016-05-16 06:37:02 -05:00
|
|
|
{
|
|
|
|
std::string font;
|
|
|
|
if (tokens.count() < 2 ||
|
|
|
|
!getTokenString(tokens[1], "font", font))
|
|
|
|
{
|
2016-05-20 18:25:38 -05:00
|
|
|
return sendTextFrame("error: cmd=renderfont kind=syntax");
|
2016-05-16 06:37:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
const std::string response = "renderfont: " + Poco::cat(std::string(" "), tokens.begin() + 1, tokens.end()) + "\n";
|
|
|
|
|
|
|
|
std::vector<char> output;
|
|
|
|
output.resize(response.size());
|
|
|
|
std::memcpy(output.data(), response.data(), response.size());
|
|
|
|
|
|
|
|
std::unique_ptr<std::fstream> cachedRendering = _docBroker->tileCache().lookupRendering(font, "font");
|
|
|
|
if (cachedRendering && cachedRendering->is_open())
|
|
|
|
{
|
|
|
|
cachedRendering->seekg(0, std::ios_base::end);
|
|
|
|
size_t pos = output.size();
|
|
|
|
std::streamsize size = cachedRendering->tellg();
|
|
|
|
output.resize(pos + size);
|
|
|
|
cachedRendering->seekg(0, std::ios_base::beg);
|
|
|
|
cachedRendering->read(output.data() + pos, size);
|
|
|
|
cachedRendering->close();
|
|
|
|
|
2016-05-20 18:25:38 -05:00
|
|
|
return sendBinaryFrame(output.data(), output.size());
|
2016-05-16 06:37:02 -05:00
|
|
|
}
|
|
|
|
|
2016-10-08 17:21:35 -05:00
|
|
|
return forwardToChild(buffer, length);
|
2016-05-16 06:37:02 -05:00
|
|
|
}
|
|
|
|
|
2016-05-20 18:25:38 -05:00
|
|
|
bool ClientSession::sendTile(const char * /*buffer*/, int /*length*/, StringTokenizer& tokens)
|
2016-05-16 06:37:02 -05:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
auto tileDesc = TileDesc::parse(tokens);
|
|
|
|
_docBroker->handleTileRequest(tileDesc, shared_from_this());
|
|
|
|
}
|
|
|
|
catch (const std::exception& exc)
|
|
|
|
{
|
|
|
|
Log::error(std::string("Failed to process tile command: ") + exc.what() + ".");
|
2016-05-20 18:25:38 -05:00
|
|
|
return sendTextFrame("error: cmd=tile kind=invalid");
|
2016-05-16 06:37:02 -05:00
|
|
|
}
|
2016-05-20 18:25:38 -05:00
|
|
|
|
|
|
|
return true;
|
2016-05-16 06:37:02 -05:00
|
|
|
}
|
|
|
|
|
2016-05-20 18:25:38 -05:00
|
|
|
bool ClientSession::sendCombinedTiles(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
|
2016-05-16 06:37:02 -05:00
|
|
|
{
|
2016-05-22 10:45:28 -05:00
|
|
|
try
|
2016-05-16 06:37:02 -05:00
|
|
|
{
|
2016-05-22 10:45:28 -05:00
|
|
|
auto tileCombined = TileCombined::parse(tokens);
|
|
|
|
_docBroker->handleTileCombinedRequest(tileCombined, shared_from_this());
|
2016-05-16 06:37:02 -05:00
|
|
|
}
|
2016-05-22 10:45:28 -05:00
|
|
|
catch (const std::exception& exc)
|
2016-05-16 06:37:02 -05:00
|
|
|
{
|
2016-05-22 10:45:28 -05:00
|
|
|
Log::error(std::string("Failed to process tilecombine command: ") + exc.what() + ".");
|
|
|
|
return sendTextFrame("error: cmd=tile kind=invalid");
|
2016-05-16 06:37:02 -05:00
|
|
|
}
|
2016-05-20 18:25:38 -05:00
|
|
|
|
|
|
|
return true;
|
2016-05-16 06:37:02 -05:00
|
|
|
}
|
|
|
|
|
2016-10-12 05:05:57 -05:00
|
|
|
bool ClientSession::shutdownPeer(Poco::UInt16 statusCode)
|
2016-05-16 21:48:33 -05:00
|
|
|
{
|
2016-10-12 22:04:07 -05:00
|
|
|
if (_peer && !_peer->isCloseFrame())
|
2016-05-16 21:48:33 -05:00
|
|
|
{
|
2016-10-12 22:04:07 -05:00
|
|
|
_peer->shutdown(statusCode);
|
|
|
|
return true;
|
2016-05-16 21:48:33 -05:00
|
|
|
}
|
2016-10-12 22:04:07 -05:00
|
|
|
|
|
|
|
return false;
|
2016-05-16 21:48:33 -05:00
|
|
|
}
|
|
|
|
|
2016-10-08 13:25:27 -05:00
|
|
|
bool ClientSession::forwardToChild(const char *buffer, int length)
|
|
|
|
{
|
|
|
|
return _docBroker->forwardToChild(getId(), buffer, length);
|
|
|
|
}
|
|
|
|
|
2016-05-16 06:37:02 -05:00
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|