[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