[Libreoffice-commits] online.git: Branch 'feature/proxyhack' - 216 commits - android/app android/lib common/Authorization.hpp common/Clipboard.hpp common/Common.hpp common/Crypto.hpp common/FileUtil.cpp common/FileUtil.hpp common/IoUtil.cpp common/IoUtil.hpp common/JsonUtil.hpp common/Log.hpp common/LOOLWebSocket.hpp common/Message.hpp common/MessageQueue.cpp common/MessageQueue.hpp common/Png.hpp common/Protocol.hpp common/Rectangle.hpp common/Seccomp.hpp common/security.h common/Session.cpp common/Session.hpp common/SigUtil.cpp common/SigUtil.hpp common/SpookyV2.h common/StringVector.hpp common/Unit.hpp common/UnitHTTP.hpp common/Util.cpp common/Util.hpp configure.ac cypress_test/cypress.json cypress_test/data cypress_test/integration_tests cypress_test/Makefile.am cypress_test/package.json cypress_test/run_iteratively.sh docker/l10n-docker-nightly.sh fuzzer/Admin.cpp fuzzer/admin-data fuzzer/ClientSession.cpp .gitignore ios/config.h.in ios/Mobile ios/Mobile.xcodeproj kit/ChildSession.cpp kit/C hildSession.hpp kit/Delta.hpp kit/DummyLibreOfficeKit.hpp kit/ForKit.cpp kit/Kit.cpp kit/KitHelper.hpp kit/Kit.hpp kit/Watermark.hpp loleaflet/admin loleaflet/css loleaflet/.gitignore loleaflet/html loleaflet/images loleaflet/js loleaflet/Makefile.am loleaflet/po loleaflet/README loleaflet/spec loleaflet/src loleaflet/welcome loolwsd.xml.in Makefile.am net/DelaySocket.cpp net/DelaySocket.hpp net/FakeSocket.hpp net/ServerSocket.hpp net/Socket.cpp net/Socket.hpp net/Ssl.hpp net/SslSocket.hpp net/WebSocketHandler.hpp test/countloolkits.hpp test/helpers.hpp test/httpcrashtest.cpp test/lokassert.hpp test/Makefile.am test/test.hpp test/UnitConvert.cpp test/UnitFuzz.cpp test/UnitOOB.cpp test/UnitSession.cpp test/UnitWOPIDocumentConflict.cpp test/WopiProofTests.cpp tools/Connect.cpp tools/Replay.hpp tools/Stress.cpp tools/Tool.cpp tools/WebSocketDump.cpp wsd/Admin.cpp wsd/Admin.hpp wsd/AdminModel.cpp wsd/AdminModel.hpp wsd/Auth.cpp wsd/Auth.hpp wsd/ClientSession.cpp wsd/ClientSession.hpp ws d/DocumentBroker.cpp wsd/DocumentBroker.hpp wsd/Exceptions.hpp wsd/FileServer.cpp wsd/FileServer.hpp wsd/LOOLWSD.cpp wsd/LOOLWSD.hpp wsd/metrics.txt wsd/ProofKey.cpp wsd/ProofKey.hpp wsd/protocol.txt wsd/ProxyProtocol.cpp wsd/ProxyProtocol.hpp wsd/QueueHandler.hpp wsd/SenderQueue.hpp wsd/Storage.hpp wsd/TileCache.hpp wsd/TileDesc.hpp wsd/TraceFile.hpp wsd/UserMessages.hpp
Michael Meeks (via logerrit)
logerrit at kemper.freedesktop.org
Sat Apr 18 16:48:40 UTC 2020
Rebased ref, commits from common ancestor:
commit c90bf00077d4091ca49c6ade6ffaf86d0603a0b3
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Tue Apr 14 17:01:41 2020 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 18 17:38:17 2020 +0100
Proof: improve debugging and connection handling.
Change-Id: I1d48c4ec7fb80eaab1aabc83b0c210b7cf138ef2
diff --git a/loleaflet/js/global.js b/loleaflet/js/global.js
index 2268af83f..17fe03c9a 100644
--- a/loleaflet/js/global.js
+++ b/loleaflet/js/global.js
@@ -260,7 +260,6 @@
this.sendQueue = '';
this.sendTimeout = undefined;
this.doSend = function () {
- that.sendTimeout = undefined;
console.debug('send msg "' + that.sendQueue + '"');
var req = new XMLHttpRequest();
req.open('POST', that.getEndPoint('write'));
@@ -279,6 +278,7 @@
}
req.send(that.sendQueue);
that.sendQueue = '';
+ that.sendTimeout = undefined;
};
this.getSessionId = function() {
var req = new XMLHttpRequest();
@@ -318,7 +318,7 @@
// horrors ...
this.waitConnect = function() {
console.debug('proxy: waiting - ' + that.readWaiting + ' on session ' + that.sessionId);
- if (that.readWaiting > 4) // max 4 waiting connections concurrently.
+ if (that.readWaiting >= 4) // max 4 waiting connections concurrently.
return;
if (that.sessionId == 'fetchsession')
return; // waiting for our session id.
diff --git a/net/Socket.cpp b/net/Socket.cpp
index 24041bc4b..0b7a2f2ff 100644
--- a/net/Socket.cpp
+++ b/net/Socket.cpp
@@ -219,7 +219,6 @@ int SocketPoll::poll(int64_t timeoutMaxMicroS)
timeout.tv_sec = timeoutMaxMicroS / (1000 * 1000);
timeout.tv_nsec = (timeoutMaxMicroS % (1000 * 1000)) * 1000;
rc = ::ppoll(&_pollFds[0], size + 1, &timeout, nullptr);
- LOG_TRC("ppoll result " << rc << " errno " << strerror(errno));
# else
int timeoutMaxMs = (timeoutMaxMicroS + 9999) / 1000;
LOG_TRC("Legacy Poll start, timeoutMs: " << timeoutMaxMs);
diff --git a/wsd/ProxyProtocol.cpp b/wsd/ProxyProtocol.cpp
index 3ed43e979..c8a259abe 100644
--- a/wsd/ProxyProtocol.cpp
+++ b/wsd/ProxyProtocol.cpp
@@ -219,6 +219,13 @@ void ProxyProtocolHandler::getIOStats(uint64_t &sent, uint64_t &recv)
void ProxyProtocolHandler::dumpState(std::ostream& os)
{
os << "proxy protocol sockets: " << _outSockets.size() << " writeQueue: " << _writeQueue.size() << ":\n";
+ os << "\t";
+ for (auto &it : _outSockets)
+ {
+ auto sock = it.lock();
+ os << "#" << (sock ? sock->getFD() : -2) << " ";
+ }
+ os << "\n";
for (auto it : _writeQueue)
Util::dumpHex(os, "\twrite queue entry:", "\t\t", *it);
if (_msgHandler)
commit 13a09ec86c013d53acab6b3ec6beff0b110e2c80
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Sat Mar 21 20:03:37 2020 +0000
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 18 17:38:17 2020 +0100
Proxy: don't leave out sockets lingering around for the !flush case.
Change-Id: I13ad123a6c3a068a676eae5e509367e727e9ac06
diff --git a/wsd/ProxyProtocol.cpp b/wsd/ProxyProtocol.cpp
index 89b3d9ba9..3ed43e979 100644
--- a/wsd/ProxyProtocol.cpp
+++ b/wsd/ProxyProtocol.cpp
@@ -181,11 +181,14 @@ void ProxyProtocolHandler::handleIncomingMessage(SocketDisposition &disposition)
int ProxyProtocolHandler::sendMessage(const char *msg, const size_t len, bool text, bool flush)
{
_writeQueue.push_back(std::make_shared<Message>(msg, len, text));
- auto sock = popOutSocket();
- if (sock && flush)
+ if (flush)
{
- flushQueueTo(sock);
- sock->shutdown();
+ auto sock = popOutSocket();
+ if (sock)
+ {
+ flushQueueTo(sock);
+ sock->shutdown();
+ }
}
return len;
commit e955a70b2db062fc20407171cba603468aad5390
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Sat Mar 21 15:07:10 2020 +0000
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 18 17:38:17 2020 +0100
Proxy: improve debugging & naming.
Change-Id: Ifba669a33855a67c9a4e968db42ef1a2cb301d63
diff --git a/loleaflet/js/global.js b/loleaflet/js/global.js
index c5dff015e..2268af83f 100644
--- a/loleaflet/js/global.js
+++ b/loleaflet/js/global.js
@@ -216,7 +216,7 @@
};
this.parseIncomingArray = function(arr) {
var decoder = new TextDecoder();
- console.debug('Parse incoming array of length ' + arr.length);
+ console.debug('proxy: parse incoming array of length ' + arr.length);
for (var i = 0; i < arr.length; ++i)
{
var left = arr.length - i;
@@ -274,7 +274,7 @@
if (this.status == 200)
that.parseIncomingArray(new Uint8Array(this.response));
else
- console.debug('Error on incoming response');
+ console.debug('proxy: error on incoming response');
});
}
req.send(that.sendQueue);
@@ -300,21 +300,24 @@
this.sendTimeout = setTimeout(this.doSend, 2 /* ms */);
};
this.close = function() {
- console.debug('close socket');
+ console.debug('proxy: close socket');
this.readyState = 3;
this.onclose();
+ clearInterval(this.waitInterval);
+ this.waitInterval = undefined;
};
this.getEndPoint = function(type) {
var base = this.uri;
return base.replace(/^ws/, 'http') + '/' + type;
};
- console.debug('New proxy socket ' + this.id + ' ' + this.uri);
+ console.debug('proxy: new socket ' + this.id + ' ' + this.uri);
// queue fetch of session id.
this.getSessionId();
// horrors ...
- this.readInterval = setInterval(function() {
+ this.waitConnect = function() {
+ console.debug('proxy: waiting - ' + that.readWaiting + ' on session ' + that.sessionId);
if (that.readWaiting > 4) // max 4 waiting connections concurrently.
return;
if (that.sessionId == 'fetchsession')
@@ -329,13 +332,16 @@
});
req.addEventListener('loadend', function() {
that.readWaiting--;
+ console.debug('proxy: wait ended, re-issue');
+ that.waitConnect();
});
- req.open('GET', that.getEndPoint('read'));
+ req.open('GET', that.getEndPoint('wait'));
req.setRequestHeader('SessionId', that.sessionId);
req.responseType = 'arraybuffer';
req.send('');
that.readWaiting++;
- }, 250);
+ };
+ this.waitInterval = setInterval(this.waitConnect, 250);
};
if (global.socketProxy)
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index badf0b05f..541640608 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -2911,7 +2911,7 @@ private:
none, url, docKey, _id, uriPublic);
std::string fullURL = request.getURI();
- std::string ending = "/ws/read";
+ std::string ending = "/ws/wait";
bool isWaiting = (fullURL.size() > ending.size() &&
std::equal(ending.rbegin(), ending.rend(), fullURL.rbegin()));
if (docBroker)
diff --git a/wsd/ProxyProtocol.cpp b/wsd/ProxyProtocol.cpp
index c8f578559..89b3d9ba9 100644
--- a/wsd/ProxyProtocol.cpp
+++ b/wsd/ProxyProtocol.cpp
@@ -31,7 +31,7 @@ void DocumentBroker::handleProxyRequest(
std::shared_ptr<ClientSession> clientSession;
if (sessionId == "fetchsession")
{
- LOG_TRC("Create session for " << _docKey);
+ LOG_TRC("proxy: Create session for " << _docKey);
clientSession = createNewClientSession(
std::make_shared<ProxyProtocolHandler>(),
id, uriPublic, isReadOnly, hostNoTrust);
@@ -39,7 +39,7 @@ void DocumentBroker::handleProxyRequest(
LOOLWSD::checkDiskSpaceAndWarnClients(true);
LOOLWSD::checkSessionLimitsAndWarnClients();
- LOG_TRC("Returning id " << clientSession->getId());
+ LOG_TRC("proxy: Returning sessionId " << clientSession->getId());
std::ostringstream oss;
oss << "HTTP/1.1 200 OK\r\n"
@@ -57,7 +57,7 @@ void DocumentBroker::handleProxyRequest(
}
else
{
- LOG_TRC("Find session for " << _docKey << " with id " << sessionId);
+ LOG_TRC("proxy: find session for " << _docKey << " with id " << sessionId);
for (const auto &it : _sessions)
{
if (it.second->getId() == sessionId)
@@ -133,28 +133,29 @@ void ProxyProtocolHandler::handleRequest(bool isWaiting, const std::shared_ptr<S
{
auto streamSocket = std::static_pointer_cast<StreamSocket>(socket);
- LOG_INF("Proxy handle request type: " << (isWaiting ? "wait" : "respond"));
+ LOG_INF("proxy: handle request type: " << (isWaiting ? "wait" : "respond") <<
+ " on socket #" << socket->getFD());
if (!isWaiting)
{
if (!_msgHandler)
- LOG_WRN("unusual - incoming message with no-one to handle it");
+ LOG_WRN("proxy: unusual - incoming message with no-one to handle it");
else if (!parseEmitIncoming(streamSocket))
{
std::stringstream oss;
streamSocket->dumpState(oss);
- LOG_ERR("bad socket structure " << oss.str());
+ LOG_ERR("proxy: bad socket structure " << oss.str());
}
}
if (!flushQueueTo(streamSocket) && isWaiting)
{
- LOG_TRC("Queue a waiting socket");
+ LOG_TRC("proxy: queue a waiting out socket #" << streamSocket->getFD());
// longer running 'write socket' (marked 'read' by the client)
_outSockets.push_back(streamSocket);
if (_outSockets.size() > 16)
{
- LOG_ERR("Unexpected - client opening many concurrent waiting connections " << _outSockets.size());
+ LOG_ERR("proxy: Unexpected - client opening many concurrent waiting connections " << _outSockets.size());
// cleanup older waiting sockets.
auto sockWeak = _outSockets.front();
_outSockets.erase(_outSockets.begin());
@@ -180,7 +181,7 @@ void ProxyProtocolHandler::handleIncomingMessage(SocketDisposition &disposition)
int ProxyProtocolHandler::sendMessage(const char *msg, const size_t len, bool text, bool flush)
{
_writeQueue.push_back(std::make_shared<Message>(msg, len, text));
- auto sock = popWriteSocket();
+ auto sock = popOutSocket();
if (sock && flush)
{
flushQueueTo(sock);
@@ -230,16 +231,24 @@ int ProxyProtocolHandler::getPollEvents(std::chrono::steady_clock::time_point /*
return events;
}
-void ProxyProtocolHandler::performWrites()
+/// slurp from the core to us, @returns true if there are messages to send
+bool ProxyProtocolHandler::slurpHasMessages()
{
- if (_msgHandler)
+ if (_msgHandler && _msgHandler->hasQueuedMessages())
_msgHandler->writeQueuedMessages();
- if (_writeQueue.size() <= 0)
+
+ return _writeQueue.size() > 0;
+}
+
+void ProxyProtocolHandler::performWrites()
+{
+ if (!slurpHasMessages())
return;
- auto sock = popWriteSocket();
+ auto sock = popOutSocket();
if (sock)
{
+ LOG_TRC("proxy: performWrites");
flushQueueTo(sock);
sock->shutdown();
}
@@ -247,9 +256,8 @@ void ProxyProtocolHandler::performWrites()
bool ProxyProtocolHandler::flushQueueTo(const std::shared_ptr<StreamSocket> &socket)
{
- // slurp from the core to us.
- if (_msgHandler && _msgHandler->hasQueuedMessages())
- _msgHandler->writeQueuedMessages();
+ if (!slurpHasMessages())
+ return false;
size_t totalSize = 0;
for (auto it : _writeQueue)
@@ -258,6 +266,8 @@ bool ProxyProtocolHandler::flushQueueTo(const std::shared_ptr<StreamSocket> &soc
if (!totalSize)
return false;
+ LOG_TRC("proxy: flushQueue of size " << totalSize << " to socket #" << socket->getFD() << " & close");
+
std::ostringstream oss;
oss << "HTTP/1.1 200 OK\r\n"
"Last-Modified: " << Util::getHttpTimeNow() << "\r\n"
@@ -276,7 +286,7 @@ bool ProxyProtocolHandler::flushQueueTo(const std::shared_ptr<StreamSocket> &soc
}
// LRU-ness ...
-std::shared_ptr<StreamSocket> ProxyProtocolHandler::popWriteSocket()
+std::shared_ptr<StreamSocket> ProxyProtocolHandler::popOutSocket()
{
std::weak_ptr<StreamSocket> sock;
while (!_outSockets.empty())
@@ -285,8 +295,12 @@ std::shared_ptr<StreamSocket> ProxyProtocolHandler::popWriteSocket()
_outSockets.erase(_outSockets.begin());
auto realSock = sock.lock();
if (realSock)
+ {
+ LOG_TRC("proxy: popped an out socket #" << realSock->getFD() << " leaving: " << _outSockets.size());
return realSock;
+ }
}
+ LOG_TRC("proxy: no out sockets to pop.");
return std::shared_ptr<StreamSocket>();
}
diff --git a/wsd/ProxyProtocol.hpp b/wsd/ProxyProtocol.hpp
index 090d4331e..692fd903c 100644
--- a/wsd/ProxyProtocol.hpp
+++ b/wsd/ProxyProtocol.hpp
@@ -60,7 +60,8 @@ public:
void handleRequest(bool isWaiting, const std::shared_ptr<Socket> &socket);
private:
- std::shared_ptr<StreamSocket> popWriteSocket();
+ std::shared_ptr<StreamSocket> popOutSocket();
+ bool slurpHasMessages();
int sendMessage(const char *msg, const size_t len, bool text, bool flush);
bool flushQueueTo(const std::shared_ptr<StreamSocket> &socket);
commit 2471f338ccff14d63a5d3af4edb2dd03fc55ca5b
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Sat Mar 21 14:27:15 2020 +0000
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 18 17:38:17 2020 +0100
Proxy: ensure dumpState dumps via the MessageHandlerInterface too.
Change-Id: If514e2359188d56bbf7ddef6e04f9d8bf5c50910
diff --git a/net/Socket.cpp b/net/Socket.cpp
index 372f9ea1a..24041bc4b 100644
--- a/net/Socket.cpp
+++ b/net/Socket.cpp
@@ -524,6 +524,8 @@ void WebSocketHandler::dumpState(std::ostream& os)
if (_wsPayload.size() > 0)
Util::dumpHex(os, "\t\tws queued payload:\n", "\t\t", _wsPayload);
os << "\n";
+ if (_msgHandler)
+ _msgHandler->dumpState(os);
}
void StreamSocket::dumpState(std::ostream& os)
diff --git a/wsd/ProxyProtocol.cpp b/wsd/ProxyProtocol.cpp
index 6279682f2..c8f578559 100644
--- a/wsd/ProxyProtocol.cpp
+++ b/wsd/ProxyProtocol.cpp
@@ -217,6 +217,8 @@ void ProxyProtocolHandler::dumpState(std::ostream& os)
os << "proxy protocol sockets: " << _outSockets.size() << " writeQueue: " << _writeQueue.size() << ":\n";
for (auto it : _writeQueue)
Util::dumpHex(os, "\twrite queue entry:", "\t\t", *it);
+ if (_msgHandler)
+ _msgHandler->dumpState(os);
}
int ProxyProtocolHandler::getPollEvents(std::chrono::steady_clock::time_point /* now */,
commit 134beda7984af0195b32bc4927274bc4fc453dd0
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Sat Mar 21 14:19:49 2020 +0000
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 18 17:38:17 2020 +0100
Proxy: make eslint happier.
Change-Id: I9ecec787a9a69633a015459eaf39d4b8bd5bb61d
diff --git a/loleaflet/js/global.js b/loleaflet/js/global.js
index babbd5f02..c5dff015e 100644
--- a/loleaflet/js/global.js
+++ b/loleaflet/js/global.js
@@ -1,4 +1,5 @@
/* -*- js-indent-level: 8 -*- */
+/* global Uint8Array */
(function (global) {
var ua = navigator.userAgent.toLowerCase(),
@@ -312,8 +313,6 @@
// queue fetch of session id.
this.getSessionId();
- var that = this;
-
// horrors ...
this.readInterval = setInterval(function() {
if (that.readWaiting > 4) // max 4 waiting connections concurrently.
commit 831b763474b581b7d398025e4fede0eb1dd6f262
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri Mar 20 20:45:38 2020 +0000
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 18 17:38:17 2020 +0100
Proxy: poll for output space if we need waking.
Change-Id: I18a5e71bd3342eea7992672d9be1f5518ea008e3
diff --git a/loleaflet/js/global.js b/loleaflet/js/global.js
index 146083d71..babbd5f02 100644
--- a/loleaflet/js/global.js
+++ b/loleaflet/js/global.js
@@ -215,6 +215,7 @@
};
this.parseIncomingArray = function(arr) {
var decoder = new TextDecoder();
+ console.debug('Parse incoming array of length ' + arr.length);
for (var i = 0; i < arr.length; ++i)
{
var left = arr.length - i;
diff --git a/wsd/ProxyProtocol.cpp b/wsd/ProxyProtocol.cpp
index 25602f146..6279682f2 100644
--- a/wsd/ProxyProtocol.cpp
+++ b/wsd/ProxyProtocol.cpp
@@ -219,6 +219,15 @@ void ProxyProtocolHandler::dumpState(std::ostream& os)
Util::dumpHex(os, "\twrite queue entry:", "\t\t", *it);
}
+int ProxyProtocolHandler::getPollEvents(std::chrono::steady_clock::time_point /* now */,
+ int64_t &/* timeoutMaxMs */)
+{
+ int events = POLLIN;
+ if (_msgHandler && _msgHandler->hasQueuedMessages())
+ events |= POLLOUT;
+ return events;
+}
+
void ProxyProtocolHandler::performWrites()
{
if (_msgHandler)
diff --git a/wsd/ProxyProtocol.hpp b/wsd/ProxyProtocol.hpp
index dda24328a..090d4331e 100644
--- a/wsd/ProxyProtocol.hpp
+++ b/wsd/ProxyProtocol.hpp
@@ -34,11 +34,7 @@ public:
void handleIncomingMessage(SocketDisposition &/* disposition */) override;
int getPollEvents(std::chrono::steady_clock::time_point /* now */,
- int &/* timeoutMaxMs */) override
- {
- // underlying buffer based polling is fine.
- return POLLIN;
- }
+ int64_t &/* timeoutMaxMs */) override;
void checkTimeout(std::chrono::steady_clock::time_point /* now */) override
{
commit 89db64728d453b313926724582ac848de26db950
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri Mar 20 20:15:08 2020 +0000
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 18 17:38:17 2020 +0100
Proxy: open four wait sockets concurrently.
Change-Id: I08b85677be528b7aa77272a8527c9bacf3f7c336
diff --git a/loleaflet/js/global.js b/loleaflet/js/global.js
index 28def7224..146083d71 100644
--- a/loleaflet/js/global.js
+++ b/loleaflet/js/global.js
@@ -206,7 +206,7 @@
this.sessionId = 'fetchsession';
this.id = window.proxySocketCounter++;
this.sendCounter = 0;
- this.readWaiting = false;
+ this.readWaiting = 0;
this.onclose = function() {
};
this.onerror = function() {
@@ -315,9 +315,9 @@
// horrors ...
this.readInterval = setInterval(function() {
- if (this.readWaiting) // one at a time for now
+ if (that.readWaiting > 4) // max 4 waiting connections concurrently.
return;
- if (this.sessionId == 'fetchsession')
+ if (that.sessionId == 'fetchsession')
return; // waiting for our session id.
var req = new XMLHttpRequest();
// fetch session id:
@@ -326,13 +326,15 @@
that.parseIncomingArray(new Uint8Array(this.response));
else
console.debug('Handle error ' + this.status);
- that.readWaiting = false;
+ });
+ req.addEventListener('loadend', function() {
+ that.readWaiting--;
});
req.open('GET', that.getEndPoint('read'));
req.setRequestHeader('SessionId', that.sessionId);
req.responseType = 'arraybuffer';
req.send('');
- that.readWaiting = true;
+ that.readWaiting++;
}, 250);
};
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index 4e854d3fb..6e265c3dc 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -147,7 +147,8 @@ public:
const Poco::URI& uriPublic,
const bool isReadOnly,
const std::string& hostNoTrust,
- const std::shared_ptr<StreamSocket> &socket);
+ const std::shared_ptr<StreamSocket> &socket,
+ bool isWaiting);
/// Thread safe termination of this broker if it has a lingering thread
void joinThread();
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index e07758269..badf0b05f 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -2909,11 +2909,16 @@ private:
// Request a kit process for this doc.
std::shared_ptr<DocumentBroker> docBroker = findOrCreateDocBroker(
none, url, docKey, _id, uriPublic);
+
+ std::string fullURL = request.getURI();
+ std::string ending = "/ws/read";
+ bool isWaiting = (fullURL.size() > ending.size() &&
+ std::equal(ending.rbegin(), ending.rend(), fullURL.rbegin()));
if (docBroker)
{
// need to move into the DocumentBroker context before doing session lookup / creation etc.
std::string id = _id;
- disposition.setMove([docBroker, id, uriPublic, isReadOnly, hostNoTrust, sessionId]
+ disposition.setMove([docBroker, id, uriPublic, isReadOnly, hostNoTrust, sessionId, isWaiting]
(const std::shared_ptr<Socket> &moveSocket)
{
LOG_TRC("Setting up docbroker thread for " << docBroker->getDocKey());
@@ -2923,7 +2928,8 @@ private:
// We no longer own this socket.
moveSocket->setThreadOwner(std::thread::id());
- docBroker->addCallback([docBroker, id, uriPublic, isReadOnly, hostNoTrust, sessionId, moveSocket]()
+ docBroker->addCallback([docBroker, id, uriPublic, isReadOnly, hostNoTrust,
+ sessionId, moveSocket, isWaiting]()
{
// Now inside the document broker thread ...
LOG_TRC("In the docbroker thread for " << docBroker->getDocKey());
@@ -2933,7 +2939,7 @@ private:
{
docBroker->handleProxyRequest(
sessionId, id, uriPublic, isReadOnly,
- hostNoTrust, streamSocket);
+ hostNoTrust, streamSocket, isWaiting);
return;
}
catch (const UnauthorizedRequestException& exc)
diff --git a/wsd/ProxyProtocol.cpp b/wsd/ProxyProtocol.cpp
index 8aaff0131..25602f146 100644
--- a/wsd/ProxyProtocol.cpp
+++ b/wsd/ProxyProtocol.cpp
@@ -25,7 +25,8 @@ void DocumentBroker::handleProxyRequest(
const Poco::URI& uriPublic,
const bool isReadOnly,
const std::string& hostNoTrust,
- const std::shared_ptr<StreamSocket> &socket)
+ const std::shared_ptr<StreamSocket> &socket,
+ bool isWaiting)
{
std::shared_ptr<ClientSession> clientSession;
if (sessionId == "fetchsession")
@@ -82,7 +83,7 @@ void DocumentBroker::handleProxyRequest(
auto proxy = std::static_pointer_cast<ProxyProtocolHandler>(
protocol);
- proxy->handleRequest(uriPublic.toString(), socket);
+ proxy->handleRequest(isWaiting, socket);
}
bool ProxyProtocolHandler::parseEmitIncoming(
@@ -128,16 +129,13 @@ bool ProxyProtocolHandler::parseEmitIncoming(
return true;
}
-void ProxyProtocolHandler::handleRequest(const std::string &uriPublic,
- const std::shared_ptr<Socket> &socket)
+void ProxyProtocolHandler::handleRequest(bool isWaiting, const std::shared_ptr<Socket> &socket)
{
auto streamSocket = std::static_pointer_cast<StreamSocket>(socket);
- bool bRead = uriPublic.find("/write") == std::string::npos;
- LOG_INF("Proxy handle request " << uriPublic << " type: " <<
- (bRead ? "read" : "write"));
+ LOG_INF("Proxy handle request type: " << (isWaiting ? "wait" : "respond"));
- if (bRead)
+ if (!isWaiting)
{
if (!_msgHandler)
LOG_WRN("unusual - incoming message with no-one to handle it");
@@ -149,13 +147,27 @@ void ProxyProtocolHandler::handleRequest(const std::string &uriPublic,
}
}
- if (!flushQueueTo(streamSocket) && !bRead)
+ if (!flushQueueTo(streamSocket) && isWaiting)
{
- // longer running 'write socket'
- _writeSockets.push_back(streamSocket);
+ LOG_TRC("Queue a waiting socket");
+ // longer running 'write socket' (marked 'read' by the client)
+ _outSockets.push_back(streamSocket);
+ if (_outSockets.size() > 16)
+ {
+ LOG_ERR("Unexpected - client opening many concurrent waiting connections " << _outSockets.size());
+ // cleanup older waiting sockets.
+ auto sockWeak = _outSockets.front();
+ _outSockets.erase(_outSockets.begin());
+ auto sock = sockWeak.lock();
+ if (sock)
+ sock->shutdown();
+ }
}
else
+ {
+ LOG_TRC("Return a reply immediately");
socket->shutdown();
+ }
}
void ProxyProtocolHandler::handleIncomingMessage(SocketDisposition &disposition)
@@ -202,7 +214,7 @@ void ProxyProtocolHandler::getIOStats(uint64_t &sent, uint64_t &recv)
void ProxyProtocolHandler::dumpState(std::ostream& os)
{
- os << "proxy protocol sockets: " << _writeSockets.size() << " writeQueue: " << _writeQueue.size() << ":\n";
+ os << "proxy protocol sockets: " << _outSockets.size() << " writeQueue: " << _writeQueue.size() << ":\n";
for (auto it : _writeQueue)
Util::dumpHex(os, "\twrite queue entry:", "\t\t", *it);
}
@@ -256,10 +268,10 @@ bool ProxyProtocolHandler::flushQueueTo(const std::shared_ptr<StreamSocket> &soc
std::shared_ptr<StreamSocket> ProxyProtocolHandler::popWriteSocket()
{
std::weak_ptr<StreamSocket> sock;
- while (!_writeSockets.empty())
+ while (!_outSockets.empty())
{
- sock = _writeSockets.front();
- _writeSockets.erase(_writeSockets.begin());
+ sock = _outSockets.front();
+ _outSockets.erase(_outSockets.begin());
auto realSock = sock.lock();
if (realSock)
return realSock;
diff --git a/wsd/ProxyProtocol.hpp b/wsd/ProxyProtocol.hpp
index 0b20900b1..dda24328a 100644
--- a/wsd/ProxyProtocol.hpp
+++ b/wsd/ProxyProtocol.hpp
@@ -60,11 +60,8 @@ public:
void shutdown(bool goingAway = false, const std::string &statusMessage = "") override;
void getIOStats(uint64_t &sent, uint64_t &recv) override;
void dumpState(std::ostream& os);
-
bool parseEmitIncoming(const std::shared_ptr<StreamSocket> &socket);
-
- void handleRequest(const std::string &uriPublic,
- const std::shared_ptr<Socket> &socket);
+ void handleRequest(bool isWaiting, const std::shared_ptr<Socket> &socket);
private:
std::shared_ptr<StreamSocket> popWriteSocket();
@@ -88,7 +85,7 @@ private:
};
/// queue things when we have no socket to hand.
std::vector<std::shared_ptr<Message>> _writeQueue;
- std::vector<std::weak_ptr<StreamSocket>> _writeSockets;
+ std::vector<std::weak_ptr<StreamSocket>> _outSockets;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 6c59f6af49dd3bf755daa4a8dfa38b54cc3c4249
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri Mar 20 19:05:48 2020 +0000
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 18 17:38:17 2020 +0100
Proxy: re-write css image URLs to handle the proxy.
Change-Id: I09f3dea2f5e3a51869d5b0aa3f473d8f3ba75f44
diff --git a/loleaflet/js/global.js b/loleaflet/js/global.js
index 0f773fbe6..28def7224 100644
--- a/loleaflet/js/global.js
+++ b/loleaflet/js/global.js
@@ -336,6 +336,33 @@
}, 250);
};
+ if (global.socketProxy)
+ {
+ // re-write relative URLs in CSS - somewhat grim.
+ window.addEventListener('load', function() {
+ var sheets = document.styleSheets;
+ for (var i = 0; i < sheets.length; ++i) {
+ var relBases = sheets[i].href.split('/');
+ relBases.pop(); // bin last - css name.
+ var replaceBase = 'url("' + relBases.join('/') + '/images/';
+
+ var rules = sheets[i].cssRules || sheets[i].rules;
+ for (var r = 0; r < rules.length; ++r) {
+ if (!rules[r] || !rules[r].style)
+ continue;
+ var img = rules[r].style.backgroundImage;
+ if (img === '' || img === undefined)
+ continue;
+ if (img.startsWith('url("images/'))
+ {
+ rules[r].style.backgroundImage =
+ img.replace('url("images/', replaceBase);
+ }
+ }
+ }
+ }, false);
+ }
+
global.createWebSocket = function(uri) {
if (global.socketProxy) {
return new global.ProxySocket(uri);
commit 15777d733aca9cb9c90a716130344aad1f967b38
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri Mar 20 16:38:14 2020 +0000
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 18 17:38:17 2020 +0100
Proxy: send multiple messages in a single request.
Change-Id: Ic0a303979478801bd23941e8893ce5721cf3e732
diff --git a/loleaflet/js/global.js b/loleaflet/js/global.js
index d0d1f6ad6..0f773fbe6 100644
--- a/loleaflet/js/global.js
+++ b/loleaflet/js/global.js
@@ -195,6 +195,7 @@
global.proxySocketCounter = 0;
global.ProxySocket = function (uri) {
+ var that = this;
this.uri = uri;
this.binaryType = 'arraybuffer';
this.bufferedAmount = 0;
@@ -254,56 +255,48 @@
i += size; // skip trailing '\n' in loop-increment
}
};
- this.parseIncoming = function(type, msg) {
- if (type === 'blob')
- {
- var fileReader = new FileReader();
- var that = this;
- fileReader.onload = function(event) {
- that.parseIncomingArray(event.target.result);
- };
- fileReader.readAsArrayBuffer(msg);
- }
- else if (type === 'arraybuffer')
- {
- this.parseIncomingArray(new Uint8Array(msg));
- }
- else if (type === 'text' || type === '')
- {
- const encoder = new TextEncoder()
- const arr = encoder.encode(msg);
- this.parseIncomingArray(arr);
- }
- else
- console.debug('Unknown encoding type: ' + type);
- };
- this.send = function(msg) {
- console.debug('send msg "' + msg + '"');
+ this.sendQueue = '';
+ this.sendTimeout = undefined;
+ this.doSend = function () {
+ that.sendTimeout = undefined;
+ console.debug('send msg "' + that.sendQueue + '"');
var req = new XMLHttpRequest();
- req.open('POST', this.getEndPoint('write'));
- req.setRequestHeader('SessionId', this.sessionId);
- if (this.sessionId === 'fetchsession')
- {
- req.responseType = 'text';
- req.addEventListener('load', function() {
- console.debug('got session: ' + this.responseText);
- that.sessionId = this.responseText;
- that.readyState = 1;
- that.onopen();
- });
- }
+ req.open('POST', that.getEndPoint('write'));
+ req.setRequestHeader('SessionId', that.sessionId);
+ if (that.sessionId === 'fetchsession')
+ console.debug('session fetch not completed');
else
{
req.responseType = 'arraybuffer';
req.addEventListener('load', function() {
if (this.status == 200)
- that.parseIncoming(this.responseType, this.response);
+ that.parseIncomingArray(new Uint8Array(this.response));
else
console.debug('Error on incoming response');
});
}
- req.send('B0x' + msg.length.toString(16) + '\n' + msg + '\n');
- },
+ req.send(that.sendQueue);
+ that.sendQueue = '';
+ };
+ this.getSessionId = function() {
+ var req = new XMLHttpRequest();
+ req.open('POST', that.getEndPoint('write'));
+ req.setRequestHeader('SessionId', that.sessionId);
+ req.responseType = 'text';
+ req.addEventListener('load', function() {
+ console.debug('got session: ' + this.responseText);
+ that.sessionId = this.responseText;
+ that.readyState = 1;
+ that.onopen();
+ });
+ req.send('');
+ };
+ this.send = function(msg) {
+ this.sendQueue = this.sendQueue.concat(
+ 'B0x' + msg.length.toString(16) + '\n' + msg + '\n');
+ if (this.sessionId !== 'fetchsession' && this.sendTimeout === undefined)
+ this.sendTimeout = setTimeout(this.doSend, 2 /* ms */);
+ };
this.close = function() {
console.debug('close socket');
this.readyState = 3;
@@ -315,7 +308,9 @@
};
console.debug('New proxy socket ' + this.id + ' ' + this.uri);
- this.send('fetchsession');
+ // queue fetch of session id.
+ this.getSessionId();
+
var that = this;
// horrors ...
@@ -328,7 +323,7 @@
// fetch session id:
req.addEventListener('load', function() {
if (this.status == 200)
- that.parseIncoming(this.responseType, this.response);
+ that.parseIncomingArray(new Uint8Array(this.response));
else
console.debug('Handle error ' + this.status);
that.readWaiting = false;
commit 68f1017717d95ff050a066da13bf232c77c41499
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Thu Mar 19 15:54:28 2020 +0000
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 18 17:38:17 2020 +0100
Proxy protocol bits.
For now very silly: [T|B] + hex length + \n + content + \n
Change-Id: I256b834a23cca975a705da2c569887665ac6be02
diff --git a/loleaflet/js/global.js b/loleaflet/js/global.js
index 3becdd706..d0d1f6ad6 100644
--- a/loleaflet/js/global.js
+++ b/loleaflet/js/global.js
@@ -212,19 +212,97 @@
};
this.onmessage = function() {
};
+ this.parseIncomingArray = function(arr) {
+ var decoder = new TextDecoder();
+ for (var i = 0; i < arr.length; ++i)
+ {
+ var left = arr.length - i;
+ if (left < 4)
+ {
+ console.debug('no data left');
+ break;
+ }
+ var type = String.fromCharCode(arr[i+0]);
+ if (type != 'T' && type != 'B')
+ {
+ console.debug('wrong data type: ' + type);
+ break;
+ }
+ if (arr[i+1] !== 48 && arr[i+2] !== 120) // '0x'
+ {
+ console.debug('missing hex preamble');
+ break;
+ }
+ i += 3;
+ var numStr = '';
+ var start = i;
+ while (arr[i] != 10) // '\n'
+ i++;
+ numStr = decoder.decode(arr.slice(start, i)); // FIXME: IE11
+ var size = parseInt(numStr, 16);
+
+ i++; // skip \n
+
+ var data;
+ if (type == 'T') // FIXME: IE11
+ data = decoder.decode(arr.slice(i, i + size));
+ else
+ data = arr.slice(i, i + size);
+
+ this.onmessage({ data: data });
+
+ i += size; // skip trailing '\n' in loop-increment
+ }
+ };
+ this.parseIncoming = function(type, msg) {
+ if (type === 'blob')
+ {
+ var fileReader = new FileReader();
+ var that = this;
+ fileReader.onload = function(event) {
+ that.parseIncomingArray(event.target.result);
+ };
+ fileReader.readAsArrayBuffer(msg);
+ }
+ else if (type === 'arraybuffer')
+ {
+ this.parseIncomingArray(new Uint8Array(msg));
+ }
+ else if (type === 'text' || type === '')
+ {
+ const encoder = new TextEncoder()
+ const arr = encoder.encode(msg);
+ this.parseIncomingArray(arr);
+ }
+ else
+ console.debug('Unknown encoding type: ' + type);
+ };
this.send = function(msg) {
console.debug('send msg "' + msg + '"');
var req = new XMLHttpRequest();
req.open('POST', this.getEndPoint('write'));
req.setRequestHeader('SessionId', this.sessionId);
if (this.sessionId === 'fetchsession')
+ {
+ req.responseType = 'text';
req.addEventListener('load', function() {
console.debug('got session: ' + this.responseText);
that.sessionId = this.responseText;
that.readyState = 1;
that.onopen();
});
- req.send(msg);
+ }
+ else
+ {
+ req.responseType = 'arraybuffer';
+ req.addEventListener('load', function() {
+ if (this.status == 200)
+ that.parseIncoming(this.responseType, this.response);
+ else
+ console.debug('Error on incoming response');
+ });
+ }
+ req.send('B0x' + msg.length.toString(16) + '\n' + msg + '\n');
},
this.close = function() {
console.debug('close socket');
@@ -237,7 +315,6 @@
};
console.debug('New proxy socket ' + this.id + ' ' + this.uri);
- // FIXME: perhaps a little risky.
this.send('fetchsession');
var that = this;
@@ -250,20 +327,16 @@
var req = new XMLHttpRequest();
// fetch session id:
req.addEventListener('load', function() {
- console.debug('read: ' + this.responseText);
if (this.status == 200)
- {
- that.onmessage({ data: this.response });
- }
+ that.parseIncoming(this.responseType, this.response);
else
- {
console.debug('Handle error ' + this.status);
- }
that.readWaiting = false;
});
req.open('GET', that.getEndPoint('read'));
- req.setRequestHeader('SessionId', this.sessionId);
- req.send(that.sessionId);
+ req.setRequestHeader('SessionId', that.sessionId);
+ req.responseType = 'arraybuffer';
+ req.send('');
that.readWaiting = true;
}, 250);
};
diff --git a/net/Socket.hpp b/net/Socket.hpp
index f98e53dbb..07895d0bf 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -85,6 +85,10 @@ public:
{
_disposition = Type::CLOSED;
}
+ std::shared_ptr<Socket> getSocket() const
+ {
+ return _socket;
+ }
bool isMove() { return _disposition == Type::MOVE; }
bool isClosed() { return _disposition == Type::CLOSED; }
@@ -923,6 +927,12 @@ public:
std::vector<std::pair<size_t, size_t>> _spans;
};
+ /// remove all queued input bytes
+ void clearInput()
+ {
+ _inBuffer.clear();
+ }
+
/// Remove the first @count bytes from input buffer
void eraseFirstInputBytes(const MessageMap &map)
{
@@ -1086,6 +1096,8 @@ public:
/// Does it look like we have some TLS / SSL where we don't expect it ?
bool sniffSSL() const;
+ void dumpState(std::ostream& os) override;
+
protected:
/// Override to handle reading of socket data differently.
virtual int readData(char* buf, int len)
@@ -1109,8 +1121,6 @@ protected:
#endif
}
- void dumpState(std::ostream& os) override;
-
void setShutdownSignalled(bool shutdownSignalled)
{
_shutdownSignalled = shutdownSignalled;
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index 7d7b5e67d..4e854d3fb 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -147,7 +147,7 @@ public:
const Poco::URI& uriPublic,
const bool isReadOnly,
const std::string& hostNoTrust,
- const std::shared_ptr<Socket> &moveSocket);
+ const std::shared_ptr<StreamSocket> &socket);
/// Thread safe termination of this broker if it has a lingering thread
void joinThread();
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 6d5c39238..e07758269 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -2933,7 +2933,7 @@ private:
{
docBroker->handleProxyRequest(
sessionId, id, uriPublic, isReadOnly,
- hostNoTrust, moveSocket);
+ hostNoTrust, streamSocket);
return;
}
catch (const UnauthorizedRequestException& exc)
diff --git a/wsd/ProxyProtocol.cpp b/wsd/ProxyProtocol.cpp
index 41043a57a..8aaff0131 100644
--- a/wsd/ProxyProtocol.cpp
+++ b/wsd/ProxyProtocol.cpp
@@ -25,7 +25,7 @@ void DocumentBroker::handleProxyRequest(
const Poco::URI& uriPublic,
const bool isReadOnly,
const std::string& hostNoTrust,
- const std::shared_ptr<Socket> &socket)
+ const std::shared_ptr<StreamSocket> &socket)
{
std::shared_ptr<ClientSession> clientSession;
if (sessionId == "fetchsession")
@@ -37,6 +37,22 @@ void DocumentBroker::handleProxyRequest(
addSession(clientSession);
LOOLWSD::checkDiskSpaceAndWarnClients(true);
LOOLWSD::checkSessionLimitsAndWarnClients();
+
+ LOG_TRC("Returning id " << clientSession->getId());
+
+ std::ostringstream oss;
+ oss << "HTTP/1.1 200 OK\r\n"
+ "Last-Modified: " << Util::getHttpTimeNow() << "\r\n"
+ "User-Agent: " WOPI_AGENT_STRING "\r\n"
+ "Content-Length: " << clientSession->getId().size() << "\r\n"
+ "Content-Type: application/json\r\n"
+ "X-Content-Type-Options: nosniff\r\n"
+ "\r\n"
+ << clientSession->getId();
+
+ socket->send(oss.str());
+ socket->shutdown();
+ return;
}
else
{
@@ -69,13 +85,186 @@ void DocumentBroker::handleProxyRequest(
proxy->handleRequest(uriPublic.toString(), socket);
}
+bool ProxyProtocolHandler::parseEmitIncoming(
+ const std::shared_ptr<StreamSocket> &socket)
+{
+ std::vector<char> &in = socket->getInBuffer();
+
+ std::stringstream oss;
+ socket->dumpState(oss);
+ LOG_TRC("Parse message:\n" << oss.str());
+
+ while (in.size() > 0)
+ {
+ if (in[0] != 'T' && in[0] != 'B')
+ {
+ LOG_ERR("Invalid message type " << in[0]);
+ return false;
+ }
+ auto it = in.begin() + 1;
+ for (; it != in.end() && *it != '\n'; ++it);
+ *it = '\0';
+ uint64_t len = strtoll( &in[1], nullptr, 16 );
+ in.erase(in.begin(), it + 1);
+ if (len > in.size())
+ {
+ LOG_ERR("Invalid message length " << len << " vs " << in.size());
+ return false;
+ }
+ // far from efficient:
+ std::vector<char> data;
+ data.insert(data.begin(), in.begin(), in.begin() + len + 1);
+ in.erase(in.begin(), in.begin() + len);
+
+ if (in.size() < 1 || in[0] != '\n')
+ {
+ LOG_ERR("Missing final newline");
+ return false;
+ }
+ in.erase(in.begin(), in.begin() + 1);
+
+ _msgHandler->handleMessage(data);
+ }
+ return true;
+}
+
void ProxyProtocolHandler::handleRequest(const std::string &uriPublic,
const std::shared_ptr<Socket> &socket)
{
+ auto streamSocket = std::static_pointer_cast<StreamSocket>(socket);
+
bool bRead = uriPublic.find("/write") == std::string::npos;
LOG_INF("Proxy handle request " << uriPublic << " type: " <<
(bRead ? "read" : "write"));
- (void)socket;
+
+ if (bRead)
+ {
+ if (!_msgHandler)
+ LOG_WRN("unusual - incoming message with no-one to handle it");
+ else if (!parseEmitIncoming(streamSocket))
+ {
+ std::stringstream oss;
+ streamSocket->dumpState(oss);
+ LOG_ERR("bad socket structure " << oss.str());
+ }
+ }
+
+ if (!flushQueueTo(streamSocket) && !bRead)
+ {
+ // longer running 'write socket'
+ _writeSockets.push_back(streamSocket);
+ }
+ else
+ socket->shutdown();
+}
+
+void ProxyProtocolHandler::handleIncomingMessage(SocketDisposition &disposition)
+{
+ std::stringstream oss;
+ disposition.getSocket()->dumpState(oss);
+ LOG_ERR("If you got here, it means we failed to parse this properly in handleRequest: " << oss.str());
+}
+
+int ProxyProtocolHandler::sendMessage(const char *msg, const size_t len, bool text, bool flush)
+{
+ _writeQueue.push_back(std::make_shared<Message>(msg, len, text));
+ auto sock = popWriteSocket();
+ if (sock && flush)
+ {
+ flushQueueTo(sock);
+ sock->shutdown();
+ }
+
+ return len;
+}
+
+int ProxyProtocolHandler::sendTextMessage(const char *msg, const size_t len, bool flush) const
+{
+ LOG_TRC("ProxyHack - send text msg " + std::string(msg, len));
+ return const_cast<ProxyProtocolHandler *>(this)->sendMessage(msg, len, true, flush);
+}
+
+int ProxyProtocolHandler::sendBinaryMessage(const char *data, const size_t len, bool flush) const
+{
+ LOG_TRC("ProxyHack - send binary msg len " << len);
+ return const_cast<ProxyProtocolHandler *>(this)->sendMessage(data, len, false, flush);
+}
+
+void ProxyProtocolHandler::shutdown(bool goingAway, const std::string &statusMessage)
+{
+ LOG_TRC("ProxyHack - shutdown " << goingAway << ": " << statusMessage);
+}
+
+void ProxyProtocolHandler::getIOStats(uint64_t &sent, uint64_t &recv)
+{
+ sent = recv = 0;
+}
+
+void ProxyProtocolHandler::dumpState(std::ostream& os)
+{
+ os << "proxy protocol sockets: " << _writeSockets.size() << " writeQueue: " << _writeQueue.size() << ":\n";
+ for (auto it : _writeQueue)
+ Util::dumpHex(os, "\twrite queue entry:", "\t\t", *it);
+}
+
+void ProxyProtocolHandler::performWrites()
+{
+ if (_msgHandler)
+ _msgHandler->writeQueuedMessages();
+ if (_writeQueue.size() <= 0)
+ return;
+
+ auto sock = popWriteSocket();
+ if (sock)
+ {
+ flushQueueTo(sock);
+ sock->shutdown();
+ }
+}
+
+bool ProxyProtocolHandler::flushQueueTo(const std::shared_ptr<StreamSocket> &socket)
+{
+ // slurp from the core to us.
+ if (_msgHandler && _msgHandler->hasQueuedMessages())
+ _msgHandler->writeQueuedMessages();
+
+ size_t totalSize = 0;
+ for (auto it : _writeQueue)
+ totalSize += it->size();
+
+ if (!totalSize)
+ return false;
+
+ std::ostringstream oss;
+ oss << "HTTP/1.1 200 OK\r\n"
+ "Last-Modified: " << Util::getHttpTimeNow() << "\r\n"
+ "User-Agent: " WOPI_AGENT_STRING "\r\n"
+ "Content-Length: " << totalSize << "\r\n"
+ "Content-Type: application/json\r\n"
+ "X-Content-Type-Options: nosniff\r\n"
+ "\r\n";
+ socket->send(oss.str());
+
+ for (auto it : _writeQueue)
+ socket->send(it->data(), it->size(), false);
+ _writeQueue.clear();
+
+ return true;
+}
+
+// LRU-ness ...
+std::shared_ptr<StreamSocket> ProxyProtocolHandler::popWriteSocket()
+{
+ std::weak_ptr<StreamSocket> sock;
+ while (!_writeSockets.empty())
+ {
+ sock = _writeSockets.front();
+ _writeSockets.erase(_writeSockets.begin());
+ auto realSock = sock.lock();
+ if (realSock)
+ return realSock;
+ }
+ return std::shared_ptr<StreamSocket>();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/wsd/ProxyProtocol.hpp b/wsd/ProxyProtocol.hpp
index bd6beac3d..0b20900b1 100644
--- a/wsd/ProxyProtocol.hpp
+++ b/wsd/ProxyProtocol.hpp
@@ -9,19 +9,21 @@
#pragma once
+#include <memory>
#include <net/Socket.hpp>
-/// Interface for building a websocket from this ...
+/**
+ * Implementation that builds a websocket like protocol from many
+ * individual proxied HTTP requests back to back.
+ *
+ * we use a trivial framing: <hex-length>\r\n<content>\r\n
+ */
class ProxyProtocolHandler : public ProtocolHandlerInterface
{
public:
- ProxyProtocolHandler()
- {
- }
+ ProxyProtocolHandler() { }
- virtual ~ProxyProtocolHandler()
- {
- }
+ virtual ~ProxyProtocolHandler() { }
/// Will be called exactly once by setHandler
void onConnect(const std::shared_ptr<StreamSocket>& /* socket */) override
@@ -29,10 +31,7 @@ public:
}
/// Called after successful socket reads.
- void handleIncomingMessage(SocketDisposition &/* disposition */) override
- {
- assert("we get our data a different way" && false);
- }
+ void handleIncomingMessage(SocketDisposition &/* disposition */) override;
int getPollEvents(std::chrono::steady_clock::time_point /* now */,
int &/* timeoutMaxMs */) override
@@ -45,9 +44,7 @@ public:
{
}
- void performWrites() override
- {
- }
+ void performWrites() override;
void onDisconnect() override
{
@@ -58,40 +55,40 @@ public:
/// Clear all external references
virtual void dispose() { _msgHandler.reset(); }
- int sendTextMessage(const char *msg, const size_t len, bool flush = false) const override
- {
- LOG_TRC("ProxyHack - send text msg " + std::string(msg, len));
- (void) flush;
- return len;
- }
+ int sendTextMessage(const char *msg, const size_t len, bool flush = false) const override;
+ int sendBinaryMessage(const char *data, const size_t len, bool flush = false) const override;
+ void shutdown(bool goingAway = false, const std::string &statusMessage = "") override;
+ void getIOStats(uint64_t &sent, uint64_t &recv) override;
+ void dumpState(std::ostream& os);
- int sendBinaryMessage(const char *data, const size_t len, bool flush = false) const override
- {
- (void) data; (void) flush;
- LOG_TRC("ProxyHack - send binary msg len " << len);
- return len;
- }
-
- void shutdown(bool goingAway = false, const std::string &statusMessage = "") override
- {
- LOG_TRC("ProxyHack - shutdown " << goingAway << ": " << statusMessage);
- }
-
- void getIOStats(uint64_t &sent, uint64_t &recv) override
- {
- sent = recv = 0;
- }
-
- void dumpState(std::ostream& os)
- {
- os << "proxy protocol\n";
- }
+ bool parseEmitIncoming(const std::shared_ptr<StreamSocket> &socket);
void handleRequest(const std::string &uriPublic,
const std::shared_ptr<Socket> &socket);
private:
- std::vector<std::weak_ptr<StreamSocket>> _sockets;
+ std::shared_ptr<StreamSocket> popWriteSocket();
+ int sendMessage(const char *msg, const size_t len, bool text, bool flush);
+ bool flushQueueTo(const std::shared_ptr<StreamSocket> &socket);
+
+ struct Message : public std::vector<char>
+ {
+ Message(const char *msg, const size_t len, bool text)
+ {
+ const char *type = text ? "T" : "B";
+ insert(end(), type, type + 1);
+ std::ostringstream os;
+ os << std::hex << "0x" << len << "\n";
+ std::string str = os.str();
+ insert(end(), str.c_str(), str.c_str() + str.size());
+ insert(end(), msg, msg + len);
+ const char *terminator = "\n";
+ insert(end(), terminator, terminator + 1);
+ }
+ };
+ /// queue things when we have no socket to hand.
+ std::vector<std::shared_ptr<Message>> _writeQueue;
+ std::vector<std::weak_ptr<StreamSocket>> _writeSockets;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit b75148c54b474127f853336ad0a7c66366f01c38
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Wed Mar 4 13:54:04 2020 +0000
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 18 17:38:16 2020 +0100
Proxy websocket prototype.
Try to read/write avoiding a websocket.
Change-Id: I382039fa88f1030a63df1e47f687df2ee5a6055b
diff --git a/Makefile.am b/Makefile.am
index ff7ad0b5f..b6cd106f4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -113,6 +113,7 @@ loolwsd_sources = common/Crypto.cpp \
wsd/AdminModel.cpp \
wsd/Auth.cpp \
wsd/DocumentBroker.cpp \
+ wsd/ProxyProtocol.cpp \
wsd/LOOLWSD.cpp \
wsd/ClientSession.cpp \
wsd/FileServer.cpp \
@@ -219,6 +220,7 @@ wsd_headers = wsd/Admin.hpp \
wsd/Auth.hpp \
wsd/ClientSession.hpp \
wsd/DocumentBroker.hpp \
+ wsd/ProxyProtocol.hpp \
wsd/Exceptions.hpp \
wsd/FileServer.hpp \
wsd/LOOLWSD.hpp \
diff --git a/loleaflet/js/global.js b/loleaflet/js/global.js
index 3022d94a3..3becdd706 100644
--- a/loleaflet/js/global.js
+++ b/loleaflet/js/global.js
@@ -185,16 +185,97 @@
};
this.onopen = function() {
};
+ this.close = function() {
+ };
};
-
- global.FakeWebSocket.prototype.close = function() {
- };
-
global.FakeWebSocket.prototype.send = function(data) {
this.sendCounter++;
window.postMobileMessage(data);
};
+ global.proxySocketCounter = 0;
+ global.ProxySocket = function (uri) {
+ this.uri = uri;
+ this.binaryType = 'arraybuffer';
+ this.bufferedAmount = 0;
+ this.extensions = '';
+ this.protocol = '';
+ this.connected = true;
+ this.readyState = 0; // connecting
+ this.sessionId = 'fetchsession';
+ this.id = window.proxySocketCounter++;
+ this.sendCounter = 0;
+ this.readWaiting = false;
+ this.onclose = function() {
+ };
+ this.onerror = function() {
+ };
+ this.onmessage = function() {
+ };
+ this.send = function(msg) {
+ console.debug('send msg "' + msg + '"');
+ var req = new XMLHttpRequest();
+ req.open('POST', this.getEndPoint('write'));
+ req.setRequestHeader('SessionId', this.sessionId);
+ if (this.sessionId === 'fetchsession')
+ req.addEventListener('load', function() {
+ console.debug('got session: ' + this.responseText);
+ that.sessionId = this.responseText;
+ that.readyState = 1;
+ that.onopen();
+ });
+ req.send(msg);
+ },
+ this.close = function() {
+ console.debug('close socket');
+ this.readyState = 3;
+ this.onclose();
+ };
+ this.getEndPoint = function(type) {
+ var base = this.uri;
+ return base.replace(/^ws/, 'http') + '/' + type;
+ };
+ console.debug('New proxy socket ' + this.id + ' ' + this.uri);
+
+ // FIXME: perhaps a little risky.
+ this.send('fetchsession');
+ var that = this;
+
+ // horrors ...
+ this.readInterval = setInterval(function() {
+ if (this.readWaiting) // one at a time for now
+ return;
+ if (this.sessionId == 'fetchsession')
+ return; // waiting for our session id.
+ var req = new XMLHttpRequest();
+ // fetch session id:
+ req.addEventListener('load', function() {
+ console.debug('read: ' + this.responseText);
+ if (this.status == 200)
+ {
+ that.onmessage({ data: this.response });
+ }
+ else
+ {
+ console.debug('Handle error ' + this.status);
+ }
+ that.readWaiting = false;
+ });
+ req.open('GET', that.getEndPoint('read'));
+ req.setRequestHeader('SessionId', this.sessionId);
+ req.send(that.sessionId);
+ that.readWaiting = true;
+ }, 250);
+ };
+
+ global.createWebSocket = function(uri) {
+ if (global.socketProxy) {
+ return new global.ProxySocket(uri);
+ } else {
+ return new WebSocket(uri);
+ }
+ };
+
// If not debug, don't print anything on the console
// except in tile debug mode (Ctrl-Shift-Alt-d)
console.log2 = console.log;
@@ -219,7 +300,8 @@
window.postMobileError(log);
} else if (global.socket && (global.socket instanceof WebSocket) && global.socket.readyState === 1) {
global.socket.send(log);
- } else if (global.socket && (global.socket instanceof global.L.Socket) && global.socket.connected()) {
+ } else if (global.socket && global.L && global.L.Socket &&
+ (global.socket instanceof global.L.Socket) && global.socket.connected()) {
global.socket.sendMessage(log);
} else {
var req = new XMLHttpRequest();
@@ -294,7 +376,7 @@
var websocketURI = global.host + global.serviceRoot + '/lool/' + encodeURIComponent(global.docURL + (docParams ? '?' + docParams : '')) + '/ws' + wopiSrc;
try {
- global.socket = new WebSocket(websocketURI);
+ global.socket = global.createWebSocket(websocketURI);
} catch (err) {
console.log(err);
}
diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js
index a4aa948c5..fdd0b2db6 100644
--- a/loleaflet/src/core/Socket.js
+++ b/loleaflet/src/core/Socket.js
@@ -49,7 +49,7 @@ L.Socket = L.Class.extend({
}
try {
- this.socket = new WebSocket(this.getWebSocketBaseURI(map) + wopiSrc);
+ this.socket = window.createWebSocket(this.getWebSocketBaseURI(map) + wopiSrc);
} catch (e) {
// On IE 11 there is a limitation on the number of WebSockets open to a single domain (6 by default and can go to 128).
// Detect this and hint the user.
diff --git a/net/Socket.hpp b/net/Socket.hpp
index 5155a7bc8..f98e53dbb 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -445,6 +445,11 @@ public:
}
}
+ std::shared_ptr<ProtocolHandlerInterface> getProtocol() const
+ {
+ return _protocol;
+ }
+
/// Do we have something to send ?
virtual bool hasQueuedMessages() const = 0;
/// Please send them to me then.
diff --git a/wsd/ClientSession.hpp b/wsd/ClientSession.hpp
index 0f425b117..f2bd63adc 100644
--- a/wsd/ClientSession.hpp
+++ b/wsd/ClientSession.hpp
@@ -37,9 +37,6 @@ public:
void construct();
virtual ~ClientSession();
- /// Lookup any session by id.
- static std::shared_ptr<ClientSession> getById(const std::string &id);
-
void setReadOnly() override;
enum SessionState {
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index 329bece7f..7d7b5e67d 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -140,6 +140,15 @@ public:
const bool isReadOnly,
const std::string& hostNoTrust);
+ /// Find or create a new client session for the PHP proxy
+ void handleProxyRequest(
+ const std::string& sessionId,
+ const std::string& id,
+ const Poco::URI& uriPublic,
+ const bool isReadOnly,
+ const std::string& hostNoTrust,
+ const std::shared_ptr<Socket> &moveSocket);
+
/// Thread safe termination of this broker if it has a lingering thread
void joinThread();
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 9ab86355a..6d5c39238 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -236,6 +236,9 @@ namespace
#if ENABLE_SUPPORT_KEY
inline void shutdownLimitReached(const std::shared_ptr<ProtocolHandlerInterface>& proto)
{
+ if (!proto)
+ return;
+
const std::string error = Poco::format(PAYLOAD_UNAVAILABLE_LIMIT_REACHED, LOOLWSD::MaxDocuments, LOOLWSD::MaxConnections);
LOG_INF("Sending client 'hardlimitreached' message: " << error);
@@ -1828,9 +1831,12 @@ static std::shared_ptr<DocumentBroker>
if (docBroker->isMarkedToDestroy())
{
LOG_WRN("DocBroker with docKey [" << docKey << "] that is marked to be destroyed. Rejecting client request.");
- std::string msg("error: cmd=load kind=docunloading");
- proto->sendTextMessage(msg.data(), msg.size());
- proto->shutdown(true, "error: cmd=load kind=docunloading");
+ if (proto)
+ {
+ std::string msg("error: cmd=load kind=docunloading");
+ proto->sendTextMessage(msg.data(), msg.size());
+ proto->shutdown(true, "error: cmd=load kind=docunloading");
+ }
return nullptr;
}
}
@@ -1846,9 +1852,12 @@ static std::shared_ptr<DocumentBroker>
}
// Indicate to the client that we're connecting to the docbroker.
- const std::string statusConnect = "statusindicator: connect";
- LOG_TRC("Sending to Client [" << statusConnect << "].");
- proto->sendTextMessage(statusConnect.data(), statusConnect.size());
+ if (proto)
+ {
+ const std::string statusConnect = "statusindicator: connect";
+ LOG_TRC("Sending to Client [" << statusConnect << "].");
+ proto->sendTextMessage(statusConnect.data(), statusConnect.size());
+ }
if (!docBroker)
{
@@ -2320,6 +2329,13 @@ private:
// Util::dumpHex(std::cerr, "clipboard:\n", "", socket->getInBuffer()); // lots of data ...
handleClipboardRequest(request, message, disposition);
}
+ else if (request.has("ProxyPrefix") && reqPathTokens.count() > 2 &&
+ (reqPathTokens[reqPathTokens.count()-2] == "ws"))
+ {
+ std::string decodedUri; // WOPISrc
+ Poco::URI::decode(reqPathTokens[1], decodedUri);
+ handleClientProxyRequest(request, decodedUri, message, disposition);
+ }
else if (!(request.find("Upgrade") != request.end() && Poco::icompare(request["Upgrade"], "websocket") == 0) &&
reqPathTokens.count() > 0 && reqPathTokens[0] == "lool")
{
@@ -2853,6 +2869,99 @@ private:
}
#endif
+ void handleClientProxyRequest(const Poco::Net::HTTPRequest& request,
+ std::string url,
+ Poco::MemoryInputStream& message,
+ SocketDisposition &disposition)
+ {
+ if (!request.has("SessionId"))
+ throw BadRequestException("No session id header on proxied request");
+
+ std::string sessionId = request.get("SessionId");
+
+ LOG_INF("URL [" << url << "].");
+ const auto uriPublic = DocumentBroker::sanitizeURI(url);
+ LOG_INF("URI [" << uriPublic.getPath() << "].");
+ const auto docKey = DocumentBroker::getDocKey(uriPublic);
+ LOG_INF("DocKey [" << docKey << "].");
+ const std::string fileId = Util::getFilenameFromURL(docKey);
+ Util::mapAnonymized(fileId, fileId); // Identity mapping, since fileId is already obfuscated
+
+ LOG_INF("Starting Proxy request handler for session [" << _id << "] on url [" << LOOLWSD::anonymizeUrl(url) << "].");
+
+ // Check if readonly session is required
+ bool isReadOnly = false;
+ for (const auto& param : uriPublic.getQueryParameters())
+ {
+ LOG_DBG("Query param: " << param.first << ", value: " << param.second);
+ if (param.first == "permission" && param.second == "readonly")
+ {
+ isReadOnly = true;
+ }
+ }
+
+ const std::string hostNoTrust = (LOOLWSD::ServerName.empty() ? request.getHost() : LOOLWSD::ServerName);
+
+ LOG_INF("URL [" << LOOLWSD::anonymizeUrl(url) << "] is " << (isReadOnly ? "readonly" : "writable") << ".");
+ (void)request; (void)message; (void)disposition;
+
+ std::shared_ptr<ProtocolHandlerInterface> none;
+ // Request a kit process for this doc.
+ std::shared_ptr<DocumentBroker> docBroker = findOrCreateDocBroker(
+ none, url, docKey, _id, uriPublic);
+ if (docBroker)
+ {
+ // need to move into the DocumentBroker context before doing session lookup / creation etc.
+ std::string id = _id;
+ disposition.setMove([docBroker, id, uriPublic, isReadOnly, hostNoTrust, sessionId]
+ (const std::shared_ptr<Socket> &moveSocket)
+ {
+ LOG_TRC("Setting up docbroker thread for " << docBroker->getDocKey());
+ // Make sure the thread is running before adding callback.
+ docBroker->startThread();
+
+ // We no longer own this socket.
+ moveSocket->setThreadOwner(std::thread::id());
+
+ docBroker->addCallback([docBroker, id, uriPublic, isReadOnly, hostNoTrust, sessionId, moveSocket]()
+ {
+ // Now inside the document broker thread ...
+ LOG_TRC("In the docbroker thread for " << docBroker->getDocKey());
+
+ auto streamSocket = std::static_pointer_cast<StreamSocket>(moveSocket);
+ try
+ {
+ docBroker->handleProxyRequest(
+ sessionId, id, uriPublic, isReadOnly,
+ hostNoTrust, moveSocket);
+ return;
+ }
+ catch (const UnauthorizedRequestException& exc)
+ {
+ LOG_ERR("Unauthorized Request while loading session for " << docBroker->getDocKey() << ": " << exc.what());
+ }
+ catch (const StorageConnectionException& exc)
+ {
+ LOG_ERR("Error while loading : " << exc.what());
+ }
+ catch (const std::exception& exc)
+ {
+ LOG_ERR("Error while loading : " << exc.what());
+ }
+ // badness occured:
+ std::ostringstream oss;
+ oss << "HTTP/1.1 400\r\n"
+ << "Date: " << Util::getHttpTimeNow() << "\r\n"
+ << "User-Agent: LOOLWSD WOPI Agent\r\n"
+ << "Content-Length: 0\r\n"
+ << "\r\n";
+ streamSocket->send(oss.str());
+ streamSocket->shutdown();
+ });
+ });
+ }
+ }
+
void handleClientWsUpgrade(const Poco::Net::HTTPRequest& request, const std::string& url,
SocketDisposition &disposition)
{
@@ -2915,7 +3024,7 @@ private:
// Request a kit process for this doc.
std::shared_ptr<DocumentBroker> docBroker = findOrCreateDocBroker(
std::static_pointer_cast<ProtocolHandlerInterface>(ws), url, docKey, _id, uriPublic);
- if (docBroker)
+ if (docBroker)
{
#if MOBILEAPP
const std::string hostNoTrust;
diff --git a/wsd/ProxyProtocol.cpp b/wsd/ProxyProtocol.cpp
new file mode 100644
index 000000000..41043a57a
--- /dev/null
+++ b/wsd/ProxyProtocol.cpp
@@ -0,0 +1,81 @@
+/* -*- 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 <config.h>
+
+#include "DocumentBroker.hpp"
+#include "ClientSession.hpp"
+#include "ProxyProtocol.hpp"
+#include "Exceptions.hpp"
+#include "LOOLWSD.hpp"
+#include <Socket.hpp>
+
+#include <atomic>
+#include <cassert>
+
+void DocumentBroker::handleProxyRequest(
+ const std::string& sessionId,
+ const std::string& id,
+ const Poco::URI& uriPublic,
+ const bool isReadOnly,
+ const std::string& hostNoTrust,
+ const std::shared_ptr<Socket> &socket)
+{
+ std::shared_ptr<ClientSession> clientSession;
+ if (sessionId == "fetchsession")
+ {
+ LOG_TRC("Create session for " << _docKey);
+ clientSession = createNewClientSession(
+ std::make_shared<ProxyProtocolHandler>(),
+ id, uriPublic, isReadOnly, hostNoTrust);
+ addSession(clientSession);
+ LOOLWSD::checkDiskSpaceAndWarnClients(true);
+ LOOLWSD::checkSessionLimitsAndWarnClients();
+ }
+ else
+ {
+ LOG_TRC("Find session for " << _docKey << " with id " << sessionId);
+ for (const auto &it : _sessions)
+ {
+ if (it.second->getId() == sessionId)
+ {
+ clientSession = it.second;
+ break;
+ }
+ }
+ if (!clientSession)
+ {
+ LOG_ERR("Invalid session id used " << sessionId);
+ throw BadRequestException("invalid session id");
+ }
+ }
+
+ auto protocol = clientSession->getProtocol();
+ auto streamSocket = std::static_pointer_cast<StreamSocket>(socket);
+ streamSocket->setHandler(protocol);
+
+ // this DocumentBroker's poll handles reading & writing
+ addSocketToPoll(socket);
+
+ auto proxy = std::static_pointer_cast<ProxyProtocolHandler>(
+ protocol);
+
+ proxy->handleRequest(uriPublic.toString(), socket);
+}
+
+void ProxyProtocolHandler::handleRequest(const std::string &uriPublic,
+ const std::shared_ptr<Socket> &socket)
+{
+ bool bRead = uriPublic.find("/write") == std::string::npos;
+ LOG_INF("Proxy handle request " << uriPublic << " type: " <<
+ (bRead ? "read" : "write"));
+ (void)socket;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/wsd/ProxyProtocol.hpp b/wsd/ProxyProtocol.hpp
new file mode 100644
index 000000000..bd6beac3d
--- /dev/null
+++ b/wsd/ProxyProtocol.hpp
@@ -0,0 +1,97 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+#include <net/Socket.hpp>
+
+/// Interface for building a websocket from this ...
+class ProxyProtocolHandler : public ProtocolHandlerInterface
+{
+public:
+ ProxyProtocolHandler()
+ {
+ }
+
+ virtual ~ProxyProtocolHandler()
+ {
+ }
+
+ /// Will be called exactly once by setHandler
+ void onConnect(const std::shared_ptr<StreamSocket>& /* socket */) override
+ {
+ }
+
+ /// Called after successful socket reads.
+ void handleIncomingMessage(SocketDisposition &/* disposition */) override
+ {
+ assert("we get our data a different way" && false);
+ }
+
+ int getPollEvents(std::chrono::steady_clock::time_point /* now */,
+ int &/* timeoutMaxMs */) override
+ {
+ // underlying buffer based polling is fine.
+ return POLLIN;
+ }
+
+ void checkTimeout(std::chrono::steady_clock::time_point /* now */) override
+ {
+ }
+
+ void performWrites() override
+ {
+ }
+
+ void onDisconnect() override
+ {
+ // connections & sockets come and go a lot.
+ }
+
+public:
+ /// Clear all external references
+ virtual void dispose() { _msgHandler.reset(); }
+
+ int sendTextMessage(const char *msg, const size_t len, bool flush = false) const override
+ {
+ LOG_TRC("ProxyHack - send text msg " + std::string(msg, len));
+ (void) flush;
+ return len;
+ }
+
+ int sendBinaryMessage(const char *data, const size_t len, bool flush = false) const override
+ {
+ (void) data; (void) flush;
+ LOG_TRC("ProxyHack - send binary msg len " << len);
+ return len;
+ }
+
+ void shutdown(bool goingAway = false, const std::string &statusMessage = "") override
+ {
+ LOG_TRC("ProxyHack - shutdown " << goingAway << ": " << statusMessage);
+ }
+
+ void getIOStats(uint64_t &sent, uint64_t &recv) override
+ {
+ sent = recv = 0;
+ }
+
+ void dumpState(std::ostream& os)
+ {
+ os << "proxy protocol\n";
+ }
+
+ void handleRequest(const std::string &uriPublic,
+ const std::shared_ptr<Socket> &socket);
+
+private:
+ std::vector<std::weak_ptr<StreamSocket>> _sockets;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit f261ae77409697a4e7d8a78bc45d81240e9856e5
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Wed Mar 4 13:52:51 2020 +0000
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 18 17:37:23 2020 +0100
ProxyPrefix: allow the user to specify a custom prefix.
This allows us to re-direct web traffic via a proxy quite simply
during fetch, instead of changing the service root.
Change-Id: I28d348467e48394d581fca4da4c199348a2ca8e0
diff --git a/loleaflet/html/loleaflet.html.m4 b/loleaflet/html/loleaflet.html.m4
index c8d51f0f0..bcfe6ebdb 100644
--- a/loleaflet/html/loleaflet.html.m4
+++ b/loleaflet/html/loleaflet.html.m4
@@ -240,6 +240,7 @@ m4_ifelse(MOBILEAPP,[true],
window.reuseCookies = '';
window.protocolDebug = false;
window.frameAncestors = '';
+ window.socketProxy = false;
window.tileSize = 256;],
[window.host = '%HOST%';
window.serviceRoot = '%SERVICE_ROOT%';
@@ -253,6 +254,7 @@ m4_ifelse(MOBILEAPP,[true],
window.reuseCookies = '%REUSE_COOKIES%';
window.protocolDebug = %PROTOCOL_DEBUG%;
window.frameAncestors = '%FRAME_ANCESTORS%';
+ window.socketProxy = %SOCKET_PROXY%;
window.tileSize = 256;])
m4_syscmd([cat ]GLOBAL_JS)m4_dnl
diff --git a/wsd/FileServer.cpp b/wsd/FileServer.cpp
index 5a973bc01..95f7826e4 100644
--- a/wsd/FileServer.cpp
+++ b/wsd/FileServer.cpp
@@ -640,6 +640,17 @@ constexpr char BRANDING[] = "branding";
constexpr char BRANDING_UNSUPPORTED[] = "branding-unsupported";
#endif
+namespace {
+ // The user can override the ServerRoot with a new prefix.
+ std::string getResponseRoot(const HTTPRequest &request)
+ {
+ if (!request.has("ProxyPrefix"))
+ return LOOLWSD::ServiceRoot;
+ std::string proxyPrefix = request.get("ProxyPrefix", "");
+ return proxyPrefix;
+ }
+}
+
void FileServerRequestHandler::preprocessFile(const HTTPRequest& request, Poco::MemoryInputStream& message,
const std::shared_ptr<StreamSocket>& socket)
{
@@ -686,15 +697,21 @@ void FileServerRequestHandler::preprocessFile(const HTTPRequest& request, Poco::
}
}
- const auto& config = Application::instance().config();
+ std::string socketProxy = "false";
+ if (request.has("ProxyPrefix"))
+ socketProxy = "true";
+ Poco::replaceInPlace(preprocess, std::string("%SOCKET_PROXY%"), socketProxy);
+
+ std::string responseRoot = getResponseRoot(request);
Poco::replaceInPlace(preprocess, std::string("%ACCESS_TOKEN%"), escapedAccessToken);
Poco::replaceInPlace(preprocess, std::string("%ACCESS_TOKEN_TTL%"), std::to_string(tokenTtl));
Poco::replaceInPlace(preprocess, std::string("%ACCESS_HEADER%"), escapedAccessHeader);
Poco::replaceInPlace(preprocess, std::string("%HOST%"), host);
Poco::replaceInPlace(preprocess, std::string("%VERSION%"), std::string(LOOLWSD_VERSION_HASH));
- Poco::replaceInPlace(preprocess, std::string("%SERVICE_ROOT%"), LOOLWSD::ServiceRoot);
+ Poco::replaceInPlace(preprocess, std::string("%SERVICE_ROOT%"), responseRoot);
+ const auto& config = Application::instance().config();
std::string protocolDebug = "false";
if (config.getBool("logging.protocol"))
protocolDebug = "true";
@@ -703,16 +720,16 @@ void FileServerRequestHandler::preprocessFile(const HTTPRequest& request, Poco::
static const std::string linkCSS("<link rel=\"stylesheet\" href=\"%s/loleaflet/" LOOLWSD_VERSION_HASH "/%s.css\">");
static const std::string scriptJS("<script src=\"%s/loleaflet/" LOOLWSD_VERSION_HASH "/%s.js\"></script>");
- std::string brandCSS(Poco::format(linkCSS, LOOLWSD::ServiceRoot, std::string(BRANDING)));
- std::string brandJS(Poco::format(scriptJS, LOOLWSD::ServiceRoot, std::string(BRANDING)));
+ std::string brandCSS(Poco::format(linkCSS, responseRoot, std::string(BRANDING)));
+ std::string brandJS(Poco::format(scriptJS, responseRoot, std::string(BRANDING)));
#if ENABLE_SUPPORT_KEY
const std::string keyString = config.getString("support_key", "");
SupportKey key(keyString);
if (!key.verify() || key.validDaysRemaining() <= 0)
{
- brandCSS = Poco::format(linkCSS, LOOLWSD::ServiceRoot, std::string(BRANDING_UNSUPPORTED));
- brandJS = Poco::format(scriptJS, LOOLWSD::ServiceRoot, std::string(BRANDING_UNSUPPORTED));
+ brandCSS = Poco::format(linkCSS, responseRoot, std::string(BRANDING_UNSUPPORTED));
+ brandJS = Poco::format(scriptJS, responseRoot, std::string(BRANDING_UNSUPPORTED));
}
#endif
@@ -900,13 +917,15 @@ void FileServerRequestHandler::preprocessAdminFile(const HTTPRequest& request,co
if (!FileServerRequestHandler::isAdminLoggedIn(request, response))
throw Poco::Net::NotAuthenticatedException("Invalid admin login");
+ std::string responseRoot = getResponseRoot(request);
+
static const std::string scriptJS("<script src=\"%s/loleaflet/" LOOLWSD_VERSION_HASH "/%s.js\"></script>");
static const std::string footerPage("<div class=\"footer navbar-fixed-bottom text-info text-center\"><strong>Key:</strong> %s <strong>Expiry Date:</strong> %s</div>");
const std::string relPath = getRequestPathname(request);
LOG_DBG("Preprocessing file: " << relPath);
std::string adminFile = *getUncompressedFile(relPath);
- std::string brandJS(Poco::format(scriptJS, LOOLWSD::ServiceRoot, std::string(BRANDING)));
+ std::string brandJS(Poco::format(scriptJS, responseRoot, std::string(BRANDING)));
std::string brandFooter;
#if ENABLE_SUPPORT_KEY
@@ -924,7 +943,7 @@ void FileServerRequestHandler::preprocessAdminFile(const HTTPRequest& request,co
Poco::replaceInPlace(adminFile, std::string("<!--%BRANDING_JS%-->"), brandJS);
Poco::replaceInPlace(adminFile, std::string("<!--%FOOTER%-->"), brandFooter);
Poco::replaceInPlace(adminFile, std::string("%VERSION%"), std::string(LOOLWSD_VERSION_HASH));
- Poco::replaceInPlace(adminFile, std::string("%SERVICE_ROOT%"), LOOLWSD::ServiceRoot);
+ Poco::replaceInPlace(adminFile, std::string("%SERVICE_ROOT%"), responseRoot);
// Ask UAs to block if they detect any XSS attempt
response.add("X-XSS-Protection", "1; mode=block");
commit 3e4ac31c7c6ba95eab12585e0550372b0a39973f
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Sat Apr 18 11:55:50 2020 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 18 18:29:04 2020 +0200
killpoco: remove WebSocket includes from a couple of places.
Change-Id: I06740cd978bec8e6a74beb8ed9ef8f4f970a2535
Reviewed-on: https://gerrit.libreoffice.org/c/online/+/92470
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
Reviewed-by: Michael Meeks <michael.meeks at collabora.com>
diff --git a/common/LOOLWebSocket.hpp b/common/LOOLWebSocket.hpp
index a99c3afb0..627b89a5e 100644
--- a/common/LOOLWebSocket.hpp
+++ b/common/LOOLWebSocket.hpp
@@ -62,7 +62,7 @@ public:
if (n <= 0)
LOG_TRC("Got nothing (" << n << ")");
else
- LOG_TRC("Got frame: " << LOOLProtocol::getAbbreviatedFrameDump(buffer, n, flags));
+ LOG_TRC("Got frame: " << getAbbreviatedFrameDump(buffer, n, flags));
if ((flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_CLOSE)
{
@@ -103,11 +103,11 @@ public:
if (result != length)
{
LOG_ERR("Sent incomplete message, expected " << length << " bytes but sent " << result <<
- " for: " << LOOLProtocol::getAbbreviatedFrameDump(buffer, length, flags));
+ " for: " << getAbbreviatedFrameDump(buffer, length, flags));
}
else
{
- LOG_TRC("Sent frame: " << LOOLProtocol::getAbbreviatedFrameDump(buffer, length, flags));
+ LOG_TRC("Sent frame: " << getAbbreviatedFrameDump(buffer, length, flags));
}
return result;
@@ -154,6 +154,38 @@ public:
}
}
}
+
+ // Return a string dump of a WebSocket frame: Its opcode, length, first line (if present),
+ // flags. For human-readable logging purposes. Format not guaranteed to be stable. Not to be
+ // inspected programmatically.
+ static inline
+ std::string getAbbreviatedFrameDump(const char *message, const int length, const int flags)
+ {
+ std::ostringstream result;
+ switch (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK)
+ {
+#define CASE(x) case Poco::Net::WebSocket::FRAME_OP_##x: result << #x; break
+ CASE(CONT);
+ CASE(TEXT);
+ CASE(BINARY);
+ CASE(CLOSE);
+ CASE(PING);
+ CASE(PONG);
+#undef CASE
+ default:
+ result << Poco::format("%#x", flags);
+ break;
+ }
+ result << " " << std::setw(3) << length << " bytes";
+
+ if (length > 0 &&
+ ((flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) == Poco::Net::WebSocket::FRAME_OP_TEXT ||
+ (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) == Poco::Net::WebSocket::FRAME_OP_BINARY ||
+ (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) == Poco::Net::WebSocket::FRAME_OP_PING ||
+ (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) == Poco::Net::WebSocket::FRAME_OP_PONG))
+ result << ": '" << LOOLProtocol::getAbbreviatedMessage(message, length) << "'";
+ return result.str();
+ }
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/common/MessageQueue.cpp b/common/MessageQueue.cpp
index 5482b4f79..3e5cb08d2 100644
--- a/common/MessageQueue.cpp
+++ b/common/MessageQueue.cpp
@@ -10,7 +10,7 @@
#include <config.h>
#include "MessageQueue.hpp"
-
+#include <climits>
#include <algorithm>
#include <Poco/JSON/JSON.h>
diff --git a/common/Protocol.hpp b/common/Protocol.hpp
index c10e9ae52..56cff7896 100644
--- a/common/Protocol.hpp
+++ b/common/Protocol.hpp
@@ -19,8 +19,6 @@
#include <string>
#include <vector>
-#include <Poco/Net/WebSocket.h>
-
#include <Util.hpp>
#define LOK_USE_UNSTABLE_API
@@ -311,38 +309,6 @@ namespace LOOLProtocol
{
return getAbbreviatedMessage(message.data(), message.size());
}
-
- // Return a string dump of a WebSocket frame: Its opcode, length, first line (if present),
- // flags. For human-readable logging purposes. Format not guaranteed to be stable. Not to be
- // inspected programmatically.
- inline
- std::string getAbbreviatedFrameDump(const char *message, const int length, const int flags)
- {
- std::ostringstream result;
- switch (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK)
- {
-#define CASE(x) case Poco::Net::WebSocket::FRAME_OP_##x: result << #x; break
- CASE(CONT);
- CASE(TEXT);
- CASE(BINARY);
- CASE(CLOSE);
- CASE(PING);
- CASE(PONG);
-#undef CASE
- default:
- result << Poco::format("%#x", flags);
- break;
- }
- result << " " << std::setw(3) << length << " bytes";
-
- if (length > 0 &&
- ((flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) == Poco::Net::WebSocket::FRAME_OP_TEXT ||
- (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) == Poco::Net::WebSocket::FRAME_OP_BINARY ||
- (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) == Poco::Net::WebSocket::FRAME_OP_PING ||
- (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) == Poco::Net::WebSocket::FRAME_OP_PONG))
- result << ": '" << getAbbreviatedMessage(message, length) << "'";
- return result.str();
- }
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/common/Util.cpp b/common/Util.cpp
index 7b71da598..e4d19adb1 100644
--- a/common/Util.cpp
+++ b/common/Util.cpp
@@ -25,6 +25,7 @@
#include <sys/types.h>
#include <unistd.h>
#include <dirent.h>
+#include <fcntl.h>
#include <atomic>
#include <cassert>
@@ -51,7 +52,6 @@
#include <Poco/JSON/JSON.h>
#include <Poco/JSON/Object.h>
#include <Poco/JSON/Parser.h>
-#include <Poco/Net/WebSocket.h>
#include <Poco/Process.h>
#include <Poco/RandomStream.h>
#include <Poco/TemporaryFile.h>
diff --git a/kit/ChildSession.cpp b/kit/ChildSession.cpp
index 780efb18f..cfc7c8baa 100644
--- a/kit/ChildSession.cpp
+++ b/kit/ChildSession.cpp
@@ -11,6 +11,7 @@
#include "ChildSession.hpp"
+#include <climits>
#include <fstream>
#include <sstream>
diff --git a/test/UnitSession.cpp b/test/UnitSession.cpp
index 7e11c2128..f8b859fa1 100644
--- a/test/UnitSession.cpp
+++ b/test/UnitSession.cpp
@@ -110,18 +110,18 @@ UnitBase::TestResult UnitSession::testHandshake()
int flags = 0;
char buffer[1024] = { 0 };
int bytes = socket.receiveFrame(buffer, sizeof(buffer), flags);
- TST_LOG("Got " << LOOLProtocol::getAbbreviatedFrameDump(buffer, bytes, flags));
+ TST_LOG("Got " << LOOLWebSocket::getAbbreviatedFrameDump(buffer, bytes, flags));
LOK_ASSERT_EQUAL(std::string("statusindicator: find"), std::string(buffer, bytes));
bytes = socket.receiveFrame(buffer, sizeof(buffer), flags);
- TST_LOG("Got " << LOOLProtocol::getAbbreviatedFrameDump(buffer, bytes, flags));
+ TST_LOG("Got " << LOOLWebSocket::getAbbreviatedFrameDump(buffer, bytes, flags));
if (bytes > 0 && !std::strstr(buffer, "error:"))
{
LOK_ASSERT_EQUAL(std::string("statusindicator: connect"),
std::string(buffer, bytes));
bytes = socket.receiveFrame(buffer, sizeof(buffer), flags);
- TST_LOG("Got " << LOOLProtocol::getAbbreviatedFrameDump(buffer, bytes, flags));
+ TST_LOG("Got " << LOOLWebSocket::getAbbreviatedFrameDump(buffer, bytes, flags));
if (!std::strstr(buffer, "error:"))
{
LOK_ASSERT_EQUAL(std::string("statusindicator: ready"),
@@ -134,7 +134,7 @@ UnitBase::TestResult UnitSession::testHandshake()
// close frame message
bytes = socket.receiveFrame(buffer, sizeof(buffer), flags);
- TST_LOG("Got " << LOOLProtocol::getAbbreviatedFrameDump(buffer, bytes, flags));
+ TST_LOG("Got " << LOOLWebSocket::getAbbreviatedFrameDump(buffer, bytes, flags));
LOK_ASSERT((flags & Poco::Net::WebSocket::FRAME_OP_BITMASK)
== Poco::Net::WebSocket::FRAME_OP_CLOSE);
}
@@ -146,7 +146,7 @@ UnitBase::TestResult UnitSession::testHandshake()
// close frame message
bytes = socket.receiveFrame(buffer, sizeof(buffer), flags);
- TST_LOG("Got " << LOOLProtocol::getAbbreviatedFrameDump(buffer, bytes, flags));
+ TST_LOG("Got " << LOOLWebSocket::getAbbreviatedFrameDump(buffer, bytes, flags));
LOK_ASSERT((flags & Poco::Net::WebSocket::FRAME_OP_BITMASK)
== Poco::Net::WebSocket::FRAME_OP_CLOSE);
}
diff --git a/test/helpers.hpp b/test/helpers.hpp
index 3322fc5b0..341c5621c 100644
--- a/test/helpers.hpp
+++ b/test/helpers.hpp
@@ -273,7 +273,7 @@ int getErrorCode(LOOLWebSocket& ws, std::string& message, const std::string& tes
do
{
bytes = ws.receiveFrame(buffer.begin(), READ_BUFFER_SIZE, flags);
- TST_LOG("Got " << LOOLProtocol::getAbbreviatedFrameDump(buffer.begin(), bytes, flags));
+ TST_LOG("Got " << LOOLWebSocket::getAbbreviatedFrameDump(buffer.begin(), bytes, flags));
std::this_thread::sleep_for(std::chrono::microseconds(POLL_TIMEOUT_MICRO_S));
}
while (bytes > 0 && (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) != Poco::Net::WebSocket::FRAME_OP_CLOSE);
@@ -325,7 +325,7 @@ std::vector<char> getResponseMessage(LOOLWebSocket& ws, const std::string& prefi
if (LOOLProtocol::matchPrefix(prefix, message))
{
TST_LOG("[" << prefix << "] Matched " <<
- LOOLProtocol::getAbbreviatedFrameDump(response.data(), bytes, flags));
+ LOOLWebSocket::getAbbreviatedFrameDump(response.data(), bytes, flags));
return response;
}
}
@@ -349,7 +349,7 @@ std::vector<char> getResponseMessage(LOOLWebSocket& ws, const std::string& prefi
}
TST_LOG("[" << prefix << "] Ignored " <<
- LOOLProtocol::getAbbreviatedFrameDump(response.data(), bytes, flags));
+ LOOLWebSocket::getAbbreviatedFrameDump(response.data(), bytes, flags));
}
}
}
@@ -539,7 +539,7 @@ void SocketProcessor(const std::string& testname,
}
n = socket->receiveFrame(buffer, sizeof(buffer), flags);
- TST_LOG("Got " << LOOLProtocol::getAbbreviatedFrameDump(buffer, n, flags));
+ TST_LOG("Got " << LOOLWebSocket::getAbbreviatedFrameDump(buffer, n, flags));
if (n > 0 && (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) != Poco::Net::WebSocket::FRAME_OP_CLOSE)
{
if (!handler(std::string(buffer, n)))
diff --git a/test/httpcrashtest.cpp b/test/httpcrashtest.cpp
index e824c1cb9..3a69a96ba 100644
--- a/test/httpcrashtest.cpp
+++ b/test/httpcrashtest.cpp
@@ -166,7 +166,7 @@ void HTTPCrashTest::testCrashKit()
int flags;
char buffer[READ_BUFFER_SIZE];
const int bytes = socket->receiveFrame(buffer, sizeof(buffer), flags);
- TST_LOG(testname << "Got " << LOOLProtocol::getAbbreviatedFrameDump(buffer, bytes, flags));
+ TST_LOG(testname << "Got " << LOOLWebSocket::getAbbreviatedFrameDump(buffer, bytes, flags));
// While we expect no more messages after shutdown call, apparently
// sometimes we _do_ get data. Even when the receiveFrame in the loop
diff --git a/tools/Connect.cpp b/tools/Connect.cpp
index a150bdf99..0a115960b 100644
--- a/tools/Connect.cpp
+++ b/tools/Connect.cpp
@@ -84,7 +84,7 @@ public:
{
{
std::unique_lock<std::mutex> lock(coutMutex);
- std::cout << "Got " << getAbbreviatedFrameDump(buffer, n, flags) << std::endl;
+ std::cout << "Got " << LOOLWebSocket::getAbbreviatedFrameDump(buffer, n, flags) << std::endl;
}
std::string firstLine = getFirstLine(buffer, n);
commit 378a2b5295b7b4d005107e4638ac2e8a61518b7e
Author: Tor Lillqvist <tml at collabora.com>
AuthorDate: Sat Apr 18 16:47:09 2020 +0300
Commit: Tor Lillqvist <tml at collabora.com>
CommitDate: Sat Apr 18 16:35:15 2020 +0200
Bin a couple of unintentionally committed LOG_TRC() calls
Change-Id: Ieadc06a38d71aed723191f1738f8f39154978091
Reviewed-on: https://gerrit.libreoffice.org/c/online/+/92476
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
Reviewed-by: Tor Lillqvist <tml at collabora.com>
diff --git a/common/SigUtil.cpp b/common/SigUtil.cpp
index dcca2d295..cd4c779dc 100644
--- a/common/SigUtil.cpp
+++ b/common/SigUtil.cpp
@@ -56,13 +56,11 @@ namespace SigUtil
bool getTerminationFlag()
{
- LOG_TRC("getTerminationFlag: " << (TerminationFlag ? "YES" : "NO"));
return TerminationFlag;
}
void setTerminationFlag()
{
- LOG_TRC("setTerminationFlag");
TerminationFlag = true;
}
diff --git a/kit/ForKit.cpp b/kit/ForKit.cpp
index aecf96b64..993794bc7 100644
--- a/kit/ForKit.cpp
+++ b/kit/ForKit.cpp
@@ -82,7 +82,6 @@ public:
WebSocketHandler(/* isClient = */ true, /* isMasking */ false),
_socketName(socketName)
{
- LOG_TRC("===> Here is ServerWSHandler");
}
protected:
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index 99391c0d0..329bece7f 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -75,7 +75,6 @@ public:
WSProcess("ChildProcess", pid, socket, std::make_shared<WebSocketHandler>(socket, request)),
_jailId(jailId)
{
- LOG_TRC("==> new ChildProcess");
}
commit 7a416cbf0a3cf6724d5ff21128ed46cb82c42a1a
Author: Tor Lillqvist <tml at collabora.com>
AuthorDate: Sat Apr 18 16:44:50 2020 +0300
Commit: Tor Lillqvist <tml at collabora.com>
CommitDate: Sat Apr 18 16:34:49 2020 +0200
Clarify what ChildProcess and WSProcess are
Change-Id: I13dd37c840d2c8b811bb56614fbc9f8ee2e44d40
Reviewed-on: https://gerrit.libreoffice.org/c/online/+/92475
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
Reviewed-by: Tor Lillqvist <tml at collabora.com>
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index d161be4aa..99391c0d0 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -58,8 +58,10 @@ public:
#include "LOOLWSD.hpp"
-/// Represents a new LOK child that is read
-/// to host a document.
+/// A ChildProcess object represents a KIT process that hosts a document and manipulates the
+/// document using the LibreOfficeKit API. It isn't actually a child of the WSD process, but a
+/// grandchild. The comments loosely talk about "child" anyway.
+
class ChildProcess : public WSProcess
{
public:
diff --git a/wsd/LOOLWSD.hpp b/wsd/LOOLWSD.hpp
index 368b58076..c391cc055 100644
--- a/wsd/LOOLWSD.hpp
+++ b/wsd/LOOLWSD.hpp
@@ -38,10 +38,10 @@ std::shared_ptr<ChildProcess> getNewChild_Blocks(
const std::string& uri
#endif
);
-// This is common code used to setup as socket to both
-// forkit and child document processes via a websocket.
-// In general, a WSProcess instance represents a child
-// process with which we can communicate through websocket.
+// A WSProcess object in the WSD process represents a descendant process, either the direct child
+// process FORKIT or a grandchild KIT process, with which the WSD process communicates through a
+// WebSocket.
+
class WSProcess
{
public:
commit 2a16f34812cf69bbe0f21b7e7d048fdb3271fa9d
Author: Tor Lillqvist <tml at collabora.com>
AuthorDate: Sat Apr 18 16:20:17 2020 +0300
Commit: Tor Lillqvist <tml at collabora.com>
CommitDate: Sat Apr 18 16:33:56 2020 +0200
Don't use "kitbroker" as part of the thread name in a 'kit' process
It just causes confusion with the name "DocumentBroker".
DocumentBroker objects exist only in the WSD process. Instead just use
"kit".
Change-Id: I3d9915c4759899ea6ed9084cf3ec6dc0f3b88ee5
Reviewed-on: https://gerrit.libreoffice.org/c/online/+/92474
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
Reviewed-by: Tor Lillqvist <tml at collabora.com>
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 5e28c0ca0..539615da5 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -2154,7 +2154,7 @@ protected:
std::string url;
URI::decode(docKey, url);
LOG_INF("New session [" << sessionId << "] request on url [" << url << "].");
- Util::setThreadName("kitbroker_" + docId);
+ Util::setThreadName("kit_" + docId);
if (!document)
document = std::make_shared<Document>(
commit 4eb598711cd6162452a28285abbd65c6397f58bf
Author: Tor Lillqvist <tml at collabora.com>
AuthorDate: Sat Apr 18 11:39:50 2020 +0300
Commit: Tor Lillqvist <tml at collabora.com>
CommitDate: Sat Apr 18 15:00:18 2020 +0200
Use #pragma once
LibreOffice core uses that, too, and we support an even more
restricted set of compilers.
Change-Id: I0d0e2c8608e323eb5ef0f35ee8c46d02ab49a745
Reviewed-on: https://gerrit.libreoffice.org/c/online/+/92467
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
Reviewed-by: Tor Lillqvist <tml at collabora.com>
diff --git a/common/Authorization.hpp b/common/Authorization.hpp
index c8c594988..4fd2f3671 100644
--- a/common/Authorization.hpp
+++ b/common/Authorization.hpp
@@ -9,8 +9,7 @@
// WOPI Authorization
-#ifndef INCLUDED_AUTHORIZATION_HPP
-#define INCLUDED_AUTHORIZATION_HPP
+#pragma once
#include <string>
@@ -51,6 +50,4 @@ public:
void authorizeRequest(Poco::Net::HTTPRequest& request) const;
};
-#endif
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/common/Clipboard.hpp b/common/Clipboard.hpp
index 0b4bee438..15e5e58e2 100644
--- a/common/Clipboard.hpp
+++ b/common/Clipboard.hpp
@@ -8,8 +8,8 @@
*/
// Clipboard abstraction.
-#ifndef INCLUDED_CLIPBOARD_HPP
-#define INCLUDED_CLIPBOARD_HPP
+
+#pragma once
#include <string>
#include <vector>
@@ -142,6 +142,4 @@ public:
}
};
-#endif
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/common/Common.hpp b/common/Common.hpp
index ab9989e73..b12cc67b5 100644
--- a/common/Common.hpp
+++ b/common/Common.hpp
@@ -7,11 +7,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
+#pragma once
+
#include <string>
// Default values and other shared data between processes.
-#ifndef INCLUDED_COMMON_HPP
-#define INCLUDED_COMMON_HPP
constexpr int DEFAULT_CLIENT_PORT_NUMBER = 9980;
@@ -50,6 +50,4 @@ constexpr const char CAPABILITIES_END_POINT[] = "/hosting/capabilities";
extern int ClientPortNumber;
extern std::string MasterLocation;
-#endif
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/common/Crypto.hpp b/common/Crypto.hpp
index 079a4f742..270e74e0e 100644
--- a/common/Crypto.hpp
+++ b/common/Crypto.hpp
@@ -7,8 +7,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-#ifndef INCLUDED_CRYPTO_HPP
-#define INCLUDED_CRYPTO_HPP
+#pragma once
#if ENABLE_SUPPORT_KEY
@@ -39,6 +38,4 @@ public:
#endif
-#endif
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/common/FileUtil.hpp b/common/FileUtil.hpp
index 864188308..29426e16c 100644
--- a/common/FileUtil.hpp
+++ b/common/FileUtil.hpp
@@ -7,8 +7,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-#ifndef INCLUDED_FILEUTIL_HPP
-#define INCLUDED_FILEUTIL_HPP
+#pragma once
#include <string>
@@ -98,6 +97,4 @@ namespace FileUtil
} // end namespace FileUtil
-#endif
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/common/JsonUtil.hpp b/common/JsonUtil.hpp
index c7fa20ac2..42cd4e915 100644
--- a/common/JsonUtil.hpp
+++ b/common/JsonUtil.hpp
@@ -7,8 +7,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-#ifndef INCLUDED_JSONUTIL_HPP
-#define INCLUDED_JSONUTIL_HPP
+#pragma once
#include <cstddef>
#include <set>
@@ -140,7 +139,5 @@ bool findJSONValue(Poco::JSON::Object::Ptr &object, const std::string& key, T& v
} // end namespace JsonUtil
-#endif
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/common/LOOLWebSocket.hpp b/common/LOOLWebSocket.hpp
index 2c0559593..a99c3afb0 100644
--- a/common/LOOLWebSocket.hpp
+++ b/common/LOOLWebSocket.hpp
@@ -7,8 +7,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-#ifndef INCLUDED_LOOLWEBSOCKET_HPP
-#define INCLUDED_LOOLWEBSOCKET_HPP
+#pragma once
#include <cstdlib>
#include <mutex>
@@ -157,6 +156,4 @@ public:
}
};
-#endif
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/common/Log.hpp b/common/Log.hpp
index aa83bc171..bc96035e9 100644
--- a/common/Log.hpp
+++ b/common/Log.hpp
@@ -7,8 +7,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-#ifndef INCLUDED_LOG_HPP
-#define INCLUDED_LOG_HPP
+#pragma once
#include <sys/syscall.h>
#include <unistd.h>
@@ -409,6 +408,4 @@ namespace Log
} \
} while (false)
-#endif
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/common/Message.hpp b/common/Message.hpp
index 9320037c7..8fc894b96 100644
--- a/common/Message.hpp
+++ b/common/Message.hpp
@@ -7,8 +7,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-#ifndef INCLUDED_MESSAGE_HPP
-#define INCLUDED_MESSAGE_HPP
+#pragma once
#include <atomic>
#include <string>
@@ -184,6 +183,4 @@ private:
const Type _type;
};
-#endif
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/common/MessageQueue.hpp b/common/MessageQueue.hpp
index bf5f6c950..f315de558 100644
--- a/common/MessageQueue.hpp
+++ b/common/MessageQueue.hpp
@@ -7,8 +7,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-#ifndef INCLUDED_MESSAGEQUEUE_HPP
-#define INCLUDED_MESSAGEQUEUE_HPP
+#pragma once
#include <algorithm>
#include <condition_variable>
@@ -253,6 +252,4 @@ private:
std::vector<int> _viewOrder;
};
-#endif
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/common/Png.hpp b/common/Png.hpp
index c0a99c74e..496d293df 100644
--- a/common/Png.hpp
+++ b/common/Png.hpp
@@ -7,6 +7,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
+#pragma once
+
/* cairo - a vector graphics library with display and print output
*
... etc. - the rest is truncated
More information about the Libreoffice-commits
mailing list