Never compress 0 bytes, finish pub/sub ded. compr.

This commit is contained in:
Alex Hultman
2020-06-22 07:10:43 +02:00
parent e9e6d3fa34
commit f52d816032
5 changed files with 21 additions and 10 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ int main() {
/* Very simple WebSocket broadcasting echo server */ /* Very simple WebSocket broadcasting echo server */
uWS::App().ws<PerSocketData>("/*", { uWS::App().ws<PerSocketData>("/*", {
/* Settings */ /* Settings */
.compression = uWS::SHARED_COMPRESSOR, .compression = uWS::DEDICATED_COMPRESSOR_3KB,
.maxPayloadLength = 16 * 1024 * 1024, .maxPayloadLength = 16 * 1024 * 1024,
.idleTimeout = 10, .idleTimeout = 10,
.maxBackpressure = 1 * 1024 * 1024, .maxBackpressure = 1 * 1024 * 1024,
+1 -1
View File
@@ -28,7 +28,7 @@ int main() {
/* Open event here, you may access ws->getUserData() which points to a PerSocketData struct */ /* Open event here, you may access ws->getUserData() which points to a PerSocketData struct */
}, },
.message = [](auto *ws, std::string_view message, uWS::OpCode opCode) { .message = [](auto *ws, std::string_view message, uWS::OpCode opCode) {
ws->send(message, opCode); ws->send(message, opCode, true);
}, },
.drain = [](auto *ws) { .drain = [](auto *ws) {
/* Check ws->getBufferedAmount() here */ /* Check ws->getBufferedAmount() here */
+3 -1
View File
@@ -131,7 +131,7 @@ struct DeflationStream {
deflateInit2(&deflationStream, 1, Z_DEFLATED, windowBits, memLevel, Z_DEFAULT_STRATEGY); deflateInit2(&deflationStream, 1, Z_DEFLATED, windowBits, memLevel, Z_DEFAULT_STRATEGY);
} }
/* Deflate and optionally reset */ /* Deflate and optionally reset. You must not deflate an empty string. */
std::string_view deflate(ZlibContext *zlibContext, std::string_view raw, bool reset) { std::string_view deflate(ZlibContext *zlibContext, std::string_view raw, bool reset) {
/* Odd place to clear this one, fix */ /* Odd place to clear this one, fix */
zlibContext->dynamicDeflationBuffer.clear(); zlibContext->dynamicDeflationBuffer.clear();
@@ -167,6 +167,8 @@ struct DeflationStream {
return {(char *) zlibContext->dynamicDeflationBuffer.data(), zlibContext->dynamicDeflationBuffer.length() - 4}; return {(char *) zlibContext->dynamicDeflationBuffer.data(), zlibContext->dynamicDeflationBuffer.length() - 4};
} }
/* Note: We will get an interger overflow resulting in heap buffer overflow if Z_BUF_ERROR is returned
* from passing 0 as avail_in. Therefore we must not deflate an empty string */
return { return {
zlibContext->deflationBuffer, zlibContext->deflationBuffer,
DEFLATE_OUTPUT_CHUNK - deflationStream.avail_out - 4 DEFLATE_OUTPUT_CHUNK - deflationStream.avail_out - 4
+3 -3
View File
@@ -71,8 +71,8 @@ public:
if (compress) { if (compress) {
WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData(); WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData();
/* Check and correct the compress hint */ /* Check and correct the compress hint. It is never valid to compress 0 bytes */
if (opCode < 3 && webSocketData->compressionStatus == WebSocketData::ENABLED) { if (message.length() && opCode < 3 && webSocketData->compressionStatus == WebSocketData::ENABLED) {
LoopData *loopData = Super::getLoopData(); LoopData *loopData = Super::getLoopData();
/* Compress using either shared or dedicated deflationStream */ /* Compress using either shared or dedicated deflationStream */
if (webSocketData->deflationStream) { if (webSocketData->deflationStream) {
@@ -94,7 +94,7 @@ public:
/* Get size, alloate size, write if needed */ /* Get size, alloate size, write if needed */
size_t messageFrameSize = protocol::messageFrameSize(message.length()); size_t messageFrameSize = protocol::messageFrameSize(message.length());
auto[sendBuffer, requiresWrite] = Super::getSendBuffer(messageFrameSize); auto [sendBuffer, requiresWrite] = Super::getSendBuffer(messageFrameSize);
protocol::formatMessage<isServer>(sendBuffer, message.data(), message.length(), opCode, message.length(), compress); protocol::formatMessage<isServer>(sendBuffer, message.data(), message.length(), opCode, message.length(), compress);
/* This is the slow path, when we couldn't cork for the user */ /* This is the slow path, when we couldn't cork for the user */
if (requiresWrite) { if (requiresWrite) {
+13 -4
View File
@@ -92,15 +92,22 @@ public:
WebSocket<SSL, true> *ws = (WebSocket<SSL, true> *) asyncSocket; WebSocket<SSL, true> *ws = (WebSocket<SSL, true> *) asyncSocket;
/* We need to handle being corked, and corking here */ /* We need to handle being corked, and corking here */
bool needsUncorking = false;
if (!ws->isCorked() && ws->canCork()) {
asyncSocket->cork();
needsUncorking = true;
}
while (selectedData.length()) { while (selectedData.length()) {
/* Interpret the data like so */ /* Interpret the data like so, because this is how we shoved it in */
MessageMetadata mm; MessageMetadata mm;
memcpy((char *) &mm, selectedData.data(), sizeof(MessageMetadata)); memcpy((char *) &mm, selectedData.data(), sizeof(MessageMetadata));
std::string_view unframedMessage(selectedData.data() + sizeof(MessageMetadata), mm.length); std::string_view unframedMessage(selectedData.data() + sizeof(MessageMetadata), mm.length);
//std::cout << "<" << unframedMessage << ">" << std::endl; /* Skip this message if our backpressure is too high */
if (maxBackpressure && ws->getBufferedAmount() > maxBackpressure) {
break;
}
/* Here we perform the actual compression and framing */ /* Here we perform the actual compression and framing */
ws->send(unframedMessage, mm.opCode, mm.compress); ws->send(unframedMessage, mm.opCode, mm.compress);
@@ -110,7 +117,9 @@ public:
} }
/* Here we need to uncork or keep it as was */ /* Here we need to uncork or keep it as was */
if (needsUncorking) {
asyncSocket->uncork();
}
/* See below */ /* See below */
return 0; return 0;