loolwsd/Connect.cpp | 11 ++++------ loolwsd/IoUtil.cpp | 42 ++++++++++++++++++++++++++++++----------- loolwsd/LOOLWSD.cpp | 5 +--- loolwsd/LOOLWebSocket.hpp | 21 ++++++++++++++++---- loolwsd/test/UnitFonts.cpp | 13 ++++++------ loolwsd/test/helpers.hpp | 40 +++++++++++++++++++++++++++------------ loolwsd/test/httpcrashtest.cpp | 9 +++----- loolwsd/test/httpwstest.cpp | 40 ++++++++++++++++----------------------- 8 files changed, 111 insertions(+), 70 deletions(-)
New commits: commit 4432aba25b6ee68356e0ddfc724afb8373651945 Author: Michael Meeks <michael.me...@collabora.com> Date: Fri Nov 25 09:48:59 2016 +0000 Revert "loolwsd: support reading long messages directly" This reverts commit 84607b43a31574533471defcb4756ba855f835f1. LOOLWebSocket piece requires a much too recent Poco. diff --git a/loolwsd/IoUtil.cpp b/loolwsd/IoUtil.cpp index adf5c55..035dcf8 100644 --- a/loolwsd/IoUtil.cpp +++ b/loolwsd/IoUtil.cpp @@ -50,17 +50,17 @@ void SocketProcessor(const std::shared_ptr<LOOLWebSocket>& ws, // Timeout given is in microseconds. static const Poco::Timespan waitTime(POLL_TIMEOUT_MS * 1000); - constexpr auto bufferSize = READ_BUFFER_SIZE * 8; - + const auto bufferSize = READ_BUFFER_SIZE * 100; int flags = 0; int n = -1; bool stop = false; std::vector<char> payload(bufferSize); - Poco::Buffer<char> buffer(bufferSize); try { ws->setReceiveTimeout(0); + payload.resize(0); + for (;;) { stop = stopPredicate(); @@ -79,12 +79,10 @@ void SocketProcessor(const std::shared_ptr<LOOLWebSocket>& ws, try { - payload.resize(0); - buffer.resize(0); + payload.resize(payload.capacity()); n = -1; - n = ws->receiveFrame(buffer, flags); - LOG_WRN("GOT: [" << LOOLProtocol::getAbbreviatedMessage(buffer.begin(), buffer.size()) << "]"); - payload.insert(payload.end(), buffer.begin(), buffer.end()); + n = ws->receiveFrame(payload.data(), payload.capacity(), flags); + payload.resize(n > 0 ? n : 0); } catch (const Poco::TimeoutException&) { @@ -101,7 +99,7 @@ void SocketProcessor(const std::shared_ptr<LOOLWebSocket>& ws, assert(n > 0); - const std::string firstLine = LOOLProtocol::getFirstLine(buffer.begin(), buffer.size()); + const std::string firstLine = LOOLProtocol::getFirstLine(payload); if ((flags & WebSocket::FrameFlags::FRAME_FLAG_FIN) != WebSocket::FrameFlags::FRAME_FLAG_FIN) { // One WS message split into multiple frames. @@ -109,7 +107,8 @@ void SocketProcessor(const std::shared_ptr<LOOLWebSocket>& ws, LOG_WRN("SocketProcessor [" << name << "]: Receiving multi-parm frame."); while (true) { - n = ws->receiveFrame(buffer, flags); + char buffer[READ_BUFFER_SIZE * 10]; + n = ws->receiveFrame(buffer, sizeof(buffer), flags); if (n <= 0 || (flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_CLOSE) { LOG_WRN("SocketProcessor [" << name << "]: Connection closed while reading multiframe message."); @@ -117,7 +116,7 @@ void SocketProcessor(const std::shared_ptr<LOOLWebSocket>& ws, break; } - payload.insert(payload.end(), buffer.begin(), buffer.end()); + payload.insert(payload.end(), buffer, buffer + n); if ((flags & WebSocket::FrameFlags::FRAME_FLAG_FIN) == WebSocket::FrameFlags::FRAME_FLAG_FIN) { // No more frames. @@ -125,6 +124,27 @@ void SocketProcessor(const std::shared_ptr<LOOLWebSocket>& ws, } } } + else + { + int size = 0; + Poco::StringTokenizer tokens(firstLine, " ", Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM); + // Check if it is a "nextmessage:" and in that case read the large + // follow-up message separately, and handle that only. + if (tokens.count() == 2 && tokens[0] == "nextmessage:" && + LOOLProtocol::getTokenInteger(tokens[1], "size", size) && size > 0) + { + LOG_TRC("SocketProcessor [" << name << "]: Getting large message of " << size << " bytes."); + if (size > MAX_MESSAGE_SIZE) + { + LOG_ERR("SocketProcessor [" << name << "]: Large-message size (" << size << ") over limit or invalid."); + } + else + { + payload.resize(size); + continue; + } + } + } if (n <= 0 || (flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_CLOSE) { diff --git a/loolwsd/LOOLWebSocket.hpp b/loolwsd/LOOLWebSocket.hpp index fb1d88b..e10af2a 100644 --- a/loolwsd/LOOLWebSocket.hpp +++ b/loolwsd/LOOLWebSocket.hpp @@ -108,39 +108,6 @@ public: return -1; } - - /// Wrapper for Poco::Net::WebSocket::receiveFrame() that handles PING frames - /// (by replying with a PONG frame) and PONG frames. PONG frames are ignored. - /// Should we also factor out the handling of non-final and continuation frames into this? - int receiveFrame(Poco::Buffer<char>& buffer, int& flags) - { -#ifdef ENABLE_DEBUG - // Delay receiving the frame - std::this_thread::sleep_for(getWebSocketDelay()); -#endif - // Timeout given is in microseconds. - static const Poco::Timespan waitTime(POLL_TIMEOUT_MS * 1000); - - while (poll(waitTime, Poco::Net::Socket::SELECT_READ)) - { - const int n = Poco::Net::WebSocket::receiveFrame(buffer, flags); - if (n > 0 && (flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_PING) - { - sendFrame(buffer.begin(), n, WebSocket::FRAME_FLAG_FIN | WebSocket::FRAME_OP_PONG); - } - else if ((flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_PONG) - { - // In case we do send pongs in the future. - } - else - { - return n; - } - } - - return -1; - } - /// Wrapper for Poco::Net::WebSocket::sendFrame() that handles large frames. int sendFrame(const char* buffer, const int length, const int flags = FRAME_TEXT) { @@ -150,6 +117,19 @@ public: #endif std::unique_lock<std::mutex> lock(_mutex); + // Size after which messages will be sent preceded with + // 'nextmessage' frame to let the receiver know in advance + // the size of larger coming message. All messages up to this + // size are considered small messages. + constexpr int SMALL_MESSAGE_SIZE = READ_BUFFER_SIZE / 2; + + if (length > SMALL_MESSAGE_SIZE) + { + const std::string nextmessage = "nextmessage: size=" + std::to_string(length); + Poco::Net::WebSocket::sendFrame(nextmessage.data(), nextmessage.size()); + Log::debug("Message is long, sent " + nextmessage); + } + const int result = Poco::Net::WebSocket::sendFrame(buffer, length, flags); lock.unlock(); diff --git a/loolwsd/test/helpers.hpp b/loolwsd/test/helpers.hpp index 7e5f039..30aeac1 100644 --- a/loolwsd/test/helpers.hpp +++ b/loolwsd/test/helpers.hpp @@ -197,7 +197,6 @@ std::vector<char> getResponseMessage(LOOLWebSocket& ws, const std::string& prefi int retries = timeoutMs / 500; const Poco::Timespan waitTime(retries ? timeoutMs * 1000 / retries : timeoutMs * 1000); std::vector<char> response; - Poco::Buffer<char> buffer(READ_BUFFER_SIZE); bool timedout = false; ws.setReceiveTimeout(0); @@ -211,10 +210,9 @@ std::vector<char> getResponseMessage(LOOLWebSocket& ws, const std::string& prefi timedout = false; } - response.resize(0); - buffer.resize(0); - const int bytes = ws.receiveFrame(buffer, flags); - response.insert(response.end(), buffer.begin(), buffer.end()); + response.resize(READ_BUFFER_SIZE); + int bytes = ws.receiveFrame(response.data(), response.size(), flags); + response.resize(bytes >= 0 ? bytes : 0); std::cerr << name << "Got " << LOOLProtocol::getAbbreviatedFrameDump(response.data(), bytes, flags) << std::endl; const auto message = LOOLProtocol::getFirstLine(response); if (bytes > 0 && (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) != Poco::Net::WebSocket::FRAME_OP_CLOSE) @@ -223,6 +221,26 @@ std::vector<char> getResponseMessage(LOOLWebSocket& ws, const std::string& prefi { return response; } + else if (LOOLProtocol::matchPrefix("nextmessage", message)) + { + int size = 0; + if (LOOLProtocol::getTokenIntegerFromMessage(message, "size", size) && size > 0) + { + response.resize(size); + bytes = ws.receiveFrame(response.data(), response.size(), flags); + response.resize(bytes >= 0 ? bytes : 0); + std::cerr << name << "Got " << LOOLProtocol::getAbbreviatedFrameDump(response.data(), bytes, flags) << std::endl; + if (bytes > 0 && + LOOLProtocol::matchPrefix(prefix, LOOLProtocol::getFirstLine(response))) + { + return response; + } + } + } + } + else + { + response.resize(0); } if (bytes <= 0) commit a2058341a389f09d8b8763a56aecbc0a1d3c7591 Author: Michael Meeks <michael.me...@collabora.com> Date: Fri Nov 25 09:46:01 2016 +0000 Revert "loolwsd: kill receiveFrame with char* and cleanup usage cases" This reverts commit 45c1856c6ad1753f8a90d3bb90711ab0338d623c. This patch requires a very bleeding edge Poco, reverting for now. diff --git a/loolwsd/Connect.cpp b/loolwsd/Connect.cpp index aad78fa..5b550dd 100644 --- a/loolwsd/Connect.cpp +++ b/loolwsd/Connect.cpp @@ -89,24 +89,23 @@ public: { do { - Poco::Buffer<char> buffer(READ_BUFFER_SIZE); - buffer.resize(0); - n = _ws.receiveFrame(buffer, flags); + char buffer[100000]; + n = _ws.receiveFrame(buffer, sizeof(buffer), flags); if (n > 0 && (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE) { { std::unique_lock<std::mutex> lock(coutMutex); - std::cout << "Got " << getAbbreviatedFrameDump(buffer.begin(), n, flags) << std::endl; + std::cout << "Got " << getAbbreviatedFrameDump(buffer, n, flags) << std::endl; } - const std::string firstLine = getFirstLine(buffer.begin(), n); + std::string firstLine = getFirstLine(buffer, n); StringTokenizer tokens(firstLine, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); if (std::getenv("DISPLAY") != nullptr && tokens[0] == "tile:") { TemporaryFile pngFile; std::ofstream pngStream(pngFile.path(), std::ios::binary); - pngStream.write(buffer.begin() + firstLine.size() + 1, n - firstLine.size() - 1); + pngStream.write(buffer + firstLine.size() + 1, n - firstLine.size() - 1); pngStream.close(); if (std::system((std::string("display ") + pngFile.path()).c_str()) == -1) { diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp index b7ad287..5ca3fce 100644 --- a/loolwsd/LOOLWSD.cpp +++ b/loolwsd/LOOLWSD.cpp @@ -196,7 +196,7 @@ void shutdownLimitReached(LOOLWebSocket& ws) { int flags = 0; int retries = 7; - Poco::Buffer<char> buffer(READ_BUFFER_SIZE); + std::vector<char> buffer(READ_BUFFER_SIZE * 100); const Poco::Timespan waitTime(POLL_TIMEOUT_MS * 1000); do @@ -214,8 +214,7 @@ void shutdownLimitReached(LOOLWebSocket& ws) // Ignore incoming messages. if (ws.poll(waitTime, Poco::Net::Socket::SELECT_READ)) { - buffer.resize(0); - ws.receiveFrame(buffer, flags); + ws.receiveFrame(buffer.data(), buffer.capacity(), flags); } // Shutdown. diff --git a/loolwsd/LOOLWebSocket.hpp b/loolwsd/LOOLWebSocket.hpp index 827c324..fb1d88b 100644 --- a/loolwsd/LOOLWebSocket.hpp +++ b/loolwsd/LOOLWebSocket.hpp @@ -79,6 +79,39 @@ public: /// Wrapper for Poco::Net::WebSocket::receiveFrame() that handles PING frames /// (by replying with a PONG frame) and PONG frames. PONG frames are ignored. /// Should we also factor out the handling of non-final and continuation frames into this? + int receiveFrame(char* buffer, const int length, int& flags) + { +#ifdef ENABLE_DEBUG + // Delay receiving the frame + std::this_thread::sleep_for(getWebSocketDelay()); +#endif + // Timeout given is in microseconds. + static const Poco::Timespan waitTime(POLL_TIMEOUT_MS * 1000); + + while (poll(waitTime, Poco::Net::Socket::SELECT_READ)) + { + const int n = Poco::Net::WebSocket::receiveFrame(buffer, length, flags); + if ((flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_PING) + { + sendFrame(buffer, n, WebSocket::FRAME_FLAG_FIN | WebSocket::FRAME_OP_PONG); + } + else if ((flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_PONG) + { + // In case we do send pongs in the future. + } + else + { + return n; + } + } + + return -1; + } + + + /// Wrapper for Poco::Net::WebSocket::receiveFrame() that handles PING frames + /// (by replying with a PONG frame) and PONG frames. PONG frames are ignored. + /// Should we also factor out the handling of non-final and continuation frames into this? int receiveFrame(Poco::Buffer<char>& buffer, int& flags) { #ifdef ENABLE_DEBUG diff --git a/loolwsd/test/UnitFonts.cpp b/loolwsd/test/UnitFonts.cpp index 232ecb2..60312d4 100644 --- a/loolwsd/test/UnitFonts.cpp +++ b/loolwsd/test/UnitFonts.cpp @@ -44,16 +44,17 @@ namespace { std::string readFontList(const std::shared_ptr<LOOLWebSocket> &socket) { int flags; - Poco::Buffer<char> buffer(READ_BUFFER_SIZE); + char buffer[100 * 1000]; - buffer.resize(0); - const int length = socket->receiveFrame(buffer, flags); + int length = socket->receiveFrame(buffer, sizeof (buffer), flags); if (length > 0) { - return std::string(buffer.begin(), length); + assert(length<(int)sizeof(buffer)); + buffer[length] = '\0'; + return std::string(buffer); } - - return std::string("read failure"); + else + return std::string("read failure"); } } diff --git a/loolwsd/test/helpers.hpp b/loolwsd/test/helpers.hpp index c6c730a..7e5f039 100644 --- a/loolwsd/test/helpers.hpp +++ b/loolwsd/test/helpers.hpp @@ -173,8 +173,7 @@ int getErrorCode(LOOLWebSocket& ws, std::string& message) ws.setReceiveTimeout(timeout); do { - buffer.resize(0); - bytes = ws.receiveFrame(buffer, flags); + bytes = ws.receiveFrame(buffer.begin(), READ_BUFFER_SIZE, flags); } while ((flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) != Poco::Net::WebSocket::FRAME_OP_CLOSE); @@ -410,7 +409,7 @@ void SocketProcessor(const std::string& name, const Poco::Timespan waitTime(timeoutMs * 1000); int flags = 0; int n = 0; - Poco::Buffer<char> buffer(READ_BUFFER_SIZE); + char buffer[READ_BUFFER_SIZE]; do { if (!socket->poll(waitTime, Poco::Net::Socket::SELECT_READ)) @@ -419,12 +418,11 @@ void SocketProcessor(const std::string& name, break; } - buffer.resize(0); - n = socket->receiveFrame(buffer, flags); - std::cerr << name << "Got " << LOOLProtocol::getAbbreviatedFrameDump(buffer.begin(), n, flags) << std::endl; + n = socket->receiveFrame(buffer, sizeof(buffer), flags); + std::cerr << name << "Got " << LOOLProtocol::getAbbreviatedFrameDump(buffer, n, flags) << std::endl; if (n > 0 && (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) != Poco::Net::WebSocket::FRAME_OP_CLOSE) { - if (!handler(std::string(buffer.begin(), n))) + if (!handler(std::string(buffer, n))) { break; } diff --git a/loolwsd/test/httpcrashtest.cpp b/loolwsd/test/httpcrashtest.cpp index b9a297c..1bfd4f2 100644 --- a/loolwsd/test/httpcrashtest.cpp +++ b/loolwsd/test/httpcrashtest.cpp @@ -164,12 +164,11 @@ void HTTPCrashTest::testCrashKit() // receive close frame handshake int bytes; int flags; - Poco::Buffer<char> buffer(READ_BUFFER_SIZE); + char buffer[READ_BUFFER_SIZE]; do { - buffer.resize(0); - bytes = socket->receiveFrame(buffer, flags); - std::cerr << testname << "Got " << LOOLProtocol::getAbbreviatedFrameDump(buffer.begin(), bytes, flags) << std::endl; + bytes = socket->receiveFrame(buffer, sizeof(buffer), flags); + std::cerr << testname << "Got " << LOOLProtocol::getAbbreviatedFrameDump(buffer, bytes, flags) << std::endl; } while ((flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) != Poco::Net::WebSocket::FRAME_OP_CLOSE); @@ -177,7 +176,7 @@ void HTTPCrashTest::testCrashKit() socket->shutdown(); // no more messages is received. - bytes = socket->receiveFrame(buffer, flags); + bytes = socket->receiveFrame(buffer, sizeof(buffer), flags); CPPUNIT_ASSERT_MESSAGE("Expected no more data", bytes <= 2); // The 2-byte marker is ok. CPPUNIT_ASSERT_EQUAL(0x88, flags); } diff --git a/loolwsd/test/httpwstest.cpp b/loolwsd/test/httpwstest.cpp index eeff3f4..1e65fc2 100644 --- a/loolwsd/test/httpwstest.cpp +++ b/loolwsd/test/httpwstest.cpp @@ -253,42 +253,37 @@ void HTTPWSTest::testHandShake() socket.setReceiveTimeout(0); int flags = 0; - Poco::Buffer<char> buffer(READ_BUFFER_SIZE); - buffer.resize(0); - int bytes = socket.receiveFrame(buffer, flags); - CPPUNIT_ASSERT_EQUAL(std::string("statusindicator: find"), std::string(buffer.begin(), bytes)); - - buffer.resize(0); - bytes = socket.receiveFrame(buffer, flags); - if (bytes > 0 && !std::strstr(buffer.begin(), "error:")) + char buffer[1024] = {0}; + int bytes = socket.receiveFrame(buffer, sizeof(buffer), flags); + CPPUNIT_ASSERT_EQUAL(std::string("statusindicator: find"), std::string(buffer, bytes)); + + bytes = socket.receiveFrame(buffer, sizeof(buffer), flags); + if (bytes > 0 && !std::strstr(buffer, "error:")) { - CPPUNIT_ASSERT_EQUAL(std::string("statusindicator: connect"), std::string(buffer.begin(), bytes)); + CPPUNIT_ASSERT_EQUAL(std::string("statusindicator: connect"), std::string(buffer, bytes)); - buffer.resize(0); - bytes = socket.receiveFrame(buffer, flags); - if (!std::strstr(buffer.begin(), "error:")) + bytes = socket.receiveFrame(buffer, sizeof(buffer), flags); + if (!std::strstr(buffer, "error:")) { - CPPUNIT_ASSERT_EQUAL(std::string("statusindicator: ready"), std::string(buffer.begin(), bytes)); + CPPUNIT_ASSERT_EQUAL(std::string("statusindicator: ready"), std::string(buffer, bytes)); } else { // check error message - CPPUNIT_ASSERT(std::strstr(SERVICE_UNAVAILABLE_INTERNAL_ERROR, buffer.begin()) != nullptr); + CPPUNIT_ASSERT(std::strstr(SERVICE_UNAVAILABLE_INTERNAL_ERROR, buffer) != nullptr); // close frame message - buffer.resize(0); - bytes = socket.receiveFrame(buffer, flags); + bytes = socket.receiveFrame(buffer, sizeof(buffer), flags); CPPUNIT_ASSERT((flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) == Poco::Net::WebSocket::FRAME_OP_CLOSE); } } else { // check error message - CPPUNIT_ASSERT(std::strstr(SERVICE_UNAVAILABLE_INTERNAL_ERROR, buffer.begin()) != nullptr); + CPPUNIT_ASSERT(std::strstr(SERVICE_UNAVAILABLE_INTERNAL_ERROR, buffer) != nullptr); // close frame message - buffer.resize(0); - bytes = socket.receiveFrame(buffer, flags); + bytes = socket.receiveFrame(buffer, sizeof(buffer), flags); CPPUNIT_ASSERT((flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) == Poco::Net::WebSocket::FRAME_OP_CLOSE); } } @@ -314,16 +309,15 @@ void HTTPWSTest::testCloseAfterClose() // receive close frame handshake int bytes; int flags; - Poco::Buffer<char> buffer(READ_BUFFER_SIZE); + char buffer[READ_BUFFER_SIZE]; do { - buffer.resize(0); - bytes = socket->receiveFrame(buffer, flags); + bytes = socket->receiveFrame(buffer, sizeof(buffer), flags); } while (bytes && (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) != Poco::Net::WebSocket::FRAME_OP_CLOSE); // no more messages is received. - bytes = socket->receiveFrame(buffer, flags); + bytes = socket->receiveFrame(buffer, sizeof(buffer), flags); std::cerr << "Received " << bytes << " bytes, flags: "<< std::hex << flags << std::dec << std::endl; CPPUNIT_ASSERT_EQUAL(0, bytes); CPPUNIT_ASSERT_EQUAL(0, flags); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits