[Libreoffice-commits] online.git: Branch 'private/Ashod/nonblocking' - 2 commits - net/loolnb.cpp net/Socket.hpp net/WebSocketHandler.hpp wsd/LOOLWSD.cpp

Jan Holesovsky kendy at collabora.com
Thu Mar 2 09:52:13 UTC 2017


 net/Socket.hpp           |    3 ++
 net/WebSocketHandler.hpp |   59 +++++++++++++++++++++++++++++++++++++++++---
 net/loolnb.cpp           |   62 ++++++++++++++++++++++++++++++++++++++++++++---
 wsd/LOOLWSD.cpp          |   50 +++----------------------------------
 4 files changed, 121 insertions(+), 53 deletions(-)

New commits:
commit 0aa1b7c468ad999688b8ea8b96f7b5baea2b13a7
Author: Jan Holesovsky <kendy at collabora.com>
Date:   Thu Mar 2 10:39:24 2017 +0100

    nb: It seems uppercase 'S' is preferred in Sec-WebSocket-Accept.
    
    Change-Id: I6cc86f26cf7e3c9370e5d534877bfeeb6607f5a4

diff --git a/net/WebSocketHandler.hpp b/net/WebSocketHandler.hpp
index 55f0048..feae544 100644
--- a/net/WebSocketHandler.hpp
+++ b/net/WebSocketHandler.hpp
@@ -334,7 +334,7 @@ protected:
         oss << "HTTP/1.1 101 Switching Protocols\r\n"
             << "Upgrade: websocket\r\n"
             << "Connection: Upgrade\r\n"
-            << "Sec-Websocket-Accept: " << PublicComputeAccept::doComputeAccept(wsKey) << "\r\n"
+            << "Sec-WebSocket-Accept: " << PublicComputeAccept::doComputeAccept(wsKey) << "\r\n"
             << "\r\n";
 
         socket->send(oss.str());
commit 0f0fb31e98432a7cb99a81e30136b24a1f43441e
Author: Jan Holesovsky <kendy at collabora.com>
Date:   Thu Mar 2 10:38:49 2017 +0100

    nb: Make the loolnb / clientnb work again.
    
    The more testing the better :-)
    
    Change-Id: Ibe4249f18109d50b06e1fa35e6d0fef67f9b3643

diff --git a/net/Socket.hpp b/net/Socket.hpp
index 55f264a..026a414 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -569,8 +569,11 @@ protected:
     std::mutex _writeMutex;
 
     // To be able to access _inBuffer and _outBuffer.
+    // TODO we probably need accessors to the _inBuffer & _outBuffer
+    // instead of this many friends...
     friend class WebSocketHandler;
     friend class ClientRequestDispatcher;
+    friend class SimpleResponseClient;
 };
 
 namespace HttpHelper
diff --git a/net/WebSocketHandler.hpp b/net/WebSocketHandler.hpp
index b55c4f2..55f0048 100644
--- a/net/WebSocketHandler.hpp
+++ b/net/WebSocketHandler.hpp
@@ -14,12 +14,18 @@
 #include "Log.hpp"
 #include "Socket.hpp"
 
