[Libreoffice-commits] online.git: loolwsd/LOOLWSD.cpp
Ashod Nakashian
ashod.nakashian at collabora.co.uk
Tue Mar 29 02:46:06 UTC 2016
loolwsd/LOOLWSD.cpp | 170 +++++++++++++++++++++++++++-------------------------
1 file changed, 89 insertions(+), 81 deletions(-)
New commits:
commit 7c92e263e808d75ffd79a12a1ae55b48de5ef187
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
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 <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
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)
{
More information about the Libreoffice-commits
mailing list