[Libreoffice-commits] online.git: Branch 'distro/collabora/collabora-online-3' - 2 commits - common/UnitHTTP.cpp common/UnitHTTP.hpp Makefile.am tools/Connect.cpp tools/WebSocketDump.cpp
Michael Meeks
michael.meeks at collabora.com
Thu Apr 26 17:39:03 UTC 2018
Makefile.am | 8 +
common/UnitHTTP.cpp | 41 --------
common/UnitHTTP.hpp | 29 +++++
tools/Connect.cpp | 11 --
tools/WebSocketDump.cpp | 240 ++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 276 insertions(+), 53 deletions(-)
New commits:
commit fd047dd1df81c76f6677358c0a8a15ae0b1ff532
Author: Michael Meeks <michael.meeks at collabora.com>
Date: Tue Apr 17 16:40:55 2018 +0100
Move UnitHTTP code to header to avoid linking trouble.
Change-Id: I430110e840fa8b3862c21c1d4e02288ed704e0a3
Reviewed-on: https://gerrit.libreoffice.org/53532
Reviewed-by: Michael Meeks <michael.meeks at collabora.com>
Tested-by: Michael Meeks <michael.meeks at collabora.com>
diff --git a/Makefile.am b/Makefile.am
index 07a00ab83..5471a99e6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -63,7 +63,6 @@ shared_sources = common/FileUtil.cpp \
common/SigUtil.cpp \
common/SpookyV2.cpp \
common/Unit.cpp \
- common/UnitHTTP.cpp \
common/Util.cpp \
net/DelaySocket.cpp \
net/Socket.cpp
diff --git a/common/UnitHTTP.cpp b/common/UnitHTTP.cpp
deleted file mode 100644
index b4b652b11..000000000
--- a/common/UnitHTTP.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * 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 <iostream>
-#include "UnitHTTP.hpp"
-
-Poco::Net::HTTPClientSession *UnitHTTP::createSession()
-{
- // HTTP forced in configure hook.
- return new Poco::Net::HTTPClientSession ("127.0.0.1",
- ClientPortNumber);
-}
-
-UnitWebSocket::UnitWebSocket(const std::string &docURL)
-{
- try {
- UnitHTTPServerResponse response;
- UnitHTTPServerRequest request(response, docURL);
-
- _session = UnitHTTP::createSession();
-
- // FIXME: leaking the session - hey ho ... do we need a UnitSocket ?
- _socket = new LOOLWebSocket(*_session, request, response);
- } catch (const Poco::Exception &ex) {
- std::cerr << "Exception creating websocket " << ex.displayText() << std::endl;
- throw;
- }
-}
-
-LOOLWebSocket* UnitWebSocket::getLOOLWebSocket() const
-{
- return _socket;
-}
diff --git a/common/UnitHTTP.hpp b/common/UnitHTTP.hpp
index a6a107d9f..32f2b7416 100644
--- a/common/UnitHTTP.hpp
+++ b/common/UnitHTTP.hpp
@@ -114,7 +114,12 @@ public:
namespace UnitHTTP
{
- Poco::Net::HTTPClientSession* createSession();
+ Poco::Net::HTTPClientSession* createSession()
+ {
+ // HTTP forced in configure hook.
+ return new Poco::Net::HTTPClientSession ("127.0.0.1",
+ ClientPortNumber);
+ }
}
class UnitWebSocket
@@ -124,14 +129,32 @@ class UnitWebSocket
public:
/// Get a websocket connected for a given URL
- UnitWebSocket(const std::string& docURL);
+ UnitWebSocket(const std::string& docURL)
+ {
+ try {
+ UnitHTTPServerResponse response;
+ UnitHTTPServerRequest request(response, docURL);
+
+ _session = UnitHTTP::createSession();
+
+ // FIXME: leaking the session - hey ho ... do we need a UnitSocket ?
+ _socket = new LOOLWebSocket(*_session, request, response);
+ } catch (const Poco::Exception &ex) {
+ std::cerr << "Exception creating websocket " << ex.displayText() << std::endl;
+ throw;
+ }
+ }
+
~UnitWebSocket()
{
delete _socket;
delete _session;
}
- LOOLWebSocket* getLOOLWebSocket() const;
+ LOOLWebSocket* getLOOLWebSocket() const
+ {
+ return _socket;
+ }
};
#endif
commit a56bd374efbe9b1a71b6d288076105de72275c7c
Author: Michael Meeks <michael.meeks at collabora.com>
Date: Tue Apr 17 14:01:49 2018 +0100
Initial websocket test tool for remote admin connections.
Change-Id: I8be2068bf7d77c70720a044556d11f5fc80b2f0c
Reviewed-on: https://gerrit.libreoffice.org/53531
Reviewed-by: Michael Meeks <michael.meeks at collabora.com>
Tested-by: Michael Meeks <michael.meeks at collabora.com>
diff --git a/Makefile.am b/Makefile.am
index 3e12d50e5..07a00ab83 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,7 +2,9 @@ SUBDIRS = . test loleaflet
export ENABLE_DEBUG
-bin_PROGRAMS = loolwsd loolforkit loolmap loolmount looltool loolstress loolconfig
+bin_PROGRAMS = \
+ loolwsd loolforkit loolmap loolmount \
+ looltool loolstress loolconfig loolsocketdump
dist_bin_SCRIPTS = loolwsd-systemplate-setup
@@ -132,6 +134,9 @@ loolconfig_SOURCES = tools/Config.cpp \
common/Log.cpp \
common/Util.cpp
+loolsocketdump_SOURCES = tools/WebSocketDump.cpp \
+ $(shared_sources)
+
wsd_headers = wsd/Admin.hpp \
wsd/AdminModel.hpp \
wsd/Auth.hpp \
diff --git a/tools/Connect.cpp b/tools/Connect.cpp
index 1131d3303..84123c6c0 100644
--- a/tools/Connect.cpp
+++ b/tools/Connect.cpp
@@ -236,13 +236,10 @@ private:
namespace Util
{
-
-void alertAllUsers(const std::string& cmd, const std::string& kind)
-{
- std::cout << "error: cmd=" << cmd << " kind=" << kind << std::endl;
- (void) kind;
-}
-
+ void alertAllUsers(const std::string& cmd, const std::string& kind)
+ {
+ std::cout << "error: cmd=" << cmd << " kind=" << kind << std::endl;
+ }
}
POCO_APP_MAIN(Connect)
diff --git a/tools/WebSocketDump.cpp b/tools/WebSocketDump.cpp
new file mode 100644
index 000000000..a72e646c4
--- /dev/null
+++ b/tools/WebSocketDump.cpp
@@ -0,0 +1,240 @@
+/* -*- 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/.
+ */
+
+/* A simple tool that accepts web-socket connections and dumps the contents */
+
+#include <config.h>
+
+#include <unistd.h>
+
+#include <Poco/URI.h>
+#include <Poco/MemoryStream.h>
+#include <Poco/Net/HTTPRequest.h>
+#include <Poco/Net/HTTPResponse.h>
+#include <Poco/StringTokenizer.h>
+
+#include <Log.hpp>
+#include <Util.hpp>
+#include <Protocol.hpp>
+#include <ServerSocket.hpp>
+#include <WebSocketHandler.hpp>
+#if ENABLE_SSL
+# include <SslSocket.hpp>
+#endif
+
+// Dumps incoming websocket messages and doesn't respond.
+class DumpSocketHandler : public WebSocketHandler
+{
+public:
+ DumpSocketHandler()
+ {
+ }
+
+private:
+ /// Process incoming websocket messages
+ void handleMessage(bool fin, WSOpCode code, std::vector<char> &data)
+ {
+ std::cout << "WebSocket message code " << (int)code << " fin " << fin << " data:\n";
+ Util::dumpHex(std::cout, "", " ", data, false);
+ }
+};
+
+/// Handles incoming connections and dispatches to the appropriate handler.
+class ClientRequestDispatcher : public SocketHandlerInterface
+{
+public:
+ ClientRequestDispatcher()
+ {
+ }
+
+private:
+
+ /// Set the socket associated with this ResponseClient.
+ void onConnect(const std::shared_ptr<StreamSocket>& socket) override
+ {
+ _socket = socket;
+ LOG_TRC("#" << socket->getFD() << " Connected to ClientRequestDispatcher.");
+ }
+
+ /// Called after successful socket reads.
+ void handleIncomingMessage(SocketDisposition & /* disposition */) override
+ {
+ std::shared_ptr<StreamSocket> socket = _socket.lock();
+ std::vector<char>& in = socket->_inBuffer;
+ LOG_TRC("#" << socket->getFD() << " handling incoming " << in.size() << " bytes.");
+
+ // Find the end of the header, if any.
+ static const std::string marker("\r\n\r\n");
+ auto itBody = std::search(in.begin(), in.end(),
+ marker.begin(), marker.end());
+ if (itBody == in.end())
+ {
+ LOG_DBG("#" << socket->getFD() << " doesn't have enough data yet.");
+ return;
+ }
+
+ // Skip the marker.
+ itBody += marker.size();
+
+ Poco::MemoryInputStream message(&in[0], in.size());
+ Poco::Net::HTTPRequest request;
+ try
+ {
+ request.read(message);
+
+ Log::StreamLogger logger = Log::info();
+ if (logger.enabled())
+ {
+ logger << "#" << socket->getFD() << ": Client HTTP Request: "
+ << request.getMethod() << ' '
+ << request.getURI() << ' '
+ << request.getVersion();
+
+ for (const auto& it : request)
+ {
+ logger << " / " << it.first << ": " << it.second;
+ }
+
+ LOG_END(logger);
+ }
+
+ const std::streamsize contentLength = request.getContentLength();
+ const auto offset = itBody - in.begin();
+ const std::streamsize available = in.size() - offset;
+
+ if (contentLength != Poco::Net::HTTPMessage::UNKNOWN_CONTENT_LENGTH && available < contentLength)
+ {
+ LOG_DBG("Not enough content yet: ContentLength: " << contentLength << ", available: " << available);
+ return;
+ }
+ }
+ catch (const std::exception& exc)
+ {
+ // Probably don't have enough data just yet.
+ // TODO: timeout if we never get enough.
+ return;
+ }
+
+ try
+ {
+ // Routing
+ Poco::URI requestUri(request.getURI());
+ std::vector<std::string> reqPathSegs;
+ requestUri.getPathSegments(reqPathSegs);
+
+ LOG_INF("Incoming websocket request: " << request.getURI());
+
+ const std::string& requestURI = request.getURI();
+ Poco::StringTokenizer pathTokens(requestURI, "/", Poco::StringTokenizer::TOK_IGNORE_EMPTY |
+ Poco::StringTokenizer::TOK_TRIM);
+
+ if (request.find("Upgrade") != request.end() && Poco::icompare(request["Upgrade"], "websocket") == 0)
+ socket->setHandler(std::make_shared<DumpSocketHandler>());
+ else
+ {
+ Poco::Net::HTTPResponse response;
+ response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
+ response.setContentLength(0);
+ LOG_INF("DumpWebSockets bad request");
+ socket->send(response);
+ socket->shutdown();
+ }
+ }
+ catch (const std::exception& exc)
+ {
+ // Bad request.
+ std::ostringstream oss;
+ oss << "HTTP/1.1 400\r\n"
+ << "Date: " << Poco::DateTimeFormatter::format(Poco::Timestamp(), Poco::DateTimeFormat::HTTP_FORMAT) << "\r\n"
+ << "User-Agent: LOOLWSD WOPI Agent\r\n"
+ << "Content-Length: 0\r\n"
+ << "\r\n";
+ socket->send(oss.str());
+ socket->shutdown();
+
+ // NOTE: Check _wsState to choose between HTTP response or WebSocket (app-level) error.
+ LOG_INF("#" << socket->getFD() << " Exception while processing incoming request: [" <<
+ LOOLProtocol::getAbbreviatedMessage(in) << "]: " << exc.what());
+ }
+
+ // if we succeeded - remove the request from our input buffer
+ // we expect one request per socket
+ in.erase(in.begin(), itBody);
+ }
+
+ int getPollEvents(std::chrono::steady_clock::time_point /* now */,
+ int & /* timeoutMaxMs */) override
+ {
+ return POLLIN;
+ }
+
+ void performWrites() override
+ {
+ }
+
+private:
+ // The socket that owns us (we can't own it).
+ std::weak_ptr<StreamSocket> _socket;
+};
+
+class DumpSocketFactory final : public SocketFactory
+{
+ std::shared_ptr<Socket> create(const int physicalFd) override
+ {
+#if ENABLE_SSL
+ return StreamSocket::create<SslStreamSocket>(physicalFd, std::unique_ptr<SocketHandlerInterface>{ new ClientRequestDispatcher });
+#else
+ return StreamSocket::create<StreamSocket>(physicalFd, std::unique_ptr<SocketHandlerInterface>{ new ClientRequestDispatcher });
+#endif
+ }
+};
+
+namespace Util
+{
+ void alertAllUsers(const std::string& cmd, const std::string& kind)
+ {
+ std::cout << "error: cmd=" << cmd << " kind=" << kind << std::endl;
+ }
+}
+
+int main (int argc, char **argv)
+{
+ int port = 9042;
+ (void) argc; (void) argv;
+
+ SocketPoll acceptPoll("accept");
+ SocketPoll DumpSocketPoll("websocket");
+
+ // Setup listening socket with a factory for connected sockets.
+ auto serverSocket = std::make_shared<ServerSocket>(
+ Socket::Type::IPv4, DumpSocketPoll,
+ std::make_shared<DumpSocketFactory>());
+
+ if (!serverSocket->bind(ServerSocket::Type::Public, port))
+ {
+ fprintf(stderr, "Failed to bind websocket to port %d\n", port);
+ return -1;
+ }
+
+ if (!serverSocket->listen())
+ {
+ fprintf(stderr, "Failed to listen on websocket, port %d\n", port);
+ return -1;
+ }
+
+ acceptPoll.startThread();
+ acceptPoll.insertNewSocket(serverSocket);
+
+ while (true)
+ {
+ DumpSocketPoll.poll(1000);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
More information about the Libreoffice-commits
mailing list