+#include <Poco/Net/HTTPRequest.h>
+#include <Poco/Net/WebSocket.h>
+
 class WebSocketHandler : public SocketHandlerInterface
 {
+protected:
     // The socket that owns us (we can't own it).
     std::weak_ptr<StreamSocket> _socket;
+
     std::vector<char> _wsPayload;
     bool _shuttingDown;
+    enum class WSState { HTTP, WS } _wsState;
 
     enum class WSFrameMask : unsigned char
     {
@@ -27,16 +33,21 @@ class WebSocketHandler : public SocketHandlerInterface
         Mask = 0x80
     };
 
+
 public:
     WebSocketHandler() :
-        _shuttingDown(false)
+        _shuttingDown(false),
+        _wsState(WSState::HTTP)
     {
     }
 
-    WebSocketHandler(const std::weak_ptr<StreamSocket>& socket) :
-        _shuttingDown(false)
+    /// Upgrades itself to a websocket directly.
+    WebSocketHandler(const std::weak_ptr<StreamSocket>& socket, const Poco::Net::HTTPRequest& request) :
+        _socket(socket),
+        _shuttingDown(false),
+        _wsState(WSState::HTTP)
     {
-        onConnect(socket);
+        upgradeToWebSocket(request);
     }
 
     /// Implementation of the SocketHandlerInterface.
@@ -289,6 +300,46 @@ protected:
     virtual void handleMessage(bool /*fin*/, WSOpCode /*code*/, std::vector<char> &/*data*/)
     {
     }
+
+private:
+    /// To make the protected 'computeAccept' accessible.
+    class PublicComputeAccept : public Poco::Net::WebSocket
+    {
+    public:
+        static std::string doComputeAccept(const std::string &key)
+        {
+            return computeAccept(key);
+        }
+    };
+
+protected:
+    /// Upgrade the http(s) connection to a websocket.
+    void upgradeToWebSocket(const Poco::Net::HTTPRequest& req)
+    {
+        LOG_TRC("Upgrading to WebSocket");
+        assert(_wsState == WSState::HTTP);
+
+        auto socket = _socket.lock();
+        if (socket == nullptr)
+            throw std::runtime_error("Invalid socket while upgrading to WebSocket. Request: " + req.getURI());
+
+        // create our websocket goodness ...
+        const int wsVersion = std::stoi(req.get("Sec-WebSocket-Version", "13"));
+        const std::string wsKey = req.get("Sec-WebSocket-Key", "");
+        const std::string wsProtocol = req.get("Sec-WebSocket-Protocol", "chat");
+        // FIXME: other sanity checks ...
+        LOG_INF("WebSocket version " << wsVersion << " key '" << wsKey << "'.");
+
+        std::ostringstream oss;
+        oss << "HTTP/1.1 101 Switching Protocols\r\n"
+            << "Upgrade: websocket\r\n"
+            << "Connection: Upgrade\r\n"
+            << "Sec-Websocket-Accept: " << PublicComputeAccept::doComputeAccept(wsKey) << "\r\n"
+            << "\r\n";
+
+        socket->send(oss.str());
+        _wsState = WSState::WS;
+    }
 };
 
 #endif
diff --git a/net/loolnb.cpp b/net/loolnb.cpp
index f568821..6623bc0 100644
--- a/net/loolnb.cpp
+++ b/net/loolnb.cpp
@@ -20,7 +20,6 @@
 
 #include <Poco/MemoryStream.h>
 #include <Poco/Net/SocketAddress.h>
-#include <Poco/Net/HTTPRequest.h>
 #include <Poco/Util/ServerApplication.h>
 #include <Poco/StringTokenizer.h>
 #include <Poco/Runnable.h>
@@ -46,6 +45,63 @@ public:
     {
     }
 
