Never compress 0 bytes, finish pub/sub ded. compr.
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user