[Libreoffice-commits] online.git: 3 commits - loolwsd/AdminModel.cpp loolwsd/AdminModel.hpp loolwsd/Auth.cpp loolwsd/Auth.hpp loolwsd/DocumentBroker.cpp loolwsd/Makefile.am loolwsd/Storage.cpp loolwsd/Storage.hpp
Pranav Kant
pranavk at collabora.com
Thu Mar 31 07:32:31 UTC 2016
loolwsd/AdminModel.cpp | 361 ++++++++++++++++++++++++++++++++++++++++++
loolwsd/AdminModel.hpp | 385 +++------------------------------------------
loolwsd/Auth.cpp | 211 ++++++++++++++++++++++++
loolwsd/Auth.hpp | 187 ---------------------
loolwsd/DocumentBroker.cpp | 2
loolwsd/Makefile.am | 97 ++++++++---
loolwsd/Storage.cpp | 275 ++++++++++++++++++++++++++++++++
loolwsd/Storage.hpp | 245 +---------------------------
8 files changed, 972 insertions(+), 791 deletions(-)
New commits:
commit 4ae077200cb1090b109125d4534dfbf5282a9740
Author: Pranav Kant <pranavk at collabora.com>
Date: Thu Mar 31 12:55:35 2016 +0530
loolwsd: Separate AdminModel header and implementation
Change-Id: Iddf107aa7985988deba800030e75243a831a7532
diff --git a/loolwsd/AdminModel.cpp b/loolwsd/AdminModel.cpp
new file mode 100644
index 0000000..644fa9c
--- /dev/null
+++ b/loolwsd/AdminModel.cpp
@@ -0,0 +1,361 @@
+/* -*- 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/.
+ */
+
+#include <memory>
+#include <set>
+#include <sstream>
+#include <string>
+
+#include <Poco/Net/WebSocket.h>
+#include <Poco/Process.h>
+#include <Poco/StringTokenizer.h>
+
+#include "AdminModel.hpp"
+#include "Util.hpp"
+
+using Poco::StringTokenizer;
+
+/////////////////
+// Document Impl
+////////////////
+void Document::addView(int nSessionId)
+{
+ const auto ret = _views.emplace(nSessionId, View(nSessionId));
+ if (!ret.second)
+ {
+ Log::warn() << "View with SessionID [" + std::to_string(nSessionId) + "] already exists." << Log::end;
+ }
+ else
+ {
+ _nActiveViews++;
+ }
+}
+
+void Document::removeView(int nSessionId)
+{
+ auto it = _views.find(nSessionId);
+ if (it != _views.end())
+ {
+ it->second.expire();
+ _nActiveViews--;
+ }
+}
+
+///////////////////
+// Subscriber Impl
+//////////////////
+bool Subscriber::notify(const std::string& message)
+{
+ StringTokenizer tokens(message, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
+
+ if (_subscriptions.find(tokens[0]) == _subscriptions.end())
+ return true;
+
+ auto webSocket = _ws.lock();
+ if (webSocket)
+ {
+ webSocket->sendFrame(message.data(), message.length());
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool Subscriber::subscribe(const std::string& command)
+{
+ auto ret = _subscriptions.insert(command);
+ return ret.second;
+}
+
+void Subscriber::unsubscribe(const std::string& command)
+{
+ _subscriptions.erase(command);
+}
+
+///////////////////
+// AdminModel Impl
+//////////////////
+
+void AdminModel::update(const std::string& data)
+{
+ StringTokenizer tokens(data, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
+
+ Log::info("AdminModel Recv: " + data);
+
+ if (tokens[0] == "document")
+ {
+ addDocument(std::stoi(tokens[1]), tokens[2]);
+ unsigned mem = Util::getMemoryUsage(std::stoi(tokens[1]));
+ std::string response = data + std::to_string(mem);
+ notify(response);
+ return;
+ }
+ else if (tokens[0] == "addview")
+ {
+ auto it = _documents.find(std::stoi(tokens[1]));
+ if (it != _documents.end())
+ {
+ const unsigned nSessionId = Util::decodeId(tokens[2]);
+ it->second.addView(nSessionId);
+ }
+ }
+ else if (tokens[0] == "rmview")
+ {
+ auto it = _documents.find(std::stoi(tokens[1]));
+ if (it != _documents.end())
+ {
+ const unsigned nSessionId = Util::decodeId(tokens[2]);
+ it->second.removeView(nSessionId);
+ }
+ }
+ else if (tokens[0] == "rmdoc")
+ {
+ removeDocument(std::stoi(tokens[1]));
+ }
+
+ notify(data);
+}
+
+std::string AdminModel::query(const std::string command)
+{
+ StringTokenizer tokens(command, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
+
+ if (tokens[0] == "documents")
+ {
+ return getDocuments();
+ }
+ else if (tokens[0] == "active_users_count")
+ {
+ return std::to_string(getTotalActiveViews());
+ }
+ else if (tokens[0] == "active_docs_count")
+ {
+ return std::to_string(_documents.size());
+ }
+ else if (tokens[0] == "mem_stats")
+ {
+ return getMemStats();
+ }
+ else if (tokens[0] == "mem_stats_size")
+ {
+ return std::to_string(_memStatsSize);
+ }
+ else if (tokens[0] == "cpu_stats")
+ {
+ return getCpuStats();
+ }
+ else if (tokens[0] == "cpu_stats_size")
+ {
+ return std::to_string(_cpuStatsSize);
+ }
+
+ return std::string("");
+}
+
+/// Returns memory consumed by all active loolkit processes
+unsigned AdminModel::getTotalMemoryUsage()
+{
+ unsigned totalMem = 0;
+ for (auto& it: _documents)
+ {
+ if (it.second.isExpired())
+ continue;
+
+ totalMem += Util::getMemoryUsage(it.second.getPid());
+ }
+
+ return totalMem;
+}
+
+void AdminModel::subscribe(int nSessionId, std::shared_ptr<Poco::Net::WebSocket>& ws)
+{
+ const auto ret = _subscribers.emplace(nSessionId, Subscriber(nSessionId, ws));
+ if (!ret.second)
+ {
+ Log::warn() << "Subscriber already exists" << Log::end;
+ }
+}
+
+void AdminModel::subscribe(int nSessionId, const std::string& command)
+{
+ auto subscriber = _subscribers.find(nSessionId);
+ if (subscriber == _subscribers.end() )
+ return;
+
+ subscriber->second.subscribe(command);
+}
+
+void AdminModel::unsubscribe(int nSessionId, const std::string& command)
+{
+ auto subscriber = _subscribers.find(nSessionId);
+ if (subscriber == _subscribers.end())
+ return;
+
+ subscriber->second.unsubscribe(command);
+}
+
+void AdminModel::addMemStats(unsigned memUsage)
+{
+ _memStats.push_back(memUsage);
+ if (_memStats.size() > _memStatsSize)
+ {
+ _memStats.pop_front();
+ }
+
+ std::ostringstream oss;
+ oss << "mem_stats "
+ << std::to_string(memUsage);
+ notify(oss.str());
+}
+
+void AdminModel::addCpuStats(unsigned cpuUsage)
+{
+ _cpuStats.push_back(cpuUsage);
+ if (_cpuStats.size() > _cpuStatsSize)
+ {
+ _cpuStats.pop_front();
+ }
+
+ std::ostringstream oss;
+ oss << "cpu_stats "
+ << std::to_string(cpuUsage);
+ notify(oss.str());
+}
+
+void AdminModel::setCpuStatsSize(unsigned size)
+{
+ int wasteValuesLen = _cpuStats.size() - size;
+ while (wasteValuesLen-- > 0)
+ {
+ _cpuStats.pop_front();
+ }
+ _cpuStatsSize = size;
+
+ std::ostringstream oss;
+ oss << "settings "
+ << "cpu_stats_size="
+ << std::to_string(_cpuStatsSize);
+ notify(oss.str());
+}
+
+void AdminModel::setMemStatsSize(unsigned size)
+{
+ int wasteValuesLen = _memStats.size() - size;
+ while (wasteValuesLen-- > 0)
+ {
+ _memStats.pop_front();
+ }
+ _memStatsSize = size;
+
+ std::ostringstream oss;
+ oss << "settings "
+ << "mem_stats_size="
+ << std::to_string(_memStatsSize);
+ notify(oss.str());
+}
+
+void AdminModel::notify(const std::string& message)
+{
+ auto it = std::begin(_subscribers);
+ while (it != std::end(_subscribers))
+ {
+ if (!it->second.notify(message))
+ {
+ it = _subscribers.erase(it);
+ }
+ else
+ {
+ it++;
+ }
+ }
+}
+
+void AdminModel::addDocument(Poco::Process::PID pid, std::string url)
+{
+ const auto ret = _documents.emplace(pid, Document(pid, url));
+ if (!ret.second)
+ {
+ Log::warn() << "Document with PID [" + std::to_string(pid) + "] already exists." << Log::end;
+ }
+}
+
+void AdminModel::removeDocument(Poco::Process::PID pid)
+{
+ auto it = _documents.find(pid);
+ if (it != _documents.end() && !it->second.isExpired())
+ {
+ // TODO: The idea is to only expire the document and keep the history
+ // of documents open and close, to be able to give a detailed summary
+ // to the admin console with views. For now, just remove the document.
+ it->second.expire();
+ _documents.erase(it);
+ }
+}
+
+std::string AdminModel::getMemStats()
+{
+ std::string response;
+ for (auto& i: _memStats)
+ {
+ response += std::to_string(i) + ",";
+ }
+
+ return response;
+}
+
+std::string AdminModel::getCpuStats()
+{
+ std::string response;
+ for (auto& i: _cpuStats)
+ {
+ response += std::to_string(i) + ",";
+ }
+
+ return response;
+}
+
+unsigned AdminModel::getTotalActiveViews()
+{
+ unsigned nTotalViews = 0;
+ for (auto& it: _documents)
+ {
+ if (it.second.isExpired())
+ continue;
+
+ nTotalViews += it.second.getActiveViews();
+ }
+
+ return nTotalViews;
+}
+
+std::string AdminModel::getDocuments()
+{
+ std::ostringstream oss;
+ for (auto& it: _documents)
+ {
+ if (it.second.isExpired())
+ continue;
+
+ std::string sPid = std::to_string(it.second.getPid());
+ std::string sUrl = it.second.getUrl();
+ std::string sViews = std::to_string(it.second.getActiveViews());
+ std::string sMem = std::to_string(Util::getMemoryUsage(it.second.getPid()));
+
+ oss << sPid << " "
+ << sUrl << " "
+ << sViews << " "
+ << sMem << " \n ";
+ }
+
+ return oss.str();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/loolwsd/AdminModel.hpp b/loolwsd/AdminModel.hpp
index af38c6d..444689b 100644
--- a/loolwsd/AdminModel.hpp
+++ b/loolwsd/AdminModel.hpp
@@ -12,13 +12,10 @@
#include <memory>
#include <set>
-#include <sstream>
#include <string>
-#include <queue>
#include <Poco/Net/WebSocket.h>
#include <Poco/Process.h>
-#include <Poco/StringTokenizer.h>
#include "Util.hpp"
@@ -30,15 +27,9 @@ public:
_start(std::time(nullptr))
{ }
- void expire()
- {
- _end = std::time(nullptr);
- }
+ void expire() { _end = std::time(nullptr); }
- bool isExpired()
- {
- return _end != 0 && std::time(nullptr) >= _end;
- }
+ bool isExpired() { return _end != 0 && std::time(nullptr) >= _end; }
private:
int _nSessionId;
@@ -63,53 +54,19 @@ public:
Log::info("Document " + std::to_string(_nPid) + " dtor.");
}
- Poco::Process::PID getPid() const
- {
- return _nPid;
- }
+ Poco::Process::PID getPid() const { return _nPid; }
- std::string getUrl() const
- {
- return _sUrl;
- }
+ std::string getUrl() const { return _sUrl; }
- void expire()
- {
- _end = std::time(nullptr);
- }
+ void expire() { _end = std::time(nullptr); }
- bool isExpired() const
- {
- return _end != 0 && std::time(nullptr) >= _end;
- }
+ bool isExpired() const { return _end != 0 && std::time(nullptr) >= _end; }
- void addView(int nSessionId)
- {
- const auto ret = _views.emplace(nSessionId, View(nSessionId));
- if (!ret.second)
- {
- Log::warn() << "View with SessionID [" + std::to_string(nSessionId) + "] already exists." << Log::end;
- }
- else
- {
- _nActiveViews++;
- }
- }
+ void addView(int nSessionId);
- void removeView(int nSessionId)
- {
- auto it = _views.find(nSessionId);
- if (it != _views.end())
- {
- it->second.expire();
- _nActiveViews--;
- }
- }
+ void removeView(int nSessionId);
- unsigned getActiveViews() const
- {
- return _nActiveViews;
- }
+ unsigned getActiveViews() const { return _nActiveViews; }
private:
Poco::Process::PID _nPid;
@@ -140,45 +97,15 @@ public:
Log::info("Subscriber dtor.");
}
- bool notify(const std::string& message)
- {
- Poco::StringTokenizer tokens(message, " ", Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM);
-
- if (_subscriptions.find(tokens[0]) == _subscriptions.end())
- return true;
-
- auto webSocket = _ws.lock();
- if (webSocket)
- {
- webSocket->sendFrame(message.data(), message.length());
- return true;
- }
- else
- {
- return false;
- }
- }
+ bool notify(const std::string& message);
- bool subscribe(const std::string& command)
- {
- auto ret = _subscriptions.insert(command);
- return ret.second;
- }
+ bool subscribe(const std::string& command);
- void unsubscribe(const std::string& command)
- {
- _subscriptions.erase(command);
- }
+ void unsubscribe(const std::string& command);
- void expire()
- {
- _end = std::time(nullptr);
- }
+ void expire() { _end = std::time(nullptr); }
- bool isExpired() const
- {
- return _end != 0 && std::time(nullptr) >= _end;
- }
+ bool isExpired() const { return _end != 0 && std::time(nullptr) >= _end; }
private:
/// Admin session Id
@@ -210,290 +137,44 @@ public:
Log::info("AdminModel dtor.");
}
- void update(const std::string& data)
- {
- Poco::StringTokenizer tokens(data, " ", Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM);
-
- Log::info("AdminModel Recv: " + data);
-
- if (tokens[0] == "document")
- {
- addDocument(std::stoi(tokens[1]), tokens[2]);
- unsigned mem = Util::getMemoryUsage(std::stoi(tokens[1]));
- std::string response = data + std::to_string(mem);
- notify(response);
- return;
- }
- else if (tokens[0] == "addview")
- {
- auto it = _documents.find(std::stoi(tokens[1]));
- if (it != _documents.end())
- {
- const unsigned nSessionId = Util::decodeId(tokens[2]);
- it->second.addView(nSessionId);
- }
- }
- else if (tokens[0] == "rmview")
- {
- auto it = _documents.find(std::stoi(tokens[1]));
- if (it != _documents.end())
- {
- const unsigned nSessionId = Util::decodeId(tokens[2]);
- it->second.removeView(nSessionId);
- }
- }
- else if (tokens[0] == "rmdoc")
- {
- removeDocument(std::stoi(tokens[1]));
- }
-
- notify(data);
- }
+ void update(const std::string& data);
- std::string query(const std::string command)
- {
- Poco::StringTokenizer tokens(command, " ", Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM);
-
- if (tokens[0] == "documents")
- {
- return getDocuments();
- }
- else if (tokens[0] == "active_users_count")
- {
- return std::to_string(getTotalActiveViews());
- }
- else if (tokens[0] == "active_docs_count")
- {
- return std::to_string(_documents.size());
- }
- else if (tokens[0] == "mem_stats")
- {
- return getMemStats();
- }
- else if (tokens[0] == "mem_stats_size")
- {
- return std::to_string(_memStatsSize);
- }
- else if (tokens[0] == "cpu_stats")
- {
- return getCpuStats();
- }
- else if (tokens[0] == "cpu_stats_size")
- {
- return std::to_string(_cpuStatsSize);
- }
-
- return std::string("");
- }
+ std::string query(const std::string command);
/// Returns memory consumed by all active loolkit processes
- unsigned getTotalMemoryUsage()
- {
- unsigned totalMem = 0;
- for (auto& it: _documents)
- {
- if (it.second.isExpired())
- continue;
+ unsigned getTotalMemoryUsage();
- totalMem += Util::getMemoryUsage(it.second.getPid());
- }
+ void subscribe(int nSessionId, std::shared_ptr<Poco::Net::WebSocket>& ws);
+ void subscribe(int nSessionId, const std::string& command);
- return totalMem;
- }
+ void unsubscribe(int nSessionId, const std::string& command);
- void subscribe(int nSessionId, std::shared_ptr<Poco::Net::WebSocket>& ws)
- {
- const auto ret = _subscribers.emplace(nSessionId, Subscriber(nSessionId, ws));
- if (!ret.second)
- {
- Log::warn() << "Subscriber already exists" << Log::end;
- }
- }
+ void clearMemStats() { _memStats.clear(); }
- void subscribe(int nSessionId, const std::string& command)
- {
- auto subscriber = _subscribers.find(nSessionId);
- if (subscriber == _subscribers.end() )
- return;
+ void clearCpuStats() { _cpuStats.clear(); }
- subscriber->second.subscribe(command);
- }
+ void addMemStats(unsigned memUsage);
- void unsubscribe(int nSessionId, const std::string& command)
- {
- auto subscriber = _subscribers.find(nSessionId);
- if (subscriber == _subscribers.end())
- return;
-
- subscriber->second.unsubscribe(command);
- }
+ void addCpuStats(unsigned cpuUsage);
- void clearMemStats()
- {
- _memStats.clear();
- }
+ void setCpuStatsSize(unsigned size);
- void clearCpuStats()
- {
- _cpuStats.clear();
- }
+ void setMemStatsSize(unsigned size);
- void addMemStats(unsigned memUsage)
- {
- _memStats.push_back(memUsage);
- if (_memStats.size() > _memStatsSize)
- {
- _memStats.pop_front();
- }
-
- std::ostringstream oss;
- oss << "mem_stats "
- << std::to_string(memUsage);
- notify(oss.str());
- }
-
- void addCpuStats(unsigned cpuUsage)
- {
- _cpuStats.push_back(cpuUsage);
- if (_cpuStats.size() > _cpuStatsSize)
- {
- _cpuStats.pop_front();
- }
-
- std::ostringstream oss;
- oss << "cpu_stats "
- << std::to_string(cpuUsage);
- notify(oss.str());
- }
-
- void setCpuStatsSize(unsigned size)
- {
- int wasteValuesLen = _cpuStats.size() - size;
- while (wasteValuesLen-- > 0)
- {
- _cpuStats.pop_front();
- }
- _cpuStatsSize = size;
-
- std::ostringstream oss;
- oss << "settings "
- << "cpu_stats_size="
- << std::to_string(_cpuStatsSize);
- notify(oss.str());
- }
-
- void setMemStatsSize(unsigned size)
- {
- int wasteValuesLen = _memStats.size() - size;
- while (wasteValuesLen-- > 0)
- {
- _memStats.pop_front();
- }
- _memStatsSize = size;
-
- std::ostringstream oss;
- oss << "settings "
- << "mem_stats_size="
- << std::to_string(_memStatsSize);
- notify(oss.str());
- }
-
- void notify(const std::string& message)
- {
- auto it = std::begin(_subscribers);
- while (it != std::end(_subscribers))
- {
- if (!it->second.notify(message))
- {
- it = _subscribers.erase(it);
- }
- else
- {
- it++;
- }
- }
- }
+ void notify(const std::string& message);
private:
- void addDocument(Poco::Process::PID pid, std::string url)
- {
- const auto ret = _documents.emplace(pid, Document(pid, url));
- if (!ret.second)
- {
- Log::warn() << "Document with PID [" + std::to_string(pid) + "] already exists." << Log::end;
- }
- }
-
- void removeDocument(Poco::Process::PID pid)
- {
- auto it = _documents.find(pid);
- if (it != _documents.end() && !it->second.isExpired())
- {
- // TODO: The idea is to only expire the document and keep the history
- // of documents open and close, to be able to give a detailed summary
- // to the admin console with views. For now, just remove the document.
- it->second.expire();
- _documents.erase(it);
- }
- }
-
- std::string getMemStats()
- {
- std::string response;
- for (auto& i: _memStats)
- {
- response += std::to_string(i) + ",";
- }
+ void addDocument(Poco::Process::PID pid, std::string url);
- return response;
- }
+ void removeDocument(Poco::Process::PID pid);
- std::string getCpuStats()
- {
- std::string response;
- for (auto& i: _cpuStats)
- {
- response += std::to_string(i) + ",";
- }
+ std::string getMemStats();
- return response;
- }
-
- unsigned getTotalActiveViews()
- {
- unsigned nTotalViews = 0;
- for (auto& it: _documents)
- {
- if (it.second.isExpired())
- continue;
+ std::string getCpuStats();
- nTotalViews += it.second.getActiveViews();
- }
+ unsigned getTotalActiveViews();
- return nTotalViews;
- }
-
- std::string getDocuments()
- {
- std::ostringstream oss;
- for (auto& it: _documents)
- {
- if (it.second.isExpired())
- continue;
-
- std::string sPid = std::to_string(it.second.getPid());
- std::string sUrl = it.second.getUrl();
- std::string sViews = std::to_string(it.second.getActiveViews());
- std::string sMem = std::to_string(Util::getMemoryUsage(it.second.getPid()));
-
- oss << sPid << " "
- << sUrl << " "
- << sViews << " "
- << sMem << " \n ";
- }
-
- return oss.str();
- }
+ std::string getDocuments();
private:
std::map<int, Subscriber> _subscribers;
diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am
index 53e952a..f3f5662 100644
--- a/loolwsd/Makefile.am
+++ b/loolwsd/Makefile.am
@@ -17,6 +17,7 @@ shared_sources = IoUtil.cpp \
Util.cpp
loolwsd_SOURCES = Admin.cpp \
+ AdminModel.cpp \
Auth.cpp \
ChildProcessSession.cpp \
DocumentBroker.cpp \
commit 939388c6e6362d9977a460139e55587de0be47d4
Author: Pranav Kant <pranavk at collabora.com>
Date: Thu Mar 31 12:31:05 2016 +0530
loolwsd: Arrange sources/header in makefile alphabetically
Change-Id: I0bc70b34a590d84ac9c15f0d9d0000d02cadba74
diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am
index 7428229..53e952a 100644
--- a/loolwsd/Makefile.am
+++ b/loolwsd/Makefile.am
@@ -10,34 +10,80 @@ AM_LDFLAGS = -pthread
AM_ETAGSFLAGS = --c++-kinds=+p --fields=+iaS --extra=+q -R --totals=yes *
AM_CTAGSFLAGS = $(AM_ETAGSFLAGS)
-shared_sources = LOOLProtocol.cpp LOOLSession.cpp MessageQueue.cpp IoUtil.cpp Util.cpp
-
-loolwsd_SOURCES = LOOLWSD.cpp ChildProcessSession.cpp MasterProcessSession.cpp TileCache.cpp Admin.cpp DocumentBroker.cpp Auth.cpp Storage.cpp $(shared_sources)
-
-noinst_PROGRAMS = loadtest connect lokitclient
-
-loadtest_SOURCES = LoadTest.cpp Util.cpp LOOLProtocol.cpp
-
-connect_SOURCES = Connect.cpp Util.cpp LOOLProtocol.cpp
-
-lokitclient_SOURCES = LOKitClient.cpp LOOLProtocol.cpp IoUtil.cpp Util.cpp
-
-broker_shared_sources = ChildProcessSession.cpp $(shared_sources)
-
-loolkit_SOURCES = LOOLKit.cpp $(broker_shared_sources)
-
-loolbroker_SOURCES = LOOLBroker.cpp $(broker_shared_sources)
+shared_sources = IoUtil.cpp \
+ LOOLProtocol.cpp \
+ LOOLSession.cpp \
+ MessageQueue.cpp \
+ Util.cpp
+
+loolwsd_SOURCES = Admin.cpp \
+ Auth.cpp \
+ ChildProcessSession.cpp \
+ DocumentBroker.cpp \
+ LOOLWSD.cpp \
+ MasterProcessSession.cpp \
+ Storage.cpp \
+ TileCache.cpp \
+ $(shared_sources)
+
+noinst_PROGRAMS = connect \
+ loadtest \
+ lokitclient
+
+loadtest_SOURCES = LoadTest.cpp \
+ LOOLProtocol.cpp \
+ Util.cpp
+
+connect_SOURCES = Connect.cpp \
+ LOOLProtocol.cpp \
+ Util.cpp
+
+lokitclient_SOURCES = IoUtil.cpp \
+ LOKitClient.cpp \
+ LOOLProtocol.cpp \
+ Util.cpp
+
+broker_shared_sources = ChildProcessSession.cpp \
+ $(shared_sources)
+
+loolkit_SOURCES = LOOLKit.cpp \
+ $(broker_shared_sources)
+
+loolbroker_SOURCES = LOOLBroker.cpp \
+ $(broker_shared_sources)
loolmap_SOURCES = loolmap.c
-noinst_HEADERS = LOKitHelper.hpp LOOLProtocol.hpp LOOLSession.hpp MasterProcessSession.hpp ChildProcessSession.hpp \
- LOOLWSD.hpp LoadTest.hpp MessageQueue.hpp TileCache.hpp Util.hpp Png.hpp Common.hpp Capabilities.hpp \
- Rectangle.hpp QueueHandler.hpp Admin.hpp Auth.hpp Storage.hpp AdminModel.hpp DocumentBroker.hpp \
- FileServer.hpp IoUtil.hpp \
- bundled/include/LibreOfficeKit/LibreOfficeKit.h bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h \
- bundled/include/LibreOfficeKit/LibreOfficeKitInit.h bundled/include/LibreOfficeKit/LibreOfficeKitTypes.h
-
-EXTRA_DIST = loolwsd.service sysconfig.loolwsd discovery.xml
+noinst_HEADERS = Admin.hpp \
+ AdminModel.hpp \
+ Auth.hpp \
+ Capabilities.hpp \
+ ChildProcessSession.hpp \
+ Common.hpp \
+ DocumentBroker.hpp \
+ FileServer.hpp \
+ IoUtil.hpp \
+ LoadTest.hpp \
+ LOKitHelper.hpp \
+ LOOLProtocol.hpp \
+ LOOLSession.hpp \
+ LOOLWSD.hpp \
+ MasterProcessSession.hpp \
+ MessageQueue.hpp \
+ Png.hpp \
+ QueueHandler.hpp \
+ Rectangle.hpp \
+ Storage.hpp \
+ TileCache.hpp \
+ Util.hpp \
+ bundled/include/LibreOfficeKit/LibreOfficeKit.h \
+ bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h \
+ bundled/include/LibreOfficeKit/LibreOfficeKitInit.h \
+ bundled/include/LibreOfficeKit/LibreOfficeKitTypes.h
+
+EXTRA_DIST = discovery.xml \
+ loolwsd.service \
+ sysconfig.loolwsd
clean-cache:
# Intentionally don't use "*" below... Avoid risk of accidentally running rm -rf /*
commit f1ede0c4baa0dc77050e11f4283e3ddb4e256fb9
Author: Pranav Kant <pranavk at collabora.com>
Date: Thu Mar 31 12:18:34 2016 +0530
loolwsd: Split Storage, Auth classes into header/impl files
Change-Id: I5d8990db8f8f4aa7a88bbb0cc84b97149cf4f8c0
diff --git a/loolwsd/Auth.cpp b/loolwsd/Auth.cpp
new file mode 100644
index 0000000..5d079d4
--- /dev/null
+++ b/loolwsd/Auth.cpp
@@ -0,0 +1,211 @@
+/* -*- 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/.
+ */
+
+#include <cstdlib>
+#include <string>
+
+#include <Poco/Base64Encoder.h>
+#include <Poco/Base64Decoder.h>
+#include <Poco/Crypto/RSADigestEngine.h>
+#include <Poco/Crypto/RSAKey.h>
+#include <Poco/JSON/Object.h>
+#include <Poco/LineEndingConverter.h>
+#include <Poco/Net/HTTPClientSession.h>
+#include <Poco/Net/HTTPRequest.h>
+#include <Poco/Net/HTTPResponse.h>
+#include <Poco/StringTokenizer.h>
+#include <Poco/Timestamp.h>
+#include <Poco/URI.h>
+
+#include "Auth.hpp"
+#include "Util.hpp"
+
+
+//////////////
+// OAuth Impl
+//////////////
+const std::string JWTAuth::getAccessToken()
+{
+ std::string encodedHeader = createHeader();
+ std::string encodedPayload = createPayload();
+
+ // trim '=' from end of encoded header
+ encodedHeader.erase(std::find_if(encodedHeader.rbegin(), encodedHeader.rend(),
+ [](char& ch)->bool {return ch != '='; }).base(), encodedHeader.end());
+ // trim '=' from end of encoded payload
+ encodedPayload.erase(std::find_if(encodedPayload.rbegin(), encodedPayload.rend(),
+ [](char& ch)->bool { return ch != '='; }).base(), encodedPayload.end());
+ Log::info("Encoded JWT header: " + encodedHeader);
+ Log::info("Encoded JWT payload: " + encodedPayload);
+
+ // Convert to a URL and filename safe variant:
+ // Replace '+' with '-' && '/' with '_'
+ std::replace(encodedHeader.begin(), encodedHeader.end(), '+','-');
+ std::replace(encodedHeader.begin(), encodedHeader.end(), '/','_');
+
+ std::replace(encodedPayload.begin(), encodedPayload.end(), '+','-');
+ std::replace(encodedPayload.begin(), encodedPayload.end(), '/','_');
+
+ std::string encodedBody = encodedHeader + "." + encodedPayload;
+
+ // sign the encoded body
+ _digestEngine.update(encodedBody.c_str(), static_cast<unsigned>(encodedBody.length()));
+ Poco::Crypto::DigestEngine::Digest digest = _digestEngine.signature();
+
+ // The signature generated contains CRLF line endings.
+ // Use a line ending converter to remove these CRLF
+ std::ostringstream ostr;
+ Poco::OutputLineEndingConverter lineEndingConv(ostr, "");
+ Poco::Base64Encoder encoder(lineEndingConv);
+ encoder << std::string(digest.begin(), digest.end());
+ encoder.close();
+ std::string encodedSig = ostr.str();
+
+ // trim '=' from end of encoded signature
+ encodedSig.erase(std::find_if(encodedSig.rbegin(), encodedSig.rend(),
+ [](char& ch)->bool { return ch != '='; }).base(), encodedSig.end());
+
+ // Be URL and filename safe
+ std::replace(encodedSig.begin(), encodedSig.end(), '+','-');
+ std::replace(encodedSig.begin(), encodedSig.end(), '/','_');
+
+ Log::info("Sig generated is : " + encodedSig);
+
+ const std::string jwtToken = encodedBody + "." + encodedSig;
+ Log::info("JWT token generated: " + jwtToken);
+
+ return jwtToken;
+}
+
+bool JWTAuth::verify(const std::string& accessToken)
+{
+ Poco::StringTokenizer tokens(accessToken, ".", Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM);
+
+ std::string encodedBody = tokens[0] + "." + tokens[1];
+ _digestEngine.update(encodedBody.c_str(), static_cast<unsigned>(encodedBody.length()));
+ Poco::Crypto::DigestEngine::Digest digest = _digestEngine.signature();
+
+ std::ostringstream ostr;
+ Poco::OutputLineEndingConverter lineEndingConv(ostr, "");
+ Poco::Base64Encoder encoder(lineEndingConv);
+
+ encoder << std::string(digest.begin(), digest.end());
+ encoder.close();
+ std::string encodedSig = ostr.str();
+
+ // trim '=' from end of encoded signature.
+ encodedSig.erase(std::find_if(encodedSig.rbegin(), encodedSig.rend(),
+ [](char& ch)->bool { return ch != '='; }).base(), encodedSig.end());
+
+ // Make the encoded sig URL and filename safe
+ std::replace(encodedSig.begin(), encodedSig.end(), '+', '-');
+ std::replace(encodedSig.begin(), encodedSig.end(), '/', '_');
+
+ if (encodedSig != tokens[2])
+ {
+ Log::info("JWTAuth::Token verification failed; Expected: " + encodedSig + ", Received: " + tokens[2]);
+ return false;
+ }
+
+ // TODO: Check for expiry etc.
+
+ return true;
+}
+
+const std::string JWTAuth::createHeader()
+{
+ // TODO: Some sane code to represent JSON objects
+ std::string header = "{\"alg\":\""+_alg+"\",\"typ\":\""+_typ+"\"}";
+
+ Log::info("JWT Header: " + header);
+ std::ostringstream ostr;
+ Poco::OutputLineEndingConverter lineEndingConv(ostr, "");
+ Poco::Base64Encoder encoder(lineEndingConv);
+ encoder << header;
+ encoder.close();
+
+ return ostr.str();
+}
+
+const std::string JWTAuth::createPayload()
+{
+ std::time_t curtime = Poco::Timestamp().epochTime();
+ std::string exptime = std::to_string(curtime + 3600);
+
+ // TODO: Some sane code to represent JSON objects
+ std::string payload = "{\"iss\":\""+_iss+"\",\"sub\":\""+_sub+"\",\"aud\":\""+_aud+"\",\"nme\":\""+_name+"\",\"exp\":\""+exptime+"\"}";
+
+ Log::info("JWT Payload: " + payload);
+ std::ostringstream ostr;
+ Poco::OutputLineEndingConverter lineEndingConv(ostr, "");
+ Poco::Base64Encoder encoder(lineEndingConv);
+ encoder << payload;
+ encoder.close();
+
+ return ostr.str();
+}
+
+
+//////////////
+// OAuth Impl
+//////////////
+
+//TODO: This MUST be done over TLS to protect the token.
+const std::string OAuth::getAccessToken()
+{
+ std::string url = _tokenEndPoint
+ + "?client_id=" + _clientId
+ + "&client_secret=" + _clientSecret
+ + "&grant_type=authorization_code"
+ + "&code=" + _authorizationCode;
+ // + "&redirect_uri="
+
+ Poco::URI uri(url);
+ Poco::Net::HTTPClientSession session(uri.getHost(), uri.getPort());
+ Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, url, Poco::Net::HTTPMessage::HTTP_1_1);
+ Poco::Net::HTTPResponse response;
+ session.sendRequest(request);
+ std::istream& rs = session.receiveResponse(response);
+ Log::info() << "Status: " << response.getStatus() << " " << response.getReason() << Log::end;
+ std::string reply(std::istreambuf_iterator<char>(rs), {});
+ Log::info("Response: " + reply);
+ //TODO: Parse the token.
+
+ return std::string();
+}
+
+bool OAuth::verify(const std::string& token)
+{
+ const std::string url = _authVerifyUrl + token;
+ Log::debug("Verifying authorization token from: " + url);
+ Poco::URI uri(url);
+ Poco::Net::HTTPClientSession session(uri.getHost(), uri.getPort());
+ Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, url, Poco::Net::HTTPMessage::HTTP_1_1);
+ Poco::Net::HTTPResponse response;
+ session.sendRequest(request);
+ std::istream& rs = session.receiveResponse(response);
+ Log::info() << "Status: " << response.getStatus() << " " << response.getReason() << Log::end;
+ std::string reply(std::istreambuf_iterator<char>(rs), {});
+ Log::info("Response: " + reply);
+
+ //TODO: Parse the response.
+ /*
+ // This is used for the demo site.
+ const auto lastLogTime = std::strtoul(reply.c_str(), nullptr, 0);
+ if (lastLogTime < 1)
+ {
+ //TODO: Redirect to login page.
+ return;
+ }
+ */
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/loolwsd/Auth.hpp b/loolwsd/Auth.hpp
index fdc2fc1..f4e10a1 100644
--- a/loolwsd/Auth.hpp
+++ b/loolwsd/Auth.hpp
@@ -11,24 +11,10 @@
#ifndef INCLUDED_AUTH_HPP
#define INCLUDED_AUTH_HPP
-#include <cstdlib>
#include <string>
-#include <Poco/Base64Encoder.h>
-#include <Poco/Base64Decoder.h>
#include <Poco/Crypto/RSADigestEngine.h>
#include <Poco/Crypto/RSAKey.h>
-#include <Poco/DigestEngine.h>
-#include <Poco/JSON/Object.h>
-#include <Poco/LineEndingConverter.h>
-#include <Poco/Net/HTTPClientSession.h>
-#include <Poco/Net/HTTPRequest.h>
-#include <Poco/Net/HTTPResponse.h>
-#include <Poco/StringTokenizer.h>
-#include <Poco/Timestamp.h>
-#include <Poco/URI.h>
-
-#include "Util.hpp"
/// Base class of all Authentication/Authorization implementations.
class AuthBase
@@ -53,127 +39,14 @@ public:
_digestEngine(_key, "SHA256")
{ }
- const std::string getAccessToken()
- {
- std::string encodedHeader = createHeader();
- std::string encodedPayload = createPayload();
-
- // trim '=' from end of encoded header
- encodedHeader.erase(std::find_if(encodedHeader.rbegin(), encodedHeader.rend(),
- [](char& ch)->bool {return ch != '='; }).base(), encodedHeader.end());
- // trim '=' from end of encoded payload
- encodedPayload.erase(std::find_if(encodedPayload.rbegin(), encodedPayload.rend(),
- [](char& ch)->bool { return ch != '='; }).base(), encodedPayload.end());
- Log::info("Encoded JWT header: " + encodedHeader);
- Log::info("Encoded JWT payload: " + encodedPayload);
-
- // Convert to a URL and filename safe variant:
- // Replace '+' with '-' && '/' with '_'
- std::replace(encodedHeader.begin(), encodedHeader.end(), '+','-');
- std::replace(encodedHeader.begin(), encodedHeader.end(), '/','_');
-
- std::replace(encodedPayload.begin(), encodedPayload.end(), '+','-');
- std::replace(encodedPayload.begin(), encodedPayload.end(), '/','_');
-
- std::string encodedBody = encodedHeader + "." + encodedPayload;
-
- // sign the encoded body
- _digestEngine.update(encodedBody.c_str(), static_cast<unsigned>(encodedBody.length()));
- Poco::Crypto::DigestEngine::Digest digest = _digestEngine.signature();
-
- // The signature generated contains CRLF line endings.
- // Use a line ending converter to remove these CRLF
- std::ostringstream ostr;
- Poco::OutputLineEndingConverter lineEndingConv(ostr, "");
- Poco::Base64Encoder encoder(lineEndingConv);
- encoder << std::string(digest.begin(), digest.end());
- encoder.close();
- std::string encodedSig = ostr.str();
-
- // trim '=' from end of encoded signature
- encodedSig.erase(std::find_if(encodedSig.rbegin(), encodedSig.rend(),
- [](char& ch)->bool { return ch != '='; }).base(), encodedSig.end());
-
- // Be URL and filename safe
- std::replace(encodedSig.begin(), encodedSig.end(), '+','-');
- std::replace(encodedSig.begin(), encodedSig.end(), '/','_');
-
- Log::info("Sig generated is : " + encodedSig);
-
- const std::string jwtToken = encodedBody + "." + encodedSig;
- Log::info("JWT token generated: " + jwtToken);
-
- return jwtToken;
- }
-
- bool verify(const std::string& accessToken)
- {
- Poco::StringTokenizer tokens(accessToken, ".", Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM);
-
- std::string encodedBody = tokens[0] + "." + tokens[1];
- _digestEngine.update(encodedBody.c_str(), static_cast<unsigned>(encodedBody.length()));
- Poco::Crypto::DigestEngine::Digest digest = _digestEngine.signature();
-
- std::ostringstream ostr;
- Poco::OutputLineEndingConverter lineEndingConv(ostr, "");
- Poco::Base64Encoder encoder(lineEndingConv);
-
- encoder << std::string(digest.begin(), digest.end());
- encoder.close();
- std::string encodedSig = ostr.str();
-
- // trim '=' from end of encoded signature.
- encodedSig.erase(std::find_if(encodedSig.rbegin(), encodedSig.rend(),
- [](char& ch)->bool { return ch != '='; }).base(), encodedSig.end());
-
- // Make the encoded sig URL and filename safe
- std::replace(encodedSig.begin(), encodedSig.end(), '+', '-');
- std::replace(encodedSig.begin(), encodedSig.end(), '/', '_');
+ const std::string getAccessToken() override;
- if (encodedSig != tokens[2])
- {
- Log::info("JWTAuth::Token verification failed; Expected: " + encodedSig + ", Received: " + tokens[2]);
- return false;
- }
-
- // TODO: Check for expiry etc.
-
- return true;
- }
+ bool verify(const std::string& accessToken) override;
private:
- const std::string createHeader()
- {
- // TODO: Some sane code to represent JSON objects
- std::string header = "{\"alg\":\""+_alg+"\",\"typ\":\""+_typ+"\"}";
-
- Log::info("JWT Header: " + header);
- std::ostringstream ostr;
- Poco::OutputLineEndingConverter lineEndingConv(ostr, "");
- Poco::Base64Encoder encoder(lineEndingConv);
- encoder << header;
- encoder.close();
-
- return ostr.str();
- }
-
- const std::string createPayload()
- {
- std::time_t curtime = Poco::Timestamp().epochTime();
- std::string exptime = std::to_string(curtime + 3600);
-
- // TODO: Some sane code to represent JSON objects
- std::string payload = "{\"iss\":\""+_iss+"\",\"sub\":\""+_sub+"\",\"aud\":\""+_aud+"\",\"nme\":\""+_name+"\",\"exp\":\""+exptime+"\"}";
+ const std::string createHeader();
- Log::info("JWT Payload: " + payload);
- std::ostringstream ostr;
- Poco::OutputLineEndingConverter lineEndingConv(ostr, "");
- Poco::Base64Encoder encoder(lineEndingConv);
- encoder << payload;
- encoder.close();
-
- return ostr.str();
- }
+ const std::string createPayload();
private:
const std::string _alg = "RS256";
@@ -204,57 +77,9 @@ public:
{
}
- //TODO: This MUST be done over TLS to protect the token.
- const std::string getAccessToken() override
- {
- std::string url = _tokenEndPoint
- + "?client_id=" + _clientId
- + "&client_secret=" + _clientSecret
- + "&grant_type=authorization_code"
- + "&code=" + _authorizationCode;
- // + "&redirect_uri="
-
- Poco::URI uri(url);
- Poco::Net::HTTPClientSession session(uri.getHost(), uri.getPort());
- Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, url, Poco::Net::HTTPMessage::HTTP_1_1);
- Poco::Net::HTTPResponse response;
- session.sendRequest(request);
- std::istream& rs = session.receiveResponse(response);
- Log::info() << "Status: " << response.getStatus() << " " << response.getReason() << Log::end;
- std::string reply(std::istreambuf_iterator<char>(rs), {});
- Log::info("Response: " + reply);
- //TODO: Parse the token.
-
- return std::string();
- }
-
- bool verify(const std::string& token) override
- {
- const std::string url = _authVerifyUrl + token;
- Log::debug("Verifying authorization token from: " + url);
- Poco::URI uri(url);
- Poco::Net::HTTPClientSession session(uri.getHost(), uri.getPort());
- Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, url, Poco::Net::HTTPMessage::HTTP_1_1);
- Poco::Net::HTTPResponse response;
- session.sendRequest(request);
- std::istream& rs = session.receiveResponse(response);
- Log::info() << "Status: " << response.getStatus() << " " << response.getReason() << Log::end;
- std::string reply(std::istreambuf_iterator<char>(rs), {});
- Log::info("Response: " + reply);
+ const std::string getAccessToken() override;
- //TODO: Parse the response.
- /*
- // This is used for the demo site.
- const auto lastLogTime = std::strtoul(reply.c_str(), nullptr, 0);
- if (lastLogTime < 1)
- {
- //TODO: Redirect to login page.
- return;
- }
- */
-
- return true;
- }
+ bool verify(const std::string& token) override;
private:
const std::string _clientId;
diff --git a/loolwsd/DocumentBroker.cpp b/loolwsd/DocumentBroker.cpp
index 5390f67..5e35a86 100644
--- a/loolwsd/DocumentBroker.cpp
+++ b/loolwsd/DocumentBroker.cpp
@@ -7,6 +7,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
+#include <cassert>
+
#include <Poco/Path.h>
#include <Poco/SHA1Engine.h>
diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am
index 458ea85..7428229 100644
--- a/loolwsd/Makefile.am
+++ b/loolwsd/Makefile.am
@@ -12,7 +12,7 @@ AM_CTAGSFLAGS = $(AM_ETAGSFLAGS)
shared_sources = LOOLProtocol.cpp LOOLSession.cpp MessageQueue.cpp IoUtil.cpp Util.cpp
-loolwsd_SOURCES = LOOLWSD.cpp ChildProcessSession.cpp MasterProcessSession.cpp TileCache.cpp Admin.cpp DocumentBroker.cpp $(shared_sources)
+loolwsd_SOURCES = LOOLWSD.cpp ChildProcessSession.cpp MasterProcessSession.cpp TileCache.cpp Admin.cpp DocumentBroker.cpp Auth.cpp Storage.cpp $(shared_sources)
noinst_PROGRAMS = loadtest connect lokitclient
diff --git a/loolwsd/Storage.cpp b/loolwsd/Storage.cpp
new file mode 100644
index 0000000..f649a79
--- /dev/null
+++ b/loolwsd/Storage.cpp
@@ -0,0 +1,275 @@
+/* -*- 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/.
+ */
+
+#include <cassert>
+#include <string>
+#include <fstream>
+
+#include <Poco/Net/HTTPResponse.h>
+#include <Poco/Net/HTTPRequest.h>
+#include <Poco/Net/HTTPSClientSession.h>
+#include <Poco/Net/SSLManager.h>
+#include <Poco/StreamCopier.h>
+#include <Poco/JSON/Object.h>
+#include <Poco/JSON/Parser.h>
+
+#include "Common.hpp"
+#include "Auth.hpp"
+#include "Storage.hpp"
+#include "Util.hpp"
+
+///////////////////
+// StorageBase Impl
+///////////////////
+std::string StorageBase::getLocalRootPath() const
+{
+ auto localPath = _jailPath;
+ if (localPath[0] == '/')
+ {
+ // Remove the leading /
+ localPath.erase(0, 1);
+ }
+
+ // /chroot/jailId/user/doc/childId
+ const auto rootPath = Poco::Path(_localStorePath, localPath);
+ Poco::File(rootPath).createDirectories();
+
+ return rootPath.toString();
+}
+
+size_t StorageBase::getFileSize(const std::string& filename)
+{
+ return std::ifstream(filename, std::ifstream::ate | std::ifstream::binary).tellg();
+}
+
+////////////////////
+// LocalStorage Impl
+/////////////////////
+StorageBase::FileInfo LocalStorage::getFileInfo(const Poco::URI& uri)
+{
+ const auto path = uri.getPath();
+ Log::debug("Getting info for local uri [" + uri.toString() + "], path [" + path + "].");
+ const auto filename = Poco::Path(path).getFileName();
+ const auto lastModified = Poco::File(path).getLastModified();
+ const auto size = Poco::File(path).getSize();
+ return FileInfo({filename, lastModified, size});
+}
+
+std::string LocalStorage::loadStorageFileToLocal()
+{
+ const auto rootPath = getLocalRootPath();
+
+ // /chroot/jailId/user/doc/childId/file.ext
+ const auto filename = Poco::Path(_uri).getFileName();
+ _jailedFilePath = Poco::Path(rootPath, filename).toString();
+
+ Log::info("Public URI [" + _uri +
+ "] jailed to [" + _jailedFilePath + "].");
+
+ const auto publicFilePath = _uri;
+ Log::info("Linking " + publicFilePath + " to " + _jailedFilePath);
+ if (!Poco::File(_jailedFilePath).exists() && link(publicFilePath.c_str(), _jailedFilePath.c_str()) == -1)
+ {
+ // Failed
+ Log::warn("link(\"" + publicFilePath + "\", \"" + _jailedFilePath + "\") failed. Will copy.");
+ }
+
+ try
+ {
+ // Fallback to copying.
+ if (!Poco::File(_jailedFilePath).exists())
+ {
+ Log::info("Copying " + publicFilePath + " to " + _jailedFilePath);
+ Poco::File(publicFilePath).copyTo(_jailedFilePath);
+ _isCopy = true;
+ }
+ }
+ catch (const Poco::Exception& exc)
+ {
+ Log::error("copyTo(\"" + publicFilePath + "\", \"" + _jailedFilePath + "\") failed: " + exc.displayText());
+ throw;
+ }
+
+ // Now return the jailed path.
+ return Poco::Path(_jailPath, filename).toString();
+}
+
+bool LocalStorage::saveLocalFileToStorage()
+{
+ try
+ {
+ // Copy the file back.
+ if (_isCopy && Poco::File(_jailedFilePath).exists())
+ {
+ Log::info("Copying " + _jailedFilePath + " to " + _uri);
+ Poco::File(_jailedFilePath).copyTo(_uri);
+ }
+ }
+ catch (const Poco::Exception& exc)
+ {
+ Log::error("copyTo(\"" + _jailedFilePath + "\", \"" + _uri + "\") failed: " + exc.displayText());
+ throw;
+ }
+
+ return true;
+}
+
+///////////////////
+// WopiStorage Impl
+///////////////////
+StorageBase::FileInfo WopiStorage::getFileInfo(const Poco::URI& uri)
+{
+ Log::debug("Getting info for wopi uri [" + uri.toString() + "].");
+
+ Poco::URI uriObject(uri);
+ Poco::Net::HTTPSClientSession session(uriObject.getHost(), uriObject.getPort(), Poco::Net::SSLManager::instance().defaultClientContext());
+ Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, uriObject.getPathAndQuery(), Poco::Net::HTTPMessage::HTTP_1_1);
+ request.set("User-Agent", "LOOLWSD WOPI Agent");
+ session.sendRequest(request);
+
+ Poco::Net::HTTPResponse response;
+ std::istream& rs = session.receiveResponse(response);
+
+ auto logger = Log::trace();
+ logger << "WOPI::CheckFileInfo header for URI [" << uri.toString() << "]:\n";
+ for (auto& pair : response)
+ {
+ logger << '\t' + pair.first + ": " + pair.second << " / ";
+ }
+
+ logger << Log::end;
+
+ // Parse the response.
+ std::string filename;
+ size_t size = 0;
+ std::string resMsg;
+ Poco::StreamCopier::copyToString(rs, resMsg);
+ Log::debug("WOPI::CheckFileInfo returned: " + resMsg);
+ const auto index = resMsg.find_first_of("{");
+ if (index != std::string::npos)
+ {
+ const std::string stringJSON = resMsg.substr(index);
+ Poco::JSON::Parser parser;
+ const auto result = parser.parse(stringJSON);
+ const auto object = result.extract<Poco::JSON::Object::Ptr>();
+ filename = object->get("BaseFileName").toString();
+ size = std::stoul (object->get("Size").toString(), nullptr, 0);
+ }
+
+ // WOPI doesn't support file last modified time.
+ return FileInfo({filename, Poco::Timestamp(), size});
+}
+
+/// uri format: http://server/<...>/wopi*/files/<id>/content
+std::string WopiStorage::loadStorageFileToLocal()
+{
+ Log::info("Downloading URI [" + _uri + "].");
+
+ _fileInfo = getFileInfo(Poco::URI(_uri));
+ if (_fileInfo.Size == 0 && _fileInfo.Filename.empty())
+ {
+ //TODO: Should throw a more appropriate exception.
+ throw std::runtime_error("Failed to load file from storage.");
+ }
+
+ // WOPI URI to download files ends in '/contents'.
+ // Add it here to get the payload instead of file info.
+ Poco::URI uriObject(_uri);
+ const auto url = uriObject.getPath() + "/contents?" + uriObject.getQuery();
+ Log::debug("Wopi requesting: " + url);
+
+ Poco::Net::HTTPSClientSession session(uriObject.getHost(), uriObject.getPort(), Poco::Net::SSLManager::instance().defaultClientContext());
+ Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, url, Poco::Net::HTTPMessage::HTTP_1_1);
+ request.set("User-Agent", "LOOLWSD WOPI Agent");
+ session.sendRequest(request);
+
+ Poco::Net::HTTPResponse response;
+ std::istream& rs = session.receiveResponse(response);
+
+ auto logger = Log::trace();
+ logger << "WOPI::GetFile header for URI [" << _uri << "]:\n";
+ for (auto& pair : response)
+ {
+ logger << '\t' + pair.first + ": " + pair.second << " / ";
+ }
+
+ logger << Log::end;
+
+ _jailedFilePath = Poco::Path(getLocalRootPath(), _fileInfo.Filename).toString();
+ std::ofstream ofs(_jailedFilePath);
+ std::copy(std::istreambuf_iterator<char>(rs),
+ std::istreambuf_iterator<char>(),
+ std::ostreambuf_iterator<char>(ofs));
+ const auto size = getFileSize(_jailedFilePath);
+
+ Log::info() << "WOPI::GetFile downloaded " << size << " bytes from [" << _uri
+ << "] -> " << _jailedFilePath << ": "
+ << response.getStatus() << " " << response.getReason() << Log::end;
+
+ // Now return the jailed path.
+ return Poco::Path(_jailPath, _fileInfo.Filename).toString();
+}
+
+bool WopiStorage::saveLocalFileToStorage()
+{
+ Log::info("Uploading URI [" + _uri + "] from [" + _jailedFilePath + "].");
+ const auto size = getFileSize(_jailedFilePath);
+
+ Poco::URI uriObject(_uri);
+ const auto url = uriObject.getPath() + "/contents?" + uriObject.getQuery();
+ Log::debug("Wopi posting: " + url);
+
+ Poco::Net::HTTPSClientSession session(uriObject.getHost(), uriObject.getPort(), Poco::Net::SSLManager::instance().defaultClientContext());
+ Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, url, Poco::Net::HTTPMessage::HTTP_1_1);
+ request.set("X-WOPIOverride", "PUT");
+ request.setContentType("application/octet-stream");
+ request.setContentLength(size);
+
+ std::ostream& os = session.sendRequest(request);
+ std::ifstream ifs(_jailedFilePath);
+ Poco::StreamCopier::copyStream(ifs, os);
+
+ Poco::Net::HTTPResponse response;
+ std::istream& rs = session.receiveResponse(response);
+ std::ostringstream oss;
+ Poco::StreamCopier::copyStream(rs, oss);
+
+ Log::info("WOPI::PutFile response: " + oss.str());
+ const auto success = (response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK);
+ Log::info() << "WOPI::PutFile uploaded " << size << " bytes from [" << _jailedFilePath << "]:"
+ << "] -> [" << _uri << "]: "
+ << response.getStatus() << " " << response.getReason() << Log::end;
+
+ return success;
+}
+
+//////////////////////
+// WebDAVStorage Impl
+///////////////////////
+StorageBase::FileInfo WebDAVStorage::getFileInfo(const Poco::URI& uri)
+{
+ Log::debug("Getting info for webdav uri [" + uri.toString() + "].");
+ (void)uri;
+ assert(!"Not Implemented!");
+ return FileInfo({"bazinga", Poco::Timestamp(), 0});
+}
+
+std::string WebDAVStorage::loadStorageFileToLocal()
+{
+ // TODO: implement webdav GET.
+ return _uri;
+}
+
+bool WebDAVStorage::saveLocalFileToStorage()
+{
+ // TODO: implement webdav PUT.
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/loolwsd/Storage.hpp b/loolwsd/Storage.hpp
index 08bec04..9e46f3d 100644
--- a/loolwsd/Storage.hpp
+++ b/loolwsd/Storage.hpp
@@ -11,18 +11,10 @@
#ifndef INCLUDED_STORAGE_HPP
#define INCLUDED_STORAGE_HPP
-#include <cassert>
#include <string>
-#include <fstream>
-#include <Poco/Net/HTTPResponse.h>
-#include <Poco/Net/HTTPSClientSession.h>
-#include <Poco/Net/SSLManager.h>
-#include <Poco/StreamCopier.h>
-#include <Poco/JSON/Object.h>
-#include <Poco/JSON/Parser.h>
+#include <Poco/URI.h>
-#include "Common.hpp"
#include "Auth.hpp"
#include "Util.hpp"
@@ -51,21 +43,7 @@ public:
Log::debug("Storage ctor: " + uri);
}
- std::string getLocalRootPath() const
- {
- auto localPath = _jailPath;
- if (localPath[0] == '/')
- {
- // Remove the leading /
- localPath.erase(0, 1);
- }
-
- // /chroot/jailId/user/doc/childId
- const auto rootPath = Poco::Path(_localStorePath, localPath);
- Poco::File(rootPath).createDirectories();
-
- return rootPath.toString();
- }
+ std::string getLocalRootPath() const;
const std::string& getUri() const { return _uri; }
@@ -83,10 +61,7 @@ public:
virtual bool saveLocalFileToStorage() = 0;
static
- size_t getFileSize(const std::string& filename)
- {
- return std::ifstream(filename, std::ifstream::ate | std::ifstream::binary).tellg();
- }
+ size_t getFileSize(const std::string& filename);
protected:
const std::string _localStorePath;
@@ -108,74 +83,11 @@ public:
{
}
- FileInfo getFileInfo(const Poco::URI& uri) override
- {
- const auto path = uri.getPath();
- Log::debug("Getting info for local uri [" + uri.toString() + "], path [" + path + "].");
- const auto filename = Poco::Path(path).getFileName();
- const auto lastModified = Poco::File(path).getLastModified();
- const auto size = Poco::File(path).getSize();
- return FileInfo({filename, lastModified, size});
- }
-
- std::string loadStorageFileToLocal() override
- {
- const auto rootPath = getLocalRootPath();
-
- // /chroot/jailId/user/doc/childId/file.ext
- const auto filename = Poco::Path(_uri).getFileName();
- _jailedFilePath = Poco::Path(rootPath, filename).toString();
-
- Log::info("Public URI [" + _uri +
- "] jailed to [" + _jailedFilePath + "].");
-
- const auto publicFilePath = _uri;
- Log::info("Linking " + publicFilePath + " to " + _jailedFilePath);
- if (!Poco::File(_jailedFilePath).exists() && link(publicFilePath.c_str(), _jailedFilePath.c_str()) == -1)
- {
- // Failed
- Log::warn("link(\"" + publicFilePath + "\", \"" + _jailedFilePath + "\") failed. Will copy.");
- }
+ FileInfo getFileInfo(const Poco::URI& uri) override;
- try
- {
- // Fallback to copying.
- if (!Poco::File(_jailedFilePath).exists())
- {
- Log::info("Copying " + publicFilePath + " to " + _jailedFilePath);
- Poco::File(publicFilePath).copyTo(_jailedFilePath);
- _isCopy = true;
- }
- }
- catch (const Poco::Exception& exc)
- {
- Log::error("copyTo(\"" + publicFilePath + "\", \"" + _jailedFilePath + "\") failed: " + exc.displayText());
- throw;
- }
+ std::string loadStorageFileToLocal() override;
- // Now return the jailed path.
- return Poco::Path(_jailPath, filename).toString();
- }
-
- bool saveLocalFileToStorage() override
- {
- try
- {
- // Copy the file back.
- if (_isCopy && Poco::File(_jailedFilePath).exists())
- {
- Log::info("Copying " + _jailedFilePath + " to " + _uri);
- Poco::File(_jailedFilePath).copyTo(_uri);
- }
- }
- catch (const Poco::Exception& exc)
- {
- Log::error("copyTo(\"" + _jailedFilePath + "\", \"" + _uri + "\") failed: " + exc.displayText());
- throw;
- }
-
- return true;
- }
+ bool saveLocalFileToStorage() override;
private:
/// True if the jailed file is not linked but copied.
@@ -192,131 +104,12 @@ public:
{
}
- FileInfo getFileInfo(const Poco::URI& uri) override
- {
- Log::debug("Getting info for wopi uri [" + uri.toString() + "].");
-
- Poco::URI uriObject(uri);
- Poco::Net::HTTPSClientSession session(uriObject.getHost(), uriObject.getPort(), Poco::Net::SSLManager::instance().defaultClientContext());
- Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, uriObject.getPathAndQuery(), Poco::Net::HTTPMessage::HTTP_1_1);
- request.set("User-Agent", "LOOLWSD WOPI Agent");
- session.sendRequest(request);
-
- Poco::Net::HTTPResponse response;
- std::istream& rs = session.receiveResponse(response);
-
- auto logger = Log::trace();
- logger << "WOPI::CheckFileInfo header for URI [" << uri.toString() << "]:\n";
- for (auto& pair : response)
- {
- logger << '\t' + pair.first + ": " + pair.second << " / ";
- }
-
- logger << Log::end;
-
- // Parse the response.
- std::string filename;
- size_t size = 0;
- std::string resMsg;
- Poco::StreamCopier::copyToString(rs, resMsg);
- Log::debug("WOPI::CheckFileInfo returned: " + resMsg);
- const auto index = resMsg.find_first_of("{");
- if (index != std::string::npos)
- {
- const std::string stringJSON = resMsg.substr(index);
- Poco::JSON::Parser parser;
- const auto result = parser.parse(stringJSON);
- const auto object = result.extract<Poco::JSON::Object::Ptr>();
- filename = object->get("BaseFileName").toString();
- size = std::stoul (object->get("Size").toString(), nullptr, 0);
- }
-
- // WOPI doesn't support file last modified time.
- return FileInfo({filename, Poco::Timestamp(), size});
- }
+ FileInfo getFileInfo(const Poco::URI& uri) override;
/// uri format: http://server/<...>/wopi*/files/<id>/content
- std::string loadStorageFileToLocal() override
- {
- Log::info("Downloading URI [" + _uri + "].");
-
- _fileInfo = getFileInfo(Poco::URI(_uri));
- if (_fileInfo.Size == 0 && _fileInfo.Filename.empty())
- {
- //TODO: Should throw a more appropriate exception.
- throw std::runtime_error("Failed to load file from storage.");
- }
-
- // WOPI URI to download files ends in '/contents'.
- // Add it here to get the payload instead of file info.
- Poco::URI uriObject(_uri);
- const auto url = uriObject.getPath() + "/contents?" + uriObject.getQuery();
- Log::debug("Wopi requesting: " + url);
-
- Poco::Net::HTTPSClientSession session(uriObject.getHost(), uriObject.getPort(), Poco::Net::SSLManager::instance().defaultClientContext());
- Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, url, Poco::Net::HTTPMessage::HTTP_1_1);
- request.set("User-Agent", "LOOLWSD WOPI Agent");
- session.sendRequest(request);
-
- Poco::Net::HTTPResponse response;
- std::istream& rs = session.receiveResponse(response);
-
- auto logger = Log::trace();
- logger << "WOPI::GetFile header for URI [" << _uri << "]:\n";
- for (auto& pair : response)
- {
- logger << '\t' + pair.first + ": " + pair.second << " / ";
- }
-
- logger << Log::end;
-
- _jailedFilePath = Poco::Path(getLocalRootPath(), _fileInfo.Filename).toString();
- std::ofstream ofs(_jailedFilePath);
- std::copy(std::istreambuf_iterator<char>(rs),
- std::istreambuf_iterator<char>(),
- std::ostreambuf_iterator<char>(ofs));
- const auto size = getFileSize(_jailedFilePath);
-
- Log::info() << "WOPI::GetFile downloaded " << size << " bytes from [" << _uri
- << "] -> " << _jailedFilePath << ": "
- << response.getStatus() << " " << response.getReason() << Log::end;
-
- // Now return the jailed path.
- return Poco::Path(_jailPath, _fileInfo.Filename).toString();
- }
-
- bool saveLocalFileToStorage() override
- {
- Log::info("Uploading URI [" + _uri + "] from [" + _jailedFilePath + "].");
- const auto size = getFileSize(_jailedFilePath);
+ std::string loadStorageFileToLocal() override;
- Poco::URI uriObject(_uri);
- const auto url = uriObject.getPath() + "/contents?" + uriObject.getQuery();
- Log::debug("Wopi posting: " + url);
-
- Poco::Net::HTTPSClientSession session(uriObject.getHost(), uriObject.getPort(), Poco::Net::SSLManager::instance().defaultClientContext());
- Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, url, Poco::Net::HTTPMessage::HTTP_1_1);
- request.set("X-WOPIOverride", "PUT");
- request.setContentType("application/octet-stream");
- request.setContentLength(size);
-
- std::ostream& os = session.sendRequest(request);
- std::ifstream ifs(_jailedFilePath);
- Poco::StreamCopier::copyStream(ifs, os);
-
- Poco::Net::HTTPResponse response;
- std::istream& rs = session.receiveResponse(response);
- std::ostringstream oss;
- Poco::StreamCopier::copyStream(rs, oss);
-
- Log::info("WOPI::PutFile response: " + oss.str());
- const auto success = (response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK);
- Log::info() << "WOPI::PutFile uploaded " << size << " bytes from [" << _jailedFilePath << "]:"
- << "] -> [" << _uri << "]: "
- << response.getStatus() << " " << response.getReason() << Log::end;
-
- return success;
- }
+ bool saveLocalFileToStorage() override;
};
class WebDAVStorage : public StorageBase
@@ -331,25 +124,11 @@ public:
{
}
- FileInfo getFileInfo(const Poco::URI& uri) override
- {
- Log::debug("Getting info for webdav uri [" + uri.toString() + "].");
- (void)uri;
- assert(!"Not Implemented!");
- return FileInfo({"bazinga", Poco::Timestamp(), 0});
- }
+ FileInfo getFileInfo(const Poco::URI& uri) override;
- std::string loadStorageFileToLocal() override
- {
- // TODO: implement webdav GET.
- return _uri;
- }
+ std::string loadStorageFileToLocal() override;
- bool saveLocalFileToStorage() override
- {
- // TODO: implement webdav PUT.
- return false;
- }
+ bool saveLocalFileToStorage() override;
private:
std::unique_ptr<AuthBase> _authAgent;
More information about the Libreoffice-commits
mailing list