+    virtual void handleIncomingMessage() override
+    {
+        LOG_TRC("incoming WebSocket message");
+        if (_wsState == WSState::HTTP)
+        {
+            auto socket = _socket.lock();
+
+            int number = 0;
+            Poco::MemoryInputStream message(&socket->_inBuffer[0], socket->_inBuffer.size());
+            Poco::Net::HTTPRequest req;
+            req.read(message);
+
+            // if we succeeded - remove that from our input buffer
+            // FIXME: We should check if this is GET or POST. For GET, we only
+            // can have a single request (headers only). For POST, we can/should
+            // use Poco HTMLForm to parse the post message properly.
+            // Otherwise, we should catch exceptions from the previous read/parse
+            // and assume we don't have sufficient data, so we wait some more.
+            socket->_inBuffer.clear();
+
+            LOG_DBG("URI: " << req.getURI());
+
+            Poco::StringTokenizer tokens(req.getURI(), "/?");
+            if (tokens.count() == 4)
+            {
+                std::string subpool = tokens[2];
+                number = std::stoi(tokens[3]);
+
+                // complex algorithmic core:
+                number = number + 1;
+
+                std::string numberString = std::to_string(number);
+                std::ostringstream oss;
+                oss << "HTTP/1.1 200 OK\r\n"
+                    << "Date: Once, Upon a time GMT\r\n" // Mon, 27 Jul 2009 12:28:53 GMT
+                    << "Server: madeup string (Linux)\r\n"
+                    << "Content-Length: " << numberString.size() << "\r\n"
+                    << "Content-Type: text/plain\r\n"
+                    << "Connection: Closed\r\n"
+                    << "\r\n"
+                    << numberString;
+                ;
+                std::string str = oss.str();
+                socket->_outBuffer.insert(socket->_outBuffer.end(), str.begin(), str.end());
+                return;
+            }
+            else if (tokens.count() == 2 && tokens[1] == "ws")
+            {
+
+                upgradeToWebSocket(req);
+                return;
+            }
+        }
+
+        WebSocketHandler::handleIncomingMessage();
+    }
+
     virtual void handleMessage(const bool fin, const WSOpCode code, std::vector<char> &data) override
     {
         std::cerr << "Message: fin? " << fin << " code " << code << " data size " << data.size();
@@ -182,7 +238,7 @@ public:
         {
             std::shared_ptr<Socket> create(const int fd) override
             {
-                return std::make_shared<StreamSocket>(fd, std::unique_ptr<SocketHandlerInterface>{ new SimpleResponseClient });
+                return StreamSocket::create<StreamSocket>(fd, std::unique_ptr<SocketHandlerInterface>{ new SimpleResponseClient });
             }
         };
 
@@ -191,7 +247,7 @@ public:
         {
             std::shared_ptr<Socket> create(const int fd) override
             {
-                return std::make_shared<SslStreamSocket>(fd, std::unique_ptr<SocketHandlerInterface>{ new SimpleResponseClient });
+                return StreamSocket::create<SslStreamSocket>(fd, std::unique_ptr<SocketHandlerInterface>{ new SimpleResponseClient });
             }
         };
 
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 73f5454..9229168 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -2580,8 +2580,7 @@ static std::shared_ptr<ClientSession> createNewClientSession(const WebSocketHand
 class ClientRequestDispatcher : public SocketHandlerInterface
 {
 public:
-    ClientRequestDispatcher() :
-        _wsState(WSState::HTTP)
+    ClientRequestDispatcher()
     {
     }
 
@@ -3125,7 +3124,7 @@ private:
         LOG_INF("Client WS request" << request.getURI() << ", url: " << url);
 
         // First Upgrade.
-        WebSocketHandler ws = upgradeToWebSocket(request);
+        WebSocketHandler ws(_socket, request);
 
         if (_connectionNum > MAX_CONNECTIONS)
         {
@@ -3206,7 +3205,8 @@ private:
         LOG_CHECK_RET(docBroker && "Null DocumentBroker instance", );
         const auto docKey = docBroker->getDocKey();
 
-        WebSocketHandler ws(_socket);
+        WebSocketHandler ws;
+        ws.onConnect(_socket);
         try
         {
             // Connection terminated. Destroy session.
@@ -3281,54 +3281,12 @@ private:
         }
     }
 
-    /// Upgrade the http(s) connection to a websocket.
-    WebSocketHandler upgradeToWebSocket(const Poco::Net::HTTPRequest& req)
-    {
-        LOG_TRC("Upgrading to WebSocket");
-        assert(_wsState == WSState::HTTP);
-
-        auto socket = _socket.lock();
-        if (socket == nullptr)
-            throw std::runtime_error("Invalid socket while upgrading to WebSocket. Request: " + req.getURI());
-
-        // create our websocket goodness ...
-        const int wsVersion = std::stoi(req.get("Sec-WebSocket-Version", "13"));
-        const std::string wsKey = req.get("Sec-WebSocket-Key", "");
-        const std::string wsProtocol = req.get("Sec-WebSocket-Protocol", "chat");
-        // FIXME: other sanity checks ...
-        LOG_INF("WebSocket version " << wsVersion << " key '" << wsKey << "'.");
-
-        std::ostringstream oss;
-        oss << "HTTP/1.1 101 Switching Protocols\r\n"
-            << "Upgrade: websocket\r\n"
-            << "Connection: Upgrade\r\n"
-            << "Sec-Websocket-Accept: " << PublicComputeAccept::doComputeAccept(wsKey) << "\r\n"
-            << "\r\n";
-
-        socket->send(oss.str());
-        _wsState = WSState::WS;
-
-        // Create a WS wrapper to use for sending the client status.
-        return WebSocketHandler(socket);
-    }
-
-    /// To make the protected 'computeAccept' accessible.
-    class PublicComputeAccept : public Poco::Net::WebSocket
-    {
-    public:
-        static std::string doComputeAccept(const std::string &key)
-        {
-            return computeAccept(key);
-        }
-    };
-
 private:
     // The socket that owns us (we can't own it).
     std::weak_ptr<StreamSocket> _socket;
     std::shared_ptr<ClientSession> _clientSession;
     std::string _id;
     size_t _connectionNum;
-    enum class WSState { HTTP, WS } _wsState;
 };
 
 


More information about the Libreoffice-commits mailing list