[Libreoffice-commits] online.git: 2 commits - fuzzer/ClientSession.cpp loleaflet/js loleaflet/src net/Socket.hpp wsd/ClientSession.cpp wsd/ClientSession.hpp wsd/DocumentBroker.cpp wsd/DocumentBroker.hpp wsd/LOOLWSD.cpp wsd/ProxyProtocol.cpp wsd/ProxyProtocol.hpp
Michael Meeks (via logerrit)
logerrit at kemper.freedesktop.org
Tue May 12 22:53:43 UTC 2020
fuzzer/ClientSession.cpp | 4 ++--
loleaflet/js/global.js | 36 +++++++++++++++++++++++++-----------
loleaflet/src/core/Socket.js | 5 +++++
loleaflet/src/main.js | 2 ++
net/Socket.hpp | 2 +-
wsd/ClientSession.cpp | 4 ++--
wsd/ClientSession.hpp | 2 +-
wsd/DocumentBroker.cpp | 8 ++++----
wsd/DocumentBroker.hpp | 10 ++++------
wsd/LOOLWSD.cpp | 24 +++++++-----------------
wsd/ProxyProtocol.cpp | 43 +++++++++++++++++++++++++++++++++++--------
wsd/ProxyProtocol.hpp | 9 ++++++---
12 files changed, 94 insertions(+), 55 deletions(-)
New commits:
commit 99d6282dde64b9528eec54bcd960ea547823571a
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Sat May 9 19:41:40 2020 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Wed May 13 00:53:36 2020 +0200
Proxy: re-arrange URL structure & document it better.
Also implement 'close' during browser unload.
Change-Id: Ie2072c14cf863876c633b3371b86016367ad4992
Reviewed-on: https://gerrit.libreoffice.org/c/online/+/94089
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
Reviewed-by: Michael Meeks <michael.meeks at collabora.com>
diff --git a/loleaflet/js/global.js b/loleaflet/js/global.js
index c5546f7c2..f0556a5fb 100644
--- a/loleaflet/js/global.js
+++ b/loleaflet/js/global.js
@@ -213,10 +213,11 @@
this.binaryType = 'arraybuffer';
this.bufferedAmount = 0;
this.extensions = '';
+ this.unloading = false;
this.protocol = '';
this.connected = true;
this.readyState = 0; // connecting
- this.sessionId = 'fetchsession';
+ this.sessionId = 'open';
this.id = window.proxySocketCounter++;
this.sendCounter = 0;
this.readWaiting = 0;
@@ -299,9 +300,8 @@
console.debug('send msg "' + that.sendQueue + '"');
var req = new XMLHttpRequest();
req.open('POST', that.getEndPoint('write'));
- req.setRequestHeader('SessionId', that.sessionId);
- if (that.sessionId === 'fetchsession')
- console.debug('session fetch not completed');
+ if (that.sessionId === 'open')
+ console.debug('new session not completed');
else
{
req.responseType = 'arraybuffer';
@@ -318,8 +318,7 @@
};
this.getSessionId = function() {
var req = new XMLHttpRequest();
- req.open('POST', that.getEndPoint('write'));
- req.setRequestHeader('SessionId', that.sessionId);
+ req.open('POST', that.getEndPoint('open'));
req.responseType = 'text';
req.addEventListener('load', function() {
console.debug('got session: ' + this.responseText);
@@ -344,19 +343,35 @@
'B0x' + this.outSerial.toString(16) + '\n' +
'0x' + msg.length.toString(16) + '\n' + msg + '\n');
this.outSerial++;
- if (this.sessionId !== 'fetchsession' && this.sendTimeout === undefined)
+ if (this.sessionId !== 'open' && this.sendTimeout === undefined)
this.sendTimeout = setTimeout(this.doSend, 2 /* ms */);
};
+ this.sendCloseMsg = function(beacon) {
+ var url = that.getEndPoint('close');
+ if (!beacon)
+ {
+ var req = new XMLHttpRequest();
+ req.open('POST', url);
+ req.send('');
+ }
+ else
+ navigator.sendBeacon(url, '');
+ };
this.close = function() {
console.debug('proxy: close socket');
this.readyState = 3;
this.onclose();
clearInterval(this.waitInterval);
this.waitInterval = undefined;
+ this.sendCloseMsg(this.unloading);
+ this.sessionId = 'open';
+ };
+ this.setUnloading = function() {
+ this.unloading = true;
};
- this.getEndPoint = function(type) {
+ this.getEndPoint = function(command) {
var base = this.uri;
- return base + '/' + type + '/' + this.outSerial;
+ return base + '/' + this.sessionId + '/' + command + '/' + this.outSerial;
};
console.debug('proxy: new socket ' + this.id + ' ' + this.uri);
@@ -368,7 +383,7 @@
console.debug('proxy: waiting - ' + that.readWaiting + ' on session ' + that.sessionId);
if (that.readWaiting >= 4) // max 4 waiting connections concurrently.
return;
- if (that.sessionId == 'fetchsession')
+ if (that.sessionId == 'open')
return; // waiting for our session id.
var req = new XMLHttpRequest();
// fetch session id:
@@ -384,7 +399,6 @@
that.waitConnect();
});
req.open('GET', that.getEndPoint('wait'));
- req.setRequestHeader('SessionId', that.sessionId);
req.responseType = 'arraybuffer';
req.send('');
that.readWaiting++;
diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js
index f6ba2a5c1..a5e394c67 100644
--- a/loleaflet/src/core/Socket.js
+++ b/loleaflet/src/core/Socket.js
@@ -104,6 +104,11 @@ L.Socket = L.Class.extend({
120 * 1000);
},
+ setUnloading: function() {
+ if (this.socket.setUnloading)
+ this.socket.setUnloading();
+ },
+
close: function () {
this.socket.onerror = function () {};
this.socket.onclose = function () {};
diff --git a/loleaflet/src/main.js b/loleaflet/src/main.js
index 7f8fbb267..6b9390058 100644
--- a/loleaflet/src/main.js
+++ b/loleaflet/src/main.js
@@ -79,6 +79,8 @@ map.loadDocument(global.socket);
global.socket = map._socket;
window.addEventListener('beforeunload', function () {
if (map && map._socket) {
+ if (map._socket.setUnloading)
+ map._socket.setUnloading();
map._socket.close();
}
});
diff --git a/net/Socket.hpp b/net/Socket.hpp
index c004a1748..967e7b8c6 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -385,7 +385,7 @@ public:
/// Do some of the queued writing.
virtual void performWrites() = 0;
- /// Called when the is disconnected and will be destroyed.
+ /// Called when the socket is disconnected and will be destroyed.
/// Will be called exactly once.
virtual void onDisconnect() {}
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index 939743fe4..17300d0cb 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -158,13 +158,11 @@ public:
/// 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 RequestDetails &requestDetails,
- const std::shared_ptr<StreamSocket> &socket,
- bool isWaiting);
+ 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 600c1e369..b03574724 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -2909,11 +2909,7 @@ private:
Poco::MemoryInputStream& message,
SocketDisposition &disposition)
{
- if (!request.has("SessionId"))
- throw BadRequestException("No session id header on proxied request");
-
std::string url = requestDetails.getDocumentURI();
- std::string sessionId = request.get("SessionId");
LOG_INF("URL [" << url << "].");
const auto uriPublic = DocumentBroker::sanitizeURI(url);
@@ -2943,15 +2939,12 @@ private:
// Request a kit process for this doc.
std::shared_ptr<DocumentBroker> docBroker = findOrCreateDocBroker(
none, DocumentBroker::ChildType::Interactive, url, docKey, _id, uriPublic);
-
- std::string fullURL = request.getURI();
- std::string ending = "/ws/wait";
- bool isWaiting = fullURL.find(ending) != std::string::npos;
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, requestDetails, sessionId, isWaiting]
+ disposition.setMove([docBroker, id, uriPublic,
+ isReadOnly, requestDetails]
(const std::shared_ptr<Socket> &moveSocket)
{
LOG_TRC("Setting up docbroker thread for " << docBroker->getDocKey());
@@ -2961,8 +2954,8 @@ private:
// We no longer own this socket.
moveSocket->setThreadOwner(std::thread::id());
- docBroker->addCallback([docBroker, id, uriPublic, isReadOnly, requestDetails,
- sessionId, moveSocket, isWaiting]()
+ docBroker->addCallback([docBroker, id, uriPublic, isReadOnly,
+ requestDetails, moveSocket]()
{
// Now inside the document broker thread ...
LOG_TRC("In the docbroker thread for " << docBroker->getDocKey());
@@ -2971,8 +2964,8 @@ private:
try
{
docBroker->handleProxyRequest(
- sessionId, id, uriPublic, isReadOnly,
- requestDetails, streamSocket, isWaiting);
+ id, uriPublic, isReadOnly,
+ requestDetails, streamSocket);
return;
}
catch (const UnauthorizedRequestException& exc)
diff --git a/wsd/ProxyProtocol.cpp b/wsd/ProxyProtocol.cpp
index 8784c39b1..7a5ef1b4c 100644
--- a/wsd/ProxyProtocol.cpp
+++ b/wsd/ProxyProtocol.cpp
@@ -7,6 +7,15 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
+/*
+ * The ProxyProtocol creates a web-socket like connection over HTTP
+ * requests. URLs are formed like this:
+ * 0 1 2 3 4 5
+ * /lool/<encoded-document-url>/ws/<session-id>/<command>/<serial>
+ * <session-id> can be 'unknown'
+ * <command> can be 'open', 'write', 'wait', or 'close'
+ */
+
#include <config.h>
#include "DocumentBroker.hpp"
@@ -20,18 +29,18 @@
#include <cassert>
void DocumentBroker::handleProxyRequest(
- const std::string& sessionId,
const std::string& id,
const Poco::URI& uriPublic,
const bool isReadOnly,
const RequestDetails &requestDetails,
- const std::shared_ptr<StreamSocket> &socket,
- bool isWaiting)
+ const std::shared_ptr<StreamSocket> &socket)
{
- std::shared_ptr<ClientSession> clientSession;
-
+ const size_t session = 3;
+ const size_t command = 4;
+ const size_t serial = 5;
- if (sessionId == "fetchsession")
+ std::shared_ptr<ClientSession> clientSession;
+ if (requestDetails.equals(command, "open"))
{
bool isLocal = socket->isLocal();
LOG_TRC("proxy: validate that socket is from localhost: " << isLocal);
@@ -64,6 +73,7 @@ void DocumentBroker::handleProxyRequest(
}
else
{
+ std::string sessionId = requestDetails[session];
LOG_TRC("proxy: find session for " << _docKey << " with id " << sessionId);
for (const auto &it : _sessions)
{
@@ -87,9 +97,16 @@ void DocumentBroker::handleProxyRequest(
// this DocumentBroker's poll handles reading & writing
addSocketToPoll(socket);
- auto proxy = std::static_pointer_cast<ProxyProtocolHandler>(
- protocol);
+ auto proxy = std::static_pointer_cast<ProxyProtocolHandler>(protocol);
+ if (requestDetails.equals(command, "close"))
+ {
+ LOG_TRC("Close session");
+ proxy->notifyDisconnected();
+ return;
+ }
+ (void)serial; // in URL for logging, debugging, and uniqueness.
+ bool isWaiting = requestDetails.equals(command, "wait");
proxy->handleRequest(isWaiting, socket);
}
@@ -98,9 +115,11 @@ bool ProxyProtocolHandler::parseEmitIncoming(
{
std::vector<char> &in = socket->getInBuffer();
+#if 0 // protocol debugging.
std::stringstream oss;
socket->dumpState(oss);
LOG_TRC("Parse message:\n" << oss.str());
+#endif
while (in.size() > 0)
{
@@ -219,6 +238,12 @@ void ProxyProtocolHandler::handleIncomingMessage(SocketDisposition &disposition)
LOG_ERR("If you got here, it means we failed to parse this properly in handleRequest: " << oss.str());
}
+void ProxyProtocolHandler::notifyDisconnected()
+{
+ if (_msgHandler)
+ _msgHandler->onDisconnect();
+}
+
int ProxyProtocolHandler::sendMessage(const char *msg, const size_t len, bool text, bool flush)
{
_writeQueue.push_back(std::make_shared<Message>(msg, len, text, _outSerial++));
diff --git a/wsd/ProxyProtocol.hpp b/wsd/ProxyProtocol.hpp
index 7bca66600..4a890d8f6 100644
--- a/wsd/ProxyProtocol.hpp
+++ b/wsd/ProxyProtocol.hpp
@@ -30,9 +30,7 @@ public:
virtual ~ProxyProtocolHandler() { }
/// Will be called exactly once by setHandler
- void onConnect(const std::shared_ptr<StreamSocket>& /* socket */) override
- {
- }
+ void onConnect(const std::shared_ptr<StreamSocket>& /* socket */) override {}
/// Called after successful socket reads.
void handleIncomingMessage(SocketDisposition &/* disposition */) override;
@@ -61,10 +59,15 @@ public:
void getIOStats(uint64_t &sent, uint64_t &recv) override;
void dumpState(std::ostream& os) override;
bool parseEmitIncoming(const std::shared_ptr<StreamSocket> &socket);
+
void handleRequest(bool isWaiting, const std::shared_ptr<Socket> &socket);
+ /// tell our handler we've received a close.
+ void notifyDisconnected();
+
private:
std::shared_ptr<StreamSocket> popOutSocket();
+ /// can we find anything to send back if we try ?
bool slurpHasMessages();
int sendMessage(const char *msg, const size_t len, bool text, bool flush);
bool flushQueueTo(const std::shared_ptr<StreamSocket> &socket);
commit 34fc7fb6b726dcdf0c40f19ed402c3728581d1a2
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Tue May 12 21:10:56 2020 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Wed May 13 00:53:24 2020 +0200
Proxy: move requestDetails closer to ProxyProtocol.
Change-Id: I07c00ea1dad15fd70b658a04f722cbd516fd5c18
Reviewed-on: https://gerrit.libreoffice.org/c/online/+/94088
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
Reviewed-by: Michael Meeks <michael.meeks at collabora.com>
diff --git a/fuzzer/ClientSession.cpp b/fuzzer/ClientSession.cpp
index edd4053d1..e24647315 100644
--- a/fuzzer/ClientSession.cpp
+++ b/fuzzer/ClientSession.cpp
@@ -22,9 +22,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
std::shared_ptr<ProtocolHandlerInterface> ws;
std::string id;
bool isReadOnly = false;
- const ServerURL serverURL;
+ const RequestDetails requestDetails("fuzzer");
auto session
- = std::make_shared<ClientSession>(ws, id, docBroker, uriPublic, isReadOnly, serverURL);
+ = std::make_shared<ClientSession>(ws, id, docBroker, uriPublic, isReadOnly, requestDetails);
std::string input(reinterpret_cast<const char*>(data), size);
std::stringstream ss(input);
diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp
index 41d9bbcd0..3991c3d92 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -44,7 +44,7 @@ ClientSession::ClientSession(
const std::shared_ptr<DocumentBroker>& docBroker,
const Poco::URI& uriPublic,
const bool readOnly,
- const ServerURL &serverURL) :
+ const RequestDetails &requestDetails) :
Session(ws, "ToClient-" + id, id, readOnly),
_docBroker(docBroker),
_uriPublic(uriPublic),
@@ -58,7 +58,7 @@ ClientSession::ClientSession(
_tileWidthTwips(0),
_tileHeightTwips(0),
_kitViewId(-1),
- _serverURL(serverURL),
+ _serverURL(requestDetails),
_isTextDocument(false)
{
const size_t curConnections = ++LOOLWSD::NumConnections;
diff --git a/wsd/ClientSession.hpp b/wsd/ClientSession.hpp
index a99832560..865649c30 100644
--- a/wsd/ClientSession.hpp
+++ b/wsd/ClientSession.hpp
@@ -34,7 +34,7 @@ public:
const std::shared_ptr<DocumentBroker>& docBroker,
const Poco::URI& uriPublic,
const bool isReadOnly,
- const ServerURL &serverURL);
+ const RequestDetails &requestDetails);
void construct();
virtual ~ClientSession();
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index 1cbfcac13..3293dea94 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -1526,7 +1526,7 @@ std::shared_ptr<ClientSession> DocumentBroker::createNewClientSession(
const std::string& id,
const Poco::URI& uriPublic,
const bool isReadOnly,
- const ServerURL &serverURL)
+ const RequestDetails &requestDetails)
{
try
{
@@ -1541,7 +1541,7 @@ std::shared_ptr<ClientSession> DocumentBroker::createNewClientSession(
// In case of WOPI, if this session is not set as readonly, it might be set so
// later after making a call to WOPI host which tells us the permission on files
// (UserCanWrite param).
- auto session = std::make_shared<ClientSession>(ws, id, shared_from_this(), uriPublic, isReadOnly, serverURL);
+ auto session = std::make_shared<ClientSession>(ws, id, shared_from_this(), uriPublic, isReadOnly, requestDetails);
session->construct();
return session;
@@ -2269,8 +2269,8 @@ bool ConvertToBroker::startConversion(SocketDisposition &disposition, const std:
const bool isReadOnly = true;
// FIXME: associate this with moveSocket (?)
std::shared_ptr<ProtocolHandlerInterface> nullPtr;
- ServerURL serverURL;
- _clientSession = std::make_shared<ClientSession>(nullPtr, id, docBroker, getPublicUri(), isReadOnly, serverURL);
+ RequestDetails requestDetails("convert-to");
+ _clientSession = std::make_shared<ClientSession>(nullPtr, id, docBroker, getPublicUri(), isReadOnly, requestDetails);
_clientSession->construct();
if (!_clientSession)
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index f086ddea6..939743fe4 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -97,7 +97,7 @@ private:
int _smapsFD;
};
-class ServerURL;
+class RequestDetails;
class ClientSession;
/// DocumentBroker is responsible for setting up a document in jail and brokering loading it from
@@ -154,7 +154,7 @@ public:
const std::string& id,
const Poco::URI& uriPublic,
const bool isReadOnly,
- const ServerURL &serverURL);
+ const RequestDetails &requestDetails);
/// Find or create a new client session for the PHP proxy
void handleProxyRequest(
@@ -162,7 +162,7 @@ public:
const std::string& id,
const Poco::URI& uriPublic,
const bool isReadOnly,
- const ServerURL &serverURL,
+ const RequestDetails &requestDetails,
const std::shared_ptr<StreamSocket> &socket,
bool isWaiting);
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 7f455e93a..600c1e369 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -2936,8 +2936,6 @@ private:
}
}
- ServerURL serverURL(requestDetails);
-
LOG_INF("URL [" << LOOLWSD::anonymizeUrl(url) << "] is " << (isReadOnly ? "readonly" : "writable") << ".");
(void)request; (void)message; (void)disposition;
@@ -2953,7 +2951,7 @@ private:
{
// need to move into the DocumentBroker context before doing session lookup / creation etc.
std::string id = _id;
- disposition.setMove([docBroker, id, uriPublic, isReadOnly, serverURL, sessionId, isWaiting]
+ disposition.setMove([docBroker, id, uriPublic, isReadOnly, requestDetails, sessionId, isWaiting]
(const std::shared_ptr<Socket> &moveSocket)
{
LOG_TRC("Setting up docbroker thread for " << docBroker->getDocKey());
@@ -2963,7 +2961,7 @@ private:
// We no longer own this socket.
moveSocket->setThreadOwner(std::thread::id());
- docBroker->addCallback([docBroker, id, uriPublic, isReadOnly, serverURL,
+ docBroker->addCallback([docBroker, id, uriPublic, isReadOnly, requestDetails,
sessionId, moveSocket, isWaiting]()
{
// Now inside the document broker thread ...
@@ -2974,7 +2972,7 @@ private:
{
docBroker->handleProxyRequest(
sessionId, id, uriPublic, isReadOnly,
- serverURL, streamSocket, isWaiting);
+ requestDetails, streamSocket, isWaiting);
return;
}
catch (const UnauthorizedRequestException& exc)
@@ -3066,9 +3064,8 @@ private:
DocumentBroker::ChildType::Interactive, url, docKey, _id, uriPublic);
if (docBroker)
{
- ServerURL serverURL(requestDetails);
std::shared_ptr<ClientSession> clientSession =
- docBroker->createNewClientSession(ws, _id, uriPublic, isReadOnly, serverURL);
+ docBroker->createNewClientSession(ws, _id, uriPublic, isReadOnly, requestDetails);
if (clientSession)
{
// Transfer the client socket to the DocumentBroker when we get back to the poll:
diff --git a/wsd/ProxyProtocol.cpp b/wsd/ProxyProtocol.cpp
index 7c03d65e8..8784c39b1 100644
--- a/wsd/ProxyProtocol.cpp
+++ b/wsd/ProxyProtocol.cpp
@@ -24,11 +24,13 @@ void DocumentBroker::handleProxyRequest(
const std::string& id,
const Poco::URI& uriPublic,
const bool isReadOnly,
- const ServerURL &serverURL,
+ const RequestDetails &requestDetails,
const std::shared_ptr<StreamSocket> &socket,
bool isWaiting)
{
std::shared_ptr<ClientSession> clientSession;
+
+
if (sessionId == "fetchsession")
{
bool isLocal = socket->isLocal();
@@ -39,7 +41,7 @@ void DocumentBroker::handleProxyRequest(
LOG_TRC("proxy: Create session for " << _docKey);
clientSession = createNewClientSession(
std::make_shared<ProxyProtocolHandler>(),
- id, uriPublic, isReadOnly, serverURL);
+ id, uriPublic, isReadOnly, requestDetails);
addSession(clientSession);
LOOLWSD::checkDiskSpaceAndWarnClients(true);
LOOLWSD::checkSessionLimitsAndWarnClients();
More information about the Libreoffice-commits
mailing list