[Libreoffice-commits] online.git: 6 commits - net/Socket.cpp net/Socket.hpp wsd/Admin.cpp wsd/Admin.hpp wsd/AdminModel.cpp wsd/AdminModel.hpp wsd/Exceptions.hpp wsd/FileServer.cpp wsd/LOOLWSD.cpp
Michael Meeks
michael.meeks at collabora.com
Wed Mar 15 18:35:57 UTC 2017
net/Socket.cpp | 57 +++++++++++++
net/Socket.hpp | 53 +-----------
wsd/Admin.cpp | 222 +++++++++++++++++++++++++++--------------------------
wsd/Admin.hpp | 92 ++++++---------------
wsd/AdminModel.cpp | 6 -
wsd/AdminModel.hpp | 10 +-
wsd/Exceptions.hpp | 9 --
wsd/FileServer.cpp | 2
wsd/LOOLWSD.cpp | 18 ++--
9 files changed, 225 insertions(+), 244 deletions(-)
New commits:
commit f392d9e6f0103360dbcaaf99fc4768dfd9624eba
Author: Michael Meeks <michael.meeks at collabora.com>
Date: Wed Mar 15 18:21:59 2017 +0000
Move http serving into socket impl.
Avoid caching headers with parameter, and add Date: parameter.
diff --git a/net/Socket.cpp b/net/Socket.cpp
index 5f13202..7af8760 100644
--- a/net/Socket.cpp
+++ b/net/Socket.cpp
@@ -12,6 +12,10 @@
#include <stdio.h>
#include <ctype.h>
+#include <Poco/DateTime.h>
+#include <Poco/DateTimeFormat.h>
+#include <Poco/DateTimeFormatter.h>
+
#include "SigUtil.hpp"
#include "Socket.hpp"
#include "ServerSocket.hpp"
@@ -147,4 +151,57 @@ void SocketPoll::dumpState(std::ostream& os)
i->dumpState(os);
}
+namespace HttpHelper
+{
+ void sendFile(const std::shared_ptr<StreamSocket>& socket, const std::string& path,
+ Poco::Net::HTTPResponse& response, bool noCache)
+ {
+ struct stat st;
+ if (stat(path.c_str(), &st) != 0)
+ {
+ LOG_WRN("#" << socket->getFD() << ": Failed to stat [" << path << "]. File will not be sent.");
+ throw Poco::FileNotFoundException("Failed to stat [" + path + "]. File will not be sent.");
+ return;
+ }
+
+ int bufferSize = std::min(st.st_size, (off_t)Socket::MaximumSendBufferSize);
+ if (st.st_size >= socket->getSendBufferSize())
+ {
+ socket->setSocketBufferSize(bufferSize);
+ bufferSize = socket->getSendBufferSize();
+ }
+
+ response.setContentLength(st.st_size);
+ response.set("User-Agent", HTTP_AGENT_STRING);
+ response.set("Date", Poco::DateTimeFormatter::format(Poco::Timestamp(), Poco::DateTimeFormat::HTTP_FORMAT));
+ if (!noCache)
+ {
+ // 60 * 60 * 24 * 128 (days) = 11059200
+ response.set("Cache-Control", "max-age=11059200");
+ response.set("ETag", "\"" LOOLWSD_VERSION_HASH "\"");
+ }
+
+ std::ostringstream oss;
+ response.write(oss);
+ const std::string header = oss.str();
+ LOG_TRC("#" << socket->getFD() << ": Sending file [" << path << "]: " << header);
+ socket->send(header);
+
+ std::ifstream file(path, std::ios::binary);
+ bool flush = true;
+ do
+ {
+ char buf[bufferSize];
+ file.read(buf, sizeof(buf));
+ const int size = file.gcount();
+ if (size > 0)
+ socket->send(buf, size, flush);
+ else
+ break;
+ flush = false;
+ }
+ while (file);
+ }
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/net/Socket.hpp b/net/Socket.hpp
index 9460c45..708ae39 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -820,58 +820,15 @@ protected:
namespace HttpHelper
{
- inline void sendFile(const std::shared_ptr<StreamSocket>& socket, const std::string& path,
- Poco::Net::HTTPResponse& response)
- {
- struct stat st;
- if (stat(path.c_str(), &st) != 0)
- {
- LOG_WRN("#" << socket->getFD() << ": Failed to stat [" << path << "]. File will not be sent.");
- throw Poco::FileNotFoundException("Failed to stat [" + path + "]. File will not be sent.");
- return;
- }
-
- int bufferSize = std::min(st.st_size, (off_t)Socket::MaximumSendBufferSize);
- if (st.st_size >= socket->getSendBufferSize())
- {
- socket->setSocketBufferSize(bufferSize);
- bufferSize = socket->getSendBufferSize();
- }
-
- response.setContentLength(st.st_size);
- response.set("User-Agent", HTTP_AGENT_STRING);
- // 60 * 60 * 24 * 128 (days) = 11059200
- response.set("Cache-Control", "max-age=11059200");
- response.set("ETag", "\"" LOOLWSD_VERSION_HASH "\"");
-
- std::ostringstream oss;
- response.write(oss);
- const std::string header = oss.str();
- LOG_TRC("#" << socket->getFD() << ": Sending file [" << path << "]: " << header);
- socket->send(header);
-
- std::ifstream file(path, std::ios::binary);
- bool flush = true;
- do
- {
- char buf[bufferSize];
- file.read(buf, sizeof(buf));
- const int size = file.gcount();
- if (size > 0)
- socket->send(buf, size, flush);
- else
- break;
- flush = false;
- }
- while (file);
- }
+ void sendFile(const std::shared_ptr<StreamSocket>& socket, const std::string& path,
+ Poco::Net::HTTPResponse& response, bool noCache = false);
inline void sendFile(const std::shared_ptr<StreamSocket>& socket, const std::string& path,
- const std::string& mediaType)
+ const std::string& mediaType, bool noCache = false)
{
Poco::Net::HTTPResponse response;
response.setContentType(mediaType);
- sendFile(socket, path, response);
+ sendFile(socket, path, response, noCache);
}
};
diff --git a/wsd/FileServer.cpp b/wsd/FileServer.cpp
index 2189205..bba77d5 100644
--- a/wsd/FileServer.cpp
+++ b/wsd/FileServer.cpp
@@ -197,7 +197,7 @@ void FileServerRequestHandler::handleRequest(const HTTPRequest& request, Poco::M
}
response.setContentType(mimeType);
- HttpHelper::sendFile(socket, filepath, response);
+ HttpHelper::sendFile(socket, filepath, response, noCache);
}
}
catch (const Poco::Net::NotAuthenticatedException& exc)
commit d19b6eb3512931bbb2dc45004ca75aef682d9709
Author: Michael Meeks <michael.meeks at collabora.com>
Date: Wed Mar 15 16:39:13 2017 +0000
Move memstats & cpustats into the main polling thread.
We can calculate the timeout ourselves easily and add it to the
polling loop simplifying life.
Also ensure we never send messages to a non-authenticated thread.
diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp
index e4b616b..a3b7035 100644
--- a/wsd/Admin.cpp
+++ b/wsd/Admin.cpp
@@ -32,7 +32,6 @@
#include "FileServer.hpp"
#include "IoUtil.hpp"
#include "Protocol.hpp"
-#include "LOOLWebSocket.hpp" // FIXME: remove.
#include "LOOLWSD.hpp"
#include "Log.hpp"
#include "Storage.hpp"
@@ -87,16 +86,18 @@ void AdminRequestHandler::handleMessage(bool /* fin */, WSOpCode /* code */, std
}
else
{
- sendTextFrame("InvalidAuthToken");
+ sendFrame("InvalidAuthToken");
LOG_TRC("Invalid auth token");
+ shutdown();
return;
}
}
if (!_isAuthenticated)
{
- sendTextFrame("NotAuthenticated");
+ sendFrame("NotAuthenticated");
LOG_TRC("Not authenticated");
+ shutdown();
return;
}
else if (tokens[0] == "documents" ||
@@ -229,7 +230,11 @@ AdminRequestHandler::AdminRequestHandler(Admin* adminManager,
void AdminRequestHandler::sendTextFrame(const std::string& message)
{
UnitWSD::get().onAdminQueryMessage(message);
- sendFrame(message);
+ std::cerr << "Admin: send text frame '" << message << "'\n";
+ if (_isAuthenticated)
+ sendFrame(message);
+ else
+ LOG_TRC("Skip sending message to non-authenticated client: '" << message << "'");
}
bool AdminRequestHandler::handleInitialRequest(
@@ -273,7 +278,10 @@ bool AdminRequestHandler::handleInitialRequest(
Admin::Admin() :
SocketPoll("admin"),
_model(AdminModel()),
- _forKitPid(-1)
+ _forKitPid(-1),
+ _lastTotalMemory(0),
+ _memStatsTaskIntervalMs(5000),
+ _cpuStatsTaskIntervalMs(5000)
{
LOG_INF("Admin ctor.");
@@ -281,20 +289,54 @@ Admin::Admin() :
const auto totalMem = getTotalMemoryUsage();
LOG_TRC("Total memory used: " << totalMem);
_model.addMemStats(totalMem);
-
- _memStatsTask = new MemoryStatsTask(this);
- _memStatsTimer.schedule(_memStatsTask, _memStatsTaskInterval, _memStatsTaskInterval);
-
- _cpuStatsTask = new CpuStats(this);
- _cpuStatsTimer.schedule(_cpuStatsTask, _cpuStatsTaskInterval, _cpuStatsTaskInterval);
}
Admin::~Admin()
{
LOG_INF("~Admin dtor.");
+}
+
+void Admin::pollingThread()
+{
+ std::chrono::steady_clock::time_point lastCPU, lastMem;
+
+ lastCPU = std::chrono::steady_clock::now();
+ lastMem = lastCPU;
+
+ while (!_stop && !TerminationFlag && !ShutdownRequestFlag)
+ {
+ std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
+ int cpuWait = _cpuStatsTaskIntervalMs -
+ std::chrono::duration_cast<std::chrono::milliseconds>(now - lastCPU).count();
+ if (cpuWait < 0)
+ {
+ // TODO: implement me ...
+ lastCPU = now;
+ cpuWait += _cpuStatsTaskIntervalMs;
+ }
+ int memWait = _memStatsTaskIntervalMs -
+ std::chrono::duration_cast<std::chrono::milliseconds>(now - lastCPU).count();
+ if (memWait < 0)
+ {
+ std::unique_lock<std::mutex> modelLock(getLock());
+ const auto totalMem = getTotalMemoryUsage();
+ if (totalMem != _lastTotalMemory)
+ {
+ LOG_TRC("Total memory used: " << totalMem);
+ _lastTotalMemory = totalMem;
+ }
+
+ _model.addMemStats(totalMem);
- _memStatsTask->cancel();
- _cpuStatsTask->cancel();
+ lastMem = now;
+ memWait += _memStatsTaskIntervalMs;
+ }
+
+ // Handle websockets & other work.
+ int timeout = std::min(cpuWait, memWait);
+ LOG_TRC("Admin poll for " << timeout << "ms");
+ poll(timeout);
+ }
}
void Admin::addDoc(const std::string& docKey, Poco::Process::PID pid, const std::string& filename, const std::string& sessionId)
@@ -316,43 +358,18 @@ void Admin::rmDoc(const std::string& docKey)
_model.removeDocument(docKey);
}
-void MemoryStatsTask::run()
-{
- std::unique_lock<std::mutex> modelLock(_admin->getLock());
- const auto totalMem = _admin->getTotalMemoryUsage();
-
- if (totalMem != _lastTotalMemory)
- {
- LOG_TRC("Total memory used: " << totalMem);
- _lastTotalMemory = totalMem;
- }
-
- _admin->getModel().addMemStats(totalMem);
-}
-
-void CpuStats::run()
-{
- //TODO: Implement me
- //std::unique_lock<std::mutex> modelLock(_admin->getLock());
- //model.addCpuStats(totalMem);
-}
-
void Admin::rescheduleMemTimer(unsigned interval)
{
- _memStatsTask->cancel();
- _memStatsTaskInterval = interval;
- _memStatsTask = new MemoryStatsTask(this);
- _memStatsTimer.schedule(_memStatsTask, _memStatsTaskInterval, _memStatsTaskInterval);
+ _memStatsTaskIntervalMs = interval;
LOG_INF("Memory stats interval changed - New interval: " << interval);
+ wakeup();
}
void Admin::rescheduleCpuTimer(unsigned interval)
{
- _cpuStatsTask->cancel();
- _cpuStatsTaskInterval = interval;
- _cpuStatsTask = new CpuStats(this);
- _cpuStatsTimer.schedule(_cpuStatsTask, _cpuStatsTaskInterval, _cpuStatsTaskInterval);
+ _cpuStatsTaskIntervalMs = interval;
LOG_INF("CPU stats interval changed - New interval: " << interval);
+ wakeup();
}
unsigned Admin::getTotalMemoryUsage()
@@ -373,12 +390,12 @@ unsigned Admin::getTotalMemoryUsage()
unsigned Admin::getMemStatsInterval()
{
- return _memStatsTaskInterval;
+ return _memStatsTaskIntervalMs;
}
unsigned Admin::getCpuStatsInterval()
{
- return _cpuStatsTaskInterval;
+ return _cpuStatsTaskIntervalMs;
}
AdminModel& Admin::getModel()
diff --git a/wsd/Admin.hpp b/wsd/Admin.hpp
index 2b8d4f0..da51cdc 100644
--- a/wsd/Admin.hpp
+++ b/wsd/Admin.hpp
@@ -22,7 +22,6 @@
#include "AdminModel.hpp"
#include "Log.hpp"
-#include <LOOLWebSocket.hpp>
#include "net/WebSocketHandler.hpp"
@@ -76,6 +75,9 @@ public:
startThread();
}
+ /// Custom poll thread function
+ void pollingThread() override;
+
unsigned getTotalMemoryUsage();
/// Update the Admin Model.
@@ -114,58 +116,10 @@ private:
AdminModel _model;
std::mutex _modelMutex;
int _forKitPid;
-
- Poco::Util::Timer _memStatsTimer;
- Poco::AutoPtr<MemoryStatsTask> _memStatsTask;
- unsigned _memStatsTaskInterval = 5000;
-
- Poco::Util::Timer _cpuStatsTimer;
- Poco::Util::TimerTask::Ptr _cpuStatsTask;
- unsigned _cpuStatsTaskInterval = 5000;
-};
-
-/// Memory statistics.
-class MemoryStatsTask : public Poco::Util::TimerTask
-{
-public:
- MemoryStatsTask(Admin* admin)
- : _admin(admin),
- _lastTotalMemory(0)
- {
- LOG_DBG("Memory stat ctor");
- }
-
- ~MemoryStatsTask()
- {
- LOG_DBG("Memory stat dtor");
- }
-
- long getLastTotalMemory() { return _lastTotalMemory; }
-
- void run() override;
-
-private:
- Admin* _admin;
long _lastTotalMemory;
-};
-
-/// CPU statistics.
-class CpuStats : public Poco::Util::TimerTask
-{
-public:
- CpuStats(Admin* /*admin*/)
- {
- LOG_DBG("Cpu stat ctor");
- }
- ~CpuStats()
- {
- LOG_DBG("Cpu stat dtor");
- }
-
- void run() override;
-
-private:
+ std::atomic<int> _memStatsTaskIntervalMs;
+ std::atomic<int> _cpuStatsTaskIntervalMs;
};
#endif
diff --git a/wsd/Exceptions.hpp b/wsd/Exceptions.hpp
index b05d98d..b97263e 100644
--- a/wsd/Exceptions.hpp
+++ b/wsd/Exceptions.hpp
@@ -58,15 +58,6 @@ public:
using LoolException::LoolException;
};
-/// An generic error-message exception meant to
-/// propagate via a valid LOOLWebSocket to the client.
-/// The contents of what() will be displayed on screen.
-class WebSocketErrorMessageException : public LoolException
-{
-public:
- using LoolException::LoolException;
-};
-
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 0089723f693a8d9549b9abb7236c2f5bae4d633a
Author: Michael Meeks <michael.meeks at collabora.com>
Date: Wed Mar 15 16:25:29 2017 +0000
Admin: review error handling on auth. failure.
diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp
index d3e684b..e4b616b 100644
--- a/wsd/Admin.cpp
+++ b/wsd/Admin.cpp
@@ -232,10 +232,10 @@ void AdminRequestHandler::sendTextFrame(const std::string& message)
sendFrame(message);
}
-bool AdminRequestHandler::handleInitialRequest(const std::weak_ptr<StreamSocket> &socketWeak,
- const Poco::Net::HTTPRequest& request)
+bool AdminRequestHandler::handleInitialRequest(
+ const std::weak_ptr<StreamSocket> &socketWeak,
+ const Poco::Net::HTTPRequest& request)
{
- HTTPResponse response;
auto socket = socketWeak.lock();
// Different session id pool for admin sessions (?)
@@ -260,28 +260,12 @@ bool AdminRequestHandler::handleInitialRequest(const std::weak_ptr<StreamSocket>
return true;
}
-// FIXME: ... should we move ourselves to an Admin poll [!?] ...
-// Probably [!] ... and use this termination thing ? ...
-// Perhaps that should be the 'Admin' instance / sub-class etc.
-// FIXME: have name 'admin' etc.
-// []() { return TerminationFlag.load(); });
-#if 0
- catch(const Poco::Net::NotAuthenticatedException& exc)
- {
- LOG_INF("Admin::NotAuthenticated");
- response.set("WWW-Authenticate", "Basic realm=\"online\"");
- response.setStatusAndReason(HTTPResponse::HTTP_UNAUTHORIZED);
- response.setContentLength(0);
- socket->send(response);
- }
- catch (const std::exception& exc)
- {
- LOG_INF("Admin::handleRequest: Exception: " << exc.what());
- response.setStatusAndReason(HTTPResponse::HTTP_BAD_REQUEST);
- response.setContentLength(0);
- socket->send(response);
- }
-#endif
+ HTTPResponse response;
+ response.setStatusAndReason(HTTPResponse::HTTP_BAD_REQUEST);
+ response.setContentLength(0);
+ LOG_INF("Admin::handleInitialRequest bad request");
+ socket->send(response);
+
return false;
}
diff --git a/wsd/Admin.hpp b/wsd/Admin.hpp
index 4332e27..2b8d4f0 100644
--- a/wsd/Admin.hpp
+++ b/wsd/Admin.hpp
@@ -51,7 +51,6 @@ private:
private:
Admin* _admin;
-// std::shared_ptr<LOOLWebSocket> _adminWs; FIXME - this is us now !
int _sessionId;
bool _isAuthenticated;
};
commit 909b5f8ac3aa57c4bc786fa03c5d999805e6d7ca
Author: Michael Meeks <michael.meeks at collabora.com>
Date: Wed Mar 15 16:13:13 2017 +0000
Admin: should be its own socket-poll goodness.
diff --git a/net/Socket.hpp b/net/Socket.hpp
index 1d67bb6..9460c45 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -412,7 +412,7 @@ public:
wakeup();
}
- void dumpState(std::ostream& os);
+ virtual void dumpState(std::ostream& os);
/// Removes a socket from this poller.
/// NB. this must be called from the socket poll that
diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp
index 6f9f7cb..d3e684b 100644
--- a/wsd/Admin.cpp
+++ b/wsd/Admin.cpp
@@ -232,7 +232,7 @@ void AdminRequestHandler::sendTextFrame(const std::string& message)
sendFrame(message);
}
-void AdminRequestHandler::handleInitialRequest(const std::weak_ptr<StreamSocket> &socketWeak,
+bool AdminRequestHandler::handleInitialRequest(const std::weak_ptr<StreamSocket> &socketWeak,
const Poco::Net::HTTPRequest& request)
{
HTTPResponse response;
@@ -257,6 +257,7 @@ void AdminRequestHandler::handleInitialRequest(const std::weak_ptr<StreamSocket>
handler->_sessionId = sessionId;
model.subscribe(sessionId, handler);
}
+ return true;
}
// FIXME: ... should we move ourselves to an Admin poll [!?] ...
@@ -281,10 +282,12 @@ void AdminRequestHandler::handleInitialRequest(const std::weak_ptr<StreamSocket>
socket->send(response);
}
#endif
+ return false;
}
/// An admin command processor.
Admin::Admin() :
+ SocketPoll("admin"),
_model(AdminModel()),
_forKitPid(-1)
{
@@ -411,4 +414,10 @@ void Admin::updateMemoryDirty(const std::string& docKey, int dirty)
_model.updateMemoryDirty(docKey, dirty);
}
+void Admin::dumpState(std::ostream& os)
+{
+ // FIXME: be more helpful ...
+ SocketPoll::dumpState(os);
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/wsd/Admin.hpp b/wsd/Admin.hpp
index c15cbbb..4332e27 100644
--- a/wsd/Admin.hpp
+++ b/wsd/Admin.hpp
@@ -36,7 +36,9 @@ public:
const std::weak_ptr<StreamSocket>& socket,
const Poco::Net::HTTPRequest& request);
- static void handleInitialRequest(const std::weak_ptr<StreamSocket> &socket,
+ /// Handle the initial Admin WS upgrade request.
+ /// @returns true if we should give this socket to the Admin poll.
+ static bool handleInitialRequest(const std::weak_ptr<StreamSocket> &socket,
const Poco::Net::HTTPRequest& request);
private:
@@ -57,7 +59,7 @@ private:
class MemoryStatsTask;
/// An admin command processor.
-class Admin
+class Admin : public SocketPoll
{
Admin();
public:
@@ -69,6 +71,12 @@ public:
return admin;
}
+ void start()
+ {
+ // FIXME: not if admin console is not enabled ?
+ startThread();
+ }
+
unsigned getTotalMemoryUsage();
/// Update the Admin Model.
@@ -101,6 +109,8 @@ public:
void updateLastActivityTime(const std::string& docKey);
void updateMemoryDirty(const std::string& docKey, int dirty);
+ void dumpState(std::ostream& os) override;
+
private:
AdminModel _model;
std::mutex _modelMutex;
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 3aee14d..81608b6 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -1808,8 +1808,12 @@ private:
else if (reqPathSegs.size() >= 2 && reqPathSegs[0] == "lool" && reqPathSegs[1] == "adminws")
{
LOG_ERR("Admin request: " << request.getURI());
- AdminRequestHandler::handleInitialRequest(_socket, request);
-
+ if (AdminRequestHandler::handleInitialRequest(_socket, request))
+ {
+ // Hand the socket over to the Admin poll.
+ WebServerPoll.releaseSocket(socket);
+ Admin::instance().insertNewSocket(socket);
+ }
}
// Client post and websocket connections
else if ((request.getMethod() == HTTPRequest::HTTP_GET ||
@@ -2336,6 +2340,7 @@ public:
_acceptPoll.insertNewSocket(findServerPort(port));
_acceptPoll.startThread();
WebServerPoll.startThread();
+ Admin::instance().start();
}
void stop()
@@ -2364,6 +2369,9 @@ public:
os << "Prisoner poll:\n";
PrisonerPoll.dumpState(os);
+ os << "Admin poll:\n";
+ Admin::instance().dumpState(os);
+
os << "Document Broker polls "
<< "[ " << DocBrokers.size() << " ]:\n";
for (auto &i : DocBrokers)
commit e1f576bdb38f9cf63f1c74cde55afdd25d7b96ed
Author: Michael Meeks <michael.meeks at collabora.com>
Date: Wed Mar 15 14:58:55 2017 +0000
Switch to using websocket here.
diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp
index 07723df..6f9f7cb 100644
--- a/wsd/Admin.cpp
+++ b/wsd/Admin.cpp
@@ -54,14 +54,19 @@ using Poco::Net::HTTPServerRequest;
using Poco::Net::HTTPServerResponse;
using Poco::Util::Application;
-bool AdminRequestHandler::adminCommandHandler(const std::vector<char>& payload)
+ /// Process incoming websocket messages
+void AdminRequestHandler::handleMessage(bool /* fin */, WSOpCode /* code */, std::vector<char> &payload)
{
+ // FIXME: check fin, code etc.
const std::string firstLine = getFirstLine(payload.data(), payload.size());
StringTokenizer tokens(firstLine, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
- LOG_TRC("Recv: " << firstLine);
+ LOG_TRC("Recv: " << firstLine << " tokens " << tokens.count());
if (tokens.count() < 1)
- return false;
+ {
+ LOG_TRC("too few tokens");
+ return;
+ }
std::unique_lock<std::mutex> modelLock(_admin->getLock());
AdminModel& model = _admin->getModel();
@@ -83,14 +88,16 @@ bool AdminRequestHandler::adminCommandHandler(const std::vector<char>& payload)
else
{
sendTextFrame("InvalidAuthToken");
- return false;
+ LOG_TRC("Invalid auth token");
+ return;
}
}
if (!_isAuthenticated)
{
sendTextFrame("NotAuthenticated");
- return false;
+ LOG_TRC("Not authenticated");
+ return;
}
else if (tokens[0] == "documents" ||
tokens[0] == "active_users_count" ||
@@ -154,7 +161,7 @@ bool AdminRequestHandler::adminCommandHandler(const std::vector<char>& payload)
LOG_INF("Shutdown requested by admin.");
ShutdownRequestFlag = true;
SocketPoll::wakeupWorld();
- return false;
+ return;
}
else if (tokens[0] == "set" && tokens.count() > 1)
{
@@ -170,7 +177,7 @@ bool AdminRequestHandler::adminCommandHandler(const std::vector<char>& payload)
{
LOG_WRN("Invalid setting value: " << setting[1] <<
" for " << setting[0]);
- return false;
+ return;
}
if (setting[0] == "mem_stats_size")
@@ -207,36 +214,13 @@ bool AdminRequestHandler::adminCommandHandler(const std::vector<char>& payload)
}
}
}
-
- return true;
-}
-
-/// Handle admin requests.
-void AdminRequestHandler::handleWSRequests(HTTPServerRequest& request, HTTPServerResponse& response, int sessionId)
-{
- _adminWs = std::make_shared<LOOLWebSocket>(request, response);
-
- {
- std::unique_lock<std::mutex> modelLock(_admin->getLock());
- // Subscribe the websocket of any AdminModel updates
- AdminModel& model = _admin->getModel();
- _sessionId = sessionId;
- model.subscribe(_sessionId, _adminWs);
- }
-
- IoUtil::SocketProcessor(_adminWs, "admin",
- [this](const std::vector<char>& payload)
- {
- return adminCommandHandler(payload);
- },
- []() { },
- []() { return TerminationFlag.load(); });
-
- LOG_DBG("Finishing Admin Session " << Util::encodeId(sessionId));
}
-AdminRequestHandler::AdminRequestHandler(Admin* adminManager)
- : _admin(adminManager),
+AdminRequestHandler::AdminRequestHandler(Admin* adminManager,
+ const std::weak_ptr<StreamSocket>& socket,
+ const Poco::Net::HTTPRequest& request)
+ : WebSocketHandler(socket, request),
+ _admin(adminManager),
_sessionId(0),
_isAuthenticated(false)
{
@@ -245,7 +229,7 @@ AdminRequestHandler::AdminRequestHandler(Admin* adminManager)
void AdminRequestHandler::sendTextFrame(const std::string& message)
{
UnitWSD::get().onAdminQueryMessage(message);
- _adminWs->sendFrame(message.data(), message.size());
+ sendFrame(message);
}
void AdminRequestHandler::handleInitialRequest(const std::weak_ptr<StreamSocket> &socketWeak,
@@ -255,21 +239,32 @@ void AdminRequestHandler::handleInitialRequest(const std::weak_ptr<StreamSocket>
auto socket = socketWeak.lock();
// Different session id pool for admin sessions (?)
-// const auto sessionId = Util::decodeId(LOOLWSD::GenSessionId());
-
- try
- {
- std::string requestURI = request.getURI();
- StringTokenizer pathTokens(requestURI, "/", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
+ const auto sessionId = Util::decodeId(LOOLWSD::GenSessionId());
- if (request.find("Upgrade") != request.end() && Poco::icompare(request["Upgrade"], "websocket") == 0)
- {
- // First Upgrade.
- WebSocketHandler ws(socketWeak, request);
+ std::string requestURI = request.getURI();
+ StringTokenizer pathTokens(requestURI, "/", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
-// handleWSRequests(request, response, sessionId);
+ if (request.find("Upgrade") != request.end() && Poco::icompare(request["Upgrade"], "websocket") == 0)
+ {
+ Admin &admin = Admin::instance();
+ auto handler = std::make_shared<AdminRequestHandler>(&admin, socketWeak, request);
+ socket->setHandler(handler);
+
+ { // FIXME: weird locking around subscribe ...
+ std::unique_lock<std::mutex> modelLock(admin.getLock());
+ // Subscribe the websocket of any AdminModel updates
+ AdminModel& model = admin.getModel();
+ handler->_sessionId = sessionId;
+ model.subscribe(sessionId, handler);
}
}
+
+// FIXME: ... should we move ourselves to an Admin poll [!?] ...
+// Probably [!] ... and use this termination thing ? ...
+// Perhaps that should be the 'Admin' instance / sub-class etc.
+// FIXME: have name 'admin' etc.
+// []() { return TerminationFlag.load(); });
+#if 0
catch(const Poco::Net::NotAuthenticatedException& exc)
{
LOG_INF("Admin::NotAuthenticated");
@@ -285,6 +280,7 @@ void AdminRequestHandler::handleInitialRequest(const std::weak_ptr<StreamSocket>
response.setContentLength(0);
socket->send(response);
}
+#endif
}
/// An admin command processor.
diff --git a/wsd/Admin.hpp b/wsd/Admin.hpp
index 82b5a5e..c15cbbb 100644
--- a/wsd/Admin.hpp
+++ b/wsd/Admin.hpp
@@ -24,14 +24,17 @@
#include "Log.hpp"
#include <LOOLWebSocket.hpp>
+#include "net/WebSocketHandler.hpp"
+
class Admin;
-class StreamSocket;
-/// Admin requests over HTTP(S) handler.
-class AdminRequestHandler /// public Poco::Net::HTTPRequestHandler
+/// Handle admin client's Websocket requests & replies.
+class AdminRequestHandler : public WebSocketHandler
{
public:
- AdminRequestHandler(Admin* adminManager);
+ AdminRequestHandler(Admin* adminManager,
+ const std::weak_ptr<StreamSocket>& socket,
+ const Poco::Net::HTTPRequest& request);
static void handleInitialRequest(const std::weak_ptr<StreamSocket> &socket,
const Poco::Net::HTTPRequest& request);
@@ -41,11 +44,12 @@ private:
void sendTextFrame(const std::string& message);
- bool adminCommandHandler(const std::vector<char>& payload);
+ /// Process incoming websocket messages
+ void handleMessage(bool fin, WSOpCode code, std::vector<char> &data);
private:
Admin* _admin;
- std::shared_ptr<LOOLWebSocket> _adminWs;
+// std::shared_ptr<LOOLWebSocket> _adminWs; FIXME - this is us now !
int _sessionId;
bool _isAuthenticated;
};
@@ -55,6 +59,7 @@ class MemoryStatsTask;
/// An admin command processor.
class Admin
{
+ Admin();
public:
virtual ~Admin();
@@ -91,20 +96,12 @@ public:
void rescheduleCpuTimer(unsigned interval);
- static AdminRequestHandler* createRequestHandler()
- {
- return new AdminRequestHandler(&instance());
- }
-
std::unique_lock<std::mutex> getLock() { return std::unique_lock<std::mutex>(_modelMutex); }
void updateLastActivityTime(const std::string& docKey);
void updateMemoryDirty(const std::string& docKey, int dirty);
private:
- Admin();
-
-private:
AdminModel _model;
std::mutex _modelMutex;
int _forKitPid;
diff --git a/wsd/AdminModel.cpp b/wsd/AdminModel.cpp
index 3b81ff3..c23641c 100644
--- a/wsd/AdminModel.cpp
+++ b/wsd/AdminModel.cpp
@@ -21,7 +21,7 @@
#include <Poco/URI.h>
#include "Protocol.hpp"
-#include <LOOLWebSocket.hpp>
+#include "net/WebSocketHandler.hpp"
#include "Log.hpp"
#include "Unit.hpp"
#include "Util.hpp"
@@ -70,7 +70,7 @@ bool Subscriber::notify(const std::string& message)
try
{
UnitWSD::get().onAdminNotifyMessage(message);
- webSocket->sendFrame(message.data(), message.length());
+ webSocket->sendFrame(message);
return true;
}
catch (const std::exception& ex)
@@ -156,7 +156,7 @@ unsigned AdminModel::getKitsMemoryUsage()
return totalMem;
}
-void AdminModel::subscribe(int sessionId, std::shared_ptr<LOOLWebSocket>& ws)
+void AdminModel::subscribe(int sessionId, const std::weak_ptr<WebSocketHandler>& ws)
{
const auto ret = _subscribers.emplace(sessionId, Subscriber(sessionId, ws));
if (!ret.second)
diff --git a/wsd/AdminModel.hpp b/wsd/AdminModel.hpp
index 8bfb719..8250687 100644
--- a/wsd/AdminModel.hpp
+++ b/wsd/AdminModel.hpp
@@ -17,7 +17,7 @@
#include <Poco/Process.h>
#include "Log.hpp"
-#include <LOOLWebSocket.hpp>
+#include "net/WebSocketHandler.hpp"
#include "Util.hpp"
/// A client view in Admin controller.
@@ -98,7 +98,7 @@ private:
class Subscriber
{
public:
- Subscriber(int sessionId, std::shared_ptr<LOOLWebSocket>& ws)
+ Subscriber(int sessionId, const std::weak_ptr<WebSocketHandler>& ws)
: _sessionId(sessionId),
_ws(ws),
_start(std::time(nullptr))
@@ -125,8 +125,8 @@ private:
/// Admin session Id
int _sessionId;
- /// LOOLWebSocket to use to send messages to session
- std::weak_ptr<LOOLWebSocket> _ws;
+ /// The underlying AdminRequestHandler
+ std::weak_ptr<WebSocketHandler> _ws;
std::set<std::string> _subscriptions;
@@ -153,7 +153,7 @@ public:
/// Returns memory consumed by all active loolkit processes
unsigned getKitsMemoryUsage();
- void subscribe(int sessionId, std::shared_ptr<LOOLWebSocket>& ws);
+ void subscribe(int sessionId, const std::weak_ptr<WebSocketHandler>& ws);
void subscribe(int sessionId, const std::string& command);
void unsubscribe(int sessionId, const std::string& command);
commit d9980e3392f04ba8f764ca561a300e36f7a130e8
Author: Michael Meeks <michael.meeks at collabora.com>
Date: Wed Mar 15 14:40:24 2017 +0000
Adjust initial AdminRequestHandler entry point.
diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp
index 636c403..07723df 100644
--- a/wsd/Admin.cpp
+++ b/wsd/Admin.cpp
@@ -32,7 +32,7 @@
#include "FileServer.hpp"
#include "IoUtil.hpp"
#include "Protocol.hpp"
-#include "LOOLWebSocket.hpp"
+#include "LOOLWebSocket.hpp" // FIXME: remove.
#include "LOOLWSD.hpp"
#include "Log.hpp"
#include "Storage.hpp"
@@ -40,6 +40,9 @@
#include "Unit.hpp"
#include "Util.hpp"
+#include "net/Socket.hpp"
+#include "net/WebSocketHandler.hpp"
+
#include "common/SigUtil.hpp"
using namespace LOOLProtocol;
@@ -245,14 +248,14 @@ void AdminRequestHandler::sendTextFrame(const std::string& message)
_adminWs->sendFrame(message.data(), message.size());
}
-void AdminRequestHandler::handleRequest(HTTPServerRequest& request, HTTPServerResponse& response)
+void AdminRequestHandler::handleInitialRequest(const std::weak_ptr<StreamSocket> &socketWeak,
+ const Poco::Net::HTTPRequest& request)
{
- // Different session id pool for admin sessions (?)
- const auto sessionId = Util::decodeId(LOOLWSD::GenSessionId());
-
- Util::setThreadName("admin_ws_" + std::to_string(sessionId));
+ HTTPResponse response;
+ auto socket = socketWeak.lock();
- LOG_DBG("Thread started.");
+ // Different session id pool for admin sessions (?)
+// const auto sessionId = Util::decodeId(LOOLWSD::GenSessionId());
try
{
@@ -261,7 +264,10 @@ void AdminRequestHandler::handleRequest(HTTPServerRequest& request, HTTPServerRe
if (request.find("Upgrade") != request.end() && Poco::icompare(request["Upgrade"], "websocket") == 0)
{
- handleWSRequests(request, response, sessionId);
+ // First Upgrade.
+ WebSocketHandler ws(socketWeak, request);
+
+// handleWSRequests(request, response, sessionId);
}
}
catch(const Poco::Net::NotAuthenticatedException& exc)
@@ -270,17 +276,15 @@ void AdminRequestHandler::handleRequest(HTTPServerRequest& request, HTTPServerRe
response.set("WWW-Authenticate", "Basic realm=\"online\"");
response.setStatusAndReason(HTTPResponse::HTTP_UNAUTHORIZED);
response.setContentLength(0);
- response.send();
+ socket->send(response);
}
catch (const std::exception& exc)
{
LOG_INF("Admin::handleRequest: Exception: " << exc.what());
response.setStatusAndReason(HTTPResponse::HTTP_BAD_REQUEST);
response.setContentLength(0);
- response.send();
+ socket->send(response);
}
-
- LOG_DBG("Thread finished.");
}
/// An admin command processor.
diff --git a/wsd/Admin.hpp b/wsd/Admin.hpp
index f1cbe86..82b5a5e 100644
--- a/wsd/Admin.hpp
+++ b/wsd/Admin.hpp
@@ -25,14 +25,16 @@
#include <LOOLWebSocket.hpp>
class Admin;
+class StreamSocket;
/// Admin requests over HTTP(S) handler.
-class AdminRequestHandler : public Poco::Net::HTTPRequestHandler
+class AdminRequestHandler /// public Poco::Net::HTTPRequestHandler
{
public:
AdminRequestHandler(Admin* adminManager);
- void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) override;
+ static void handleInitialRequest(const std::weak_ptr<StreamSocket> &socket,
+ const Poco::Net::HTTPRequest& request);
private:
void handleWSRequests(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response, int sessionId);
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index e141bb9..3aee14d 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -1807,7 +1807,9 @@ private:
// Admin connections
else if (reqPathSegs.size() >= 2 && reqPathSegs[0] == "lool" && reqPathSegs[1] == "adminws")
{
- handleAdminRequest(request);
+ LOG_ERR("Admin request: " << request.getURI());
+ AdminRequestHandler::handleInitialRequest(_socket, request);
+
}
// Client post and websocket connections
else if ((request.getMethod() == HTTPRequest::HTTP_GET ||
@@ -1881,12 +1883,6 @@ private:
socket->shutdown();
}
- void handleAdminRequest(const Poco::Net::HTTPRequest& request)
- {
- LOG_ERR("Admin request: " << request.getURI());
- // requestHandler = Admin::createRequestHandler();
- }
-
void handleRootRequest(const Poco::Net::HTTPRequest& request)
{
LOG_DBG("HTTP request: " << request.getURI());
More information about the Libreoffice-commits
mailing list