loleaflet/js/global.js | 27 ++++++++++++ net/WebSocketHandler.hpp | 19 ++++---- tools/WebSocketDump.cpp | 6 ++ wsd/Admin.cpp | 5 ++ wsd/ClientSession.cpp | 4 + wsd/LOOLWSD.cpp | 100 +++++++++++++++++++++++++++++------------------ wsd/TileCache.cpp | 4 + 7 files changed, 116 insertions(+), 49 deletions(-)
New commits: commit 5b9f0927488243b6af8a6d9e0f88c1dcc100b41e Author: Michael Meeks <michael.me...@collabora.com> AuthorDate: Fri Mar 20 19:05:48 2020 +0000 Commit: Jan Holesovsky <ke...@collabora.com> CommitDate: Fri Apr 24 15:39:25 2020 +0200 Proxy: re-write css image URLs to handle the proxy. Change-Id: I09f3dea2f5e3a51869d5b0aa3f473d8f3ba75f44 Reviewed-on: https://gerrit.libreoffice.org/c/online/+/92808 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Jan Holesovsky <ke...@collabora.com> diff --git a/loleaflet/js/global.js b/loleaflet/js/global.js index f5c038b91..023a8bf7c 100644 --- a/loleaflet/js/global.js +++ b/loleaflet/js/global.js @@ -335,6 +335,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 df6d942d08dfb5e8fffed015edf4c0eb5ce6f65e Author: Ashod Nakashian <ashod.nakash...@collabora.co.uk> AuthorDate: Sun Apr 19 14:46:01 2020 -0400 Commit: Ashod Nakashian <ashnak...@gmail.com> CommitDate: Fri Apr 24 15:39:17 2020 +0200 wsd: harden socket weakptr Weak pointers can be null and must be checked before using. This fixes at least one segfault and prevents a number of others. Also, minimizes locking of weak pointers in the message handlers. Change-Id: I306501c26c3441d7bd6812d51fa17e7356126f32 Reviewed-on: https://gerrit.libreoffice.org/c/online/+/92828 Reviewed-by: Michael Meeks <michael.me...@collabora.com> Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> diff --git a/net/WebSocketHandler.hpp b/net/WebSocketHandler.hpp index 46a2916a7..a329e7711 100644 --- a/net/WebSocketHandler.hpp +++ b/net/WebSocketHandler.hpp @@ -122,7 +122,7 @@ public: void sendCloseFrame(const StatusCodes statusCode = StatusCodes::NORMAL_CLOSE, const std::string& statusMessage = "") { std::shared_ptr<StreamSocket> socket = _socket.lock(); - if (socket == nullptr) + if (!socket) { LOG_ERR("No socket associated with WebSocketHandler " << this); return; @@ -404,23 +404,21 @@ public: /// Implementation of the ProtocolHandlerInterface. virtual void handleIncomingMessage(SocketDisposition&) override { - // LOG_TRC("***** WebSocketHandler::handleIncomingMessage()"); - std::shared_ptr<StreamSocket> socket = _socket.lock(); #if MOBILEAPP // No separate "upgrade" is going on - if (socket != nullptr && !socket->isWebSocket()) + if (socket && !socket->isWebSocket()) socket->setWebSocket(); #endif - if (socket == nullptr) + if (!socket) { LOG_ERR("No socket associated with WebSocketHandler " << this); } #if !MOBILEAPP else if (_isClient && !socket->isWebSocket()) - handleClientUpgrade(); + handleClientUpgrade(socket); #endif else { @@ -694,7 +692,7 @@ protected: void upgradeToWebSocket(const Poco::Net::HTTPRequest& req) { std::shared_ptr<StreamSocket> socket = _socket.lock(); - if (socket == nullptr) + if (!socket) throw std::runtime_error("Invalid socket while upgrading to WebSocket. Request: " + req.getURI()); LOG_TRC("#" << socket->getFD() << ": Upgrading to WebSocket."); @@ -730,9 +728,9 @@ protected: #if !MOBILEAPP // Handle incoming upgrade to full socket as client WS. - void handleClientUpgrade() + void handleClientUpgrade(const std::shared_ptr<StreamSocket>& socket) { - std::shared_ptr<StreamSocket> socket = _socket.lock(); + assert(socket && "socket must be valid"); LOG_TRC("Incoming client websocket upgrade response: " << std::string(&socket->getInBuffer()[0], socket->getInBuffer().size())); @@ -800,7 +798,8 @@ protected: void setWebSocket() { std::shared_ptr<StreamSocket> socket = _socket.lock(); - socket->setWebSocket(); + if (socket) + socket->setWebSocket(); // No need to ping right upon connection/upgrade, // but do reset the time to avoid pinging immediately after. diff --git a/tools/WebSocketDump.cpp b/tools/WebSocketDump.cpp index 81e034a67..711cbaca9 100644 --- a/tools/WebSocketDump.cpp +++ b/tools/WebSocketDump.cpp @@ -70,6 +70,12 @@ private: void handleIncomingMessage(SocketDisposition &disposition) override { std::shared_ptr<StreamSocket> socket = _socket.lock(); + if (!socket) + { + LOG_ERR("Invalid socket while reading client message."); + return; + } + std::vector<char>& in = socket->getInBuffer(); LOG_TRC("#" << socket->getFD() << " handling incoming " << in.size() << " bytes."); diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp index ca84c5c6c..8f98cce64 100644 --- a/wsd/Admin.cpp +++ b/wsd/Admin.cpp @@ -330,6 +330,11 @@ bool AdminSocketHandler::handleInitialRequest( } std::shared_ptr<StreamSocket> socket = socketWeak.lock(); + if (!socket) + { + LOG_ERR("Invalid socket while reading initial request."); + return false; + } const std::string& requestURI = request.getURI(); StringVector pathTokens(LOOLProtocol::tokenize(requestURI, '/')); diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp index c9dc7827a..a73749352 100644 --- a/wsd/ClientSession.cpp +++ b/wsd/ClientSession.cpp @@ -1358,12 +1358,16 @@ bool ClientSession::handleKitToClientMessage(const char* buffer, const int lengt << "X-Content-Type-Options: nosniff\r\n" << "\r\n"; auto socket = it.lock(); + if (!socket) + continue; + if (!empty) { oss.write(&payload->data()[header], payload->size() - header); socket->setSocketBufferSize(std::min(payload->size() + 256, size_t(Socket::MaximumSendBufferSize))); } + socket->send(oss.str()); socket->shutdown(); LOG_INF("Queued " << (empty?"empty":"clipboard") << " response for send."); diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp index c58430509..7607facef 100644 --- a/wsd/LOOLWSD.cpp +++ b/wsd/LOOLWSD.cpp @@ -1937,7 +1937,6 @@ private: /// Called after successful socket reads. void handleIncomingMessage(SocketDisposition &disposition) override { - // LOG_TRC("***** PrisonerRequestDispatcher::handleIncomingMessage()"); if (_childProcess.lock()) { // FIXME: inelegant etc. - derogate to websocket code @@ -1946,6 +1945,11 @@ private: } std::shared_ptr<StreamSocket> socket = getSocket().lock(); + if (!socket) + { + LOG_ERR("Invalid socket while reading incoming message."); + return; + } Poco::MemoryInputStream message(&socket->getInBuffer()[0], socket->getInBuffer().size());; @@ -2194,6 +2198,11 @@ private: void handleIncomingMessage(SocketDisposition &disposition) override { std::shared_ptr<StreamSocket> socket = _socket.lock(); + if (!socket) + { + LOG_ERR("Invalid socket while handling incoming client request"); + return; + } #if !MOBILEAPP if (!LOOLWSD::isSSLEnabled() && socket->sniffSSL()) @@ -2247,7 +2256,7 @@ private: else if (reqPathSegs.size() >= 1 && reqPathSegs[0] == "loleaflet") { // File server - handleFileServerRequest(request, message); + handleFileServerRequest(request, message, socket); } else if (reqPathSegs.size() >= 2 && reqPathSegs[0] == "lool" && reqPathSegs[1] == "adminws") { @@ -2308,23 +2317,23 @@ private: request.getMethod() == HTTPRequest::HTTP_HEAD) && request.getURI() == "/") { - handleRootRequest(request); + handleRootRequest(request, socket); } else if (request.getMethod() == HTTPRequest::HTTP_GET && request.getURI() == "/favicon.ico") { - handleFaviconRequest(request); + handleFaviconRequest(request, socket); } else if (request.getMethod() == HTTPRequest::HTTP_GET && (request.getURI() == "/hosting/discovery" || request.getURI() == "/hosting/discovery/")) { - handleWopiDiscoveryRequest(request); + handleWopiDiscoveryRequest(request, socket); } else if (request.getMethod() == HTTPRequest::HTTP_GET && request.getURI() == CAPABILITIES_END_POINT) { - handleCapabilitiesRequest(request); + handleCapabilitiesRequest(request, socket); } else if (request.getMethod() == HTTPRequest::HTTP_GET && request.getURI() == "/robots.txt") { - handleRobotsTxtRequest(request); + handleRobotsTxtRequest(request, socket); } else { @@ -2332,7 +2341,7 @@ private: if (reqPathTokens.count() > 1 && reqPathTokens[0] == "lool" && reqPathTokens[1] == "clipboard") { // Util::dumpHex(std::cerr, "clipboard:\n", "", socket->getInBuffer()); // lots of data ... - handleClipboardRequest(request, message, disposition); + handleClipboardRequest(request, message, disposition, socket); } else if (request.has("ProxyPrefix") && reqPathTokens.count() > 2 && (reqPathTokens[reqPathTokens.count()-2] == "ws")) @@ -2345,14 +2354,14 @@ private: reqPathTokens.count() > 0 && reqPathTokens[0] == "lool") { // All post requests have url prefix 'lool'. - handlePostRequest(request, message, disposition); + handlePostRequest(request, message, disposition, socket); } else if (reqPathTokens.count() > 2 && reqPathTokens[0] == "lool" && reqPathTokens[2] == "ws" && request.find("Upgrade") != request.end() && Poco::icompare(request["Upgrade"], "websocket") == 0) { std::string decodedUri; // WOPISrc Poco::URI::decode(reqPathTokens[1], decodedUri); - handleClientWsUpgrade(request, decodedUri, disposition); + handleClientWsUpgrade(request, decodedUri, disposition, socket); } else { @@ -2396,7 +2405,9 @@ private: Poco::Net::HTTPRequest request; // The 2nd parameter is the response to the HULLO message (which we // respond with the path of the document) - handleClientWsUpgrade(request, std::string(socket->getInBuffer().data(), socket->getInBuffer().size()), disposition); + handleClientWsUpgrade( + request, std::string(socket->getInBuffer().data(), socket->getInBuffer().size()), + disposition, socket); socket->getInBuffer().clear(); #endif } @@ -2412,15 +2423,20 @@ private: } #if !MOBILEAPP - void handleFileServerRequest(const Poco::Net::HTTPRequest& request, Poco::MemoryInputStream& message) + void handleFileServerRequest(const Poco::Net::HTTPRequest& request, + Poco::MemoryInputStream& message, + const std::shared_ptr<StreamSocket>& socket) { - std::shared_ptr<StreamSocket> socket = _socket.lock(); + assert(socket && "Must have a valid socket"); FileServerRequestHandler::handleRequest(request, message, socket); socket->shutdown(); } - void handleRootRequest(const Poco::Net::HTTPRequest& request) + void handleRootRequest(const Poco::Net::HTTPRequest& request, + const std::shared_ptr<StreamSocket>& socket) { + assert(socket && "Must have a valid socket"); + LOG_DBG("HTTP request: " << request.getURI()); const std::string mimeType = "text/plain"; const std::string responseString = "OK"; @@ -2438,14 +2454,16 @@ private: oss << responseString; } - std::shared_ptr<StreamSocket> socket = _socket.lock(); socket->send(oss.str()); socket->shutdown(); LOG_INF("Sent / response successfully."); } - void handleFaviconRequest(const Poco::Net::HTTPRequest& request) + void handleFaviconRequest(const Poco::Net::HTTPRequest& request, + const std::shared_ptr<StreamSocket>& socket) { + assert(socket && "Must have a valid socket"); + LOG_DBG("Favicon request: " << request.getURI()); std::string mimeType = "image/vnd.microsoft.icon"; std::string faviconPath = Path(Application::instance().commandPath()).parent().toString() + "favicon.ico"; @@ -2454,14 +2472,16 @@ private: faviconPath = LOOLWSD::FileServerRoot + "/favicon.ico"; } - std::shared_ptr<StreamSocket> socket = _socket.lock(); Poco::Net::HTTPResponse response; HttpHelper::sendFile(socket, faviconPath, mimeType, response); socket->shutdown(); } - void handleWopiDiscoveryRequest(const Poco::Net::HTTPRequest& request) + void handleWopiDiscoveryRequest(const Poco::Net::HTTPRequest& request, + const std::shared_ptr<StreamSocket>& socket) { + assert(socket && "Must have a valid socket"); + LOG_DBG("Wopi discovery request: " << request.getURI()); std::string xml = getFileContent("discovery.xml"); @@ -2479,17 +2499,19 @@ private: "\r\n" << xml; - std::shared_ptr<StreamSocket> socket = _socket.lock(); socket->send(oss.str()); socket->shutdown(); LOG_INF("Sent discovery.xml successfully."); } - void handleCapabilitiesRequest(const Poco::Net::HTTPRequest& request) + void handleCapabilitiesRequest(const Poco::Net::HTTPRequest& request, + const std::shared_ptr<StreamSocket>& socket) { + assert(socket && "Must have a valid socket"); + LOG_DBG("Wopi capabilities request: " << request.getURI()); - std::string capabilities = getCapabilitiesJson(request); + const std::string capabilities = getCapabilitiesJson(request, socket); std::ostringstream oss; oss << "HTTP/1.1 200 OK\r\n" @@ -2501,7 +2523,6 @@ private: "\r\n" << capabilities; - auto socket = _socket.lock(); socket->send(oss.str()); socket->shutdown(); LOG_INF("Sent capabilities.json successfully."); @@ -2509,8 +2530,11 @@ private: void handleClipboardRequest(const Poco::Net::HTTPRequest& request, Poco::MemoryInputStream& message, - SocketDisposition &disposition) + SocketDisposition &disposition, + const std::shared_ptr<StreamSocket>& socket) { + assert(socket && "Must have a valid socket"); + LOG_DBG("Clipboard " << ((request.getMethod() == HTTPRequest::HTTP_GET) ? "GET" : "POST") << " request: " << request.getURI()); @@ -2579,7 +2603,7 @@ private: LOG_TRC("queued clipboard command " << type << " on docBroker fetch"); } // fallback to persistent clipboards if we can - else if (!DocumentBroker::lookupSendClipboardTag(_socket.lock(), tag, false)) + else if (!DocumentBroker::lookupSendClipboardTag(socket, tag, false)) { LOG_ERR("Invalid clipboard request: " << serverId << " with tag " << tag << " and broker: " << (docBroker ? "" : "not ") << "found"); @@ -2598,14 +2622,16 @@ private: << "Content-Length: 0\r\n" << "\r\n" << errMsg; - auto socket = _socket.lock(); socket->send(oss.str()); socket->shutdown(); } } - void handleRobotsTxtRequest(const Poco::Net::HTTPRequest& request) + void handleRobotsTxtRequest(const Poco::Net::HTTPRequest& request, + const std::shared_ptr<StreamSocket>& socket) { + assert(socket && "Must have a valid socket"); + LOG_DBG("HTTP request: " << request.getURI()); const std::string mimeType = "text/plain"; const std::string responseString = "User-agent: *\nDisallow: /\n"; @@ -2623,7 +2649,6 @@ private: oss << responseString; } - std::shared_ptr<StreamSocket> socket = _socket.lock(); socket->send(oss.str()); socket->shutdown(); LOG_INF("Sent robots.txt response successfully."); @@ -2669,12 +2694,14 @@ private: void handlePostRequest(const Poco::Net::HTTPRequest& request, Poco::MemoryInputStream& message, - SocketDisposition &disposition) + SocketDisposition& disposition, + const std::shared_ptr<StreamSocket>& socket) { + assert(socket && "Must have a valid socket"); + LOG_INF("Post request: [" << LOOLWSD::anonymizeUrl(request.getURI()) << "]"); Poco::Net::HTTPResponse response; - std::shared_ptr<StreamSocket> socket = _socket.lock(); StringTokenizer tokens(request.getURI(), "/?"); if (tokens.count() > 2 && tokens[2] == "convert-to") @@ -2968,14 +2995,10 @@ private: } void handleClientWsUpgrade(const Poco::Net::HTTPRequest& request, const std::string& url, - SocketDisposition &disposition) + SocketDisposition& disposition, + const std::shared_ptr<StreamSocket>& socket) { - std::shared_ptr<StreamSocket> socket = _socket.lock(); - if (!socket) - { - LOG_WRN("No socket to handle client WS upgrade for request: " << LOOLWSD::anonymizeUrl(request.getURI()) << ", url: " << url); - return; - } + assert(socket && "Must have a valid socket"); // must be trace for anonymization LOG_TRC("Client WS request: " << request.getURI() << ", url: " << url << ", socket #" << socket->getFD()); @@ -3197,9 +3220,10 @@ private: } /// Create the /hosting/capabilities JSON and return as string. - std::string getCapabilitiesJson(const Poco::Net::HTTPRequest& request) + std::string getCapabilitiesJson(const Poco::Net::HTTPRequest& request, + const std::shared_ptr<StreamSocket>& socket) { - std::shared_ptr<StreamSocket> socket = _socket.lock(); + assert(socket && "Must have a valid socket"); // Can the convert-to be used? Poco::JSON::Object::Ptr convert_to = new Poco::JSON::Object; diff --git a/wsd/TileCache.cpp b/wsd/TileCache.cpp index 5ef10804f..15f24b92f 100644 --- a/wsd/TileCache.cpp +++ b/wsd/TileCache.cpp @@ -656,7 +656,9 @@ void TileCache::TileBeingRendered::dumpState(std::ostream& os) for (const auto& it : _subscribers) { std::shared_ptr<ClientSession> session = it.lock(); - os << " " << session->getId() << " " << session->getUserId() << " " << session->getName() << "\n"; + if (session) + os << " " << session->getId() << ' ' << session->getUserId() << ' ' + << session->getName() << '\n'; } } _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits