loolwsd/LOOLWSD.cpp | 170 +++++++++++++++++++++++++++------------------------- 1 file changed, 89 insertions(+), 81 deletions(-)
New commits: commit 7c92e263e808d75ffd79a12a1ae55b48de5ef187 Author: Ashod Nakashian <[email protected]> Date: Sat Mar 26 22:30:54 2016 -0400 loolwsd: improved websocket reading Change-Id: Ibedf3c6715742f18b5e4c80e47ceb0b4bf24f384 Reviewed-on: https://gerrit.libreoffice.org/23581 Reviewed-by: Ashod Nakashian <[email protected]> Tested-by: Ashod Nakashian <[email protected]> diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp index ce23783..749b2e2 100644 --- a/loolwsd/LOOLWSD.cpp +++ b/loolwsd/LOOLWSD.cpp @@ -221,112 +221,120 @@ public: // Handler returns false to end. void SocketProcessor(std::shared_ptr<WebSocket> ws, HTTPServerResponse& response, - std::function<bool(const char* data, const int size, const bool singleLine)> handler) + std::function<bool(const char* data, const int size)> handler) { Log::info("Starting Socket Processor."); const Timespan waitTime(POLL_TIMEOUT_MS * 1000); try { + ws->setReceiveTimeout(0); + int flags = 0; int n = 0; - ws->setReceiveTimeout(0); - do + std::vector<char> payload(READ_BUFFER_SIZE * 100); + + while (!TerminationFlag && + (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE) { - char buffer[200000]; //FIXME: Dynamic? + if (!ws->poll(waitTime, Socket::SELECT_READ)) + { + // Wait some more. + continue; + } - if (ws->poll(waitTime, Socket::SELECT_READ)) + payload.resize(payload.capacity()); + n = ws->receiveFrame(payload.data(), payload.capacity(), flags); + if (n >= 0) { - n = ws->receiveFrame(buffer, sizeof(buffer), flags); + payload.resize(n); + } - if ((flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_PING) - { - // Echo back the ping payload as pong. - // Technically, we should send back a PONG control frame. - // However Firefox (probably) or Node.js (possibly) doesn't - // like that and closes the socket when we do. - // Echoing the payload as a normal frame works with Firefox. - ws->sendFrame(buffer, n /*, WebSocket::FRAME_OP_PONG*/); - } - else if ((flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_PONG) - { - // In case we do send pings in the future. - } - else if (n <= 0) - { - // Connection closed. - Log::warn() << "Received " << n - << " bytes. Connection closed. Flags: " - << std::hex << flags << Log::end; - break; - } - else if ((flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE) - { - assert(n > 0); - const std::string firstLine = getFirstLine(buffer, n); - StringTokenizer tokens(firstLine, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); - int size; + if ((flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_PING) + { + // Echo back the ping payload as pong. + // Technically, we should send back a PONG control frame. + // However Firefox (probably) or Node.js (possibly) doesn't + // like that and closes the socket when we do. + // Echoing the payload as a normal frame works with Firefox. + ws->sendFrame(payload.data(), n /*, WebSocket::FRAME_OP_PONG*/); + } + else if ((flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_PONG) + { + // In case we do send pings in the future. + } + else if (n <= 0 || ((flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_CLOSE)) + { + // Connection closed. + Log::warn() << "Received " << n + << " bytes. Connection closed. Flags: " + << std::hex << flags << Log::end; + break; + } - if (firstLine == "eof") - { - Log::info("Received EOF. Finishing."); - break; - } + assert(n > 0); - if ((flags & WebSocket::FrameFlags::FRAME_FLAG_FIN) != WebSocket::FrameFlags::FRAME_FLAG_FIN) + const std::string firstLine = getFirstLine(payload.data(), payload.size()); + if ((flags & WebSocket::FrameFlags::FRAME_FLAG_FIN) != WebSocket::FrameFlags::FRAME_FLAG_FIN) + { + // One WS message split into multiple frames. + while (true) + { + 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) { - // One WS message split into multiple frames. - std::vector<char> message(buffer, buffer + n); - while (true) - { - n = ws->receiveFrame(buffer, sizeof(buffer), flags); - - if (n <= 0 || (flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_CLOSE) - break; - - message.insert(message.end(), buffer, buffer + n); - if ((flags & WebSocket::FrameFlags::FRAME_FLAG_FIN) == WebSocket::FrameFlags::FRAME_FLAG_FIN) - { - // No more frames: invoke the handler. Assume - // for now that this is always a multi-line - // message. - handler(message.data(), message.size(), false); - break; - } - } + break; } - else if (tokens.count() == 2 && - tokens[0] == "nextmessage:" && getTokenInteger(tokens[1], "size", size) && size > 0) - { - // Check if it is a "nextmessage:" and in that case read the large - // follow-up message separately, and handle that only. - - char largeBuffer[size]; //FIXME: Security risk! Flooding may segfault us. - n = ws->receiveFrame(largeBuffer, size, flags); - if (n > 0 && (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE && !handler(largeBuffer, n, false)) - { - Log::info("Socket handler flagged for finishing."); - break; - } - } - else if (firstLine.size() == static_cast<std::string::size_type>(n)) - { - handler(firstLine.c_str(), firstLine.size(), true); - } - else if (!handler(buffer, n, false)) + payload.insert(payload.end(), buffer, buffer + n); + if ((flags & WebSocket::FrameFlags::FRAME_FLAG_FIN) == WebSocket::FrameFlags::FRAME_FLAG_FIN) { - Log::info("Socket handler flagged for finishing."); + // No more frames. break; } } } + else + { + int size = 0; + StringTokenizer tokens(firstLine, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); + if (tokens.count() == 2 && + tokens[0] == "nextmessage:" && getTokenInteger(tokens[1], "size", size) && size > 0) + { + // Check if it is a "nextmessage:" and in that case read the large + // follow-up message separately, and handle that only. + payload.resize(size); + + n = ws->receiveFrame(payload.data(), size, flags); + } + } + + if (n <= 0 || (flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_CLOSE) + { + break; + } + + if (firstLine == "eof") + { + Log::info("Received EOF. Finishing."); + break; + } + + // Call the handler. + if (!handler(payload.data(), payload.size())) + { + Log::info("Socket handler flagged for finishing."); + } } - while (!TerminationFlag && - (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE); + Log::debug() << "Finishing SocketProcessor. TerminationFlag: " << TerminationFlag - << ", payload size: " << n + << ", payload size: " << payload.size() << ", flags: " << std::hex << flags << Log::end; + if (!payload.empty()) + { + Log::warn("Last message will not be processed: [" + getAbbreviatedMessage(payload.data(), payload.size()) + "]."); + } } catch (const WebSocketException& exc) { _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
