Add memory limited dedicated compressors
This commit is contained in:
@@ -27,19 +27,10 @@
|
||||
#include "WebSocket.h"
|
||||
#include "WebSocketExtensions.h"
|
||||
#include "WebSocketHandshake.h"
|
||||
#include "PerMessageDeflate.h"
|
||||
|
||||
namespace uWS {
|
||||
|
||||
/* Compress options (really more like PerMessageDeflateOptions) */
|
||||
enum CompressOptions {
|
||||
/* Compression disabled */
|
||||
DISABLED = 0,
|
||||
/* We compress using a shared non-sliding window. No added memory usage, worse compression. */
|
||||
SHARED_COMPRESSOR = 1,
|
||||
/* We compress using a dedicated sliding window. Major memory usage added, better compression of similarly repeated messages. */
|
||||
DEDICATED_COMPRESSOR = 2
|
||||
};
|
||||
|
||||
template <bool SSL>
|
||||
struct TemplatedApp {
|
||||
private:
|
||||
@@ -130,7 +121,7 @@ public:
|
||||
if (!loopData->zlibContext) {
|
||||
loopData->zlibContext = new ZlibContext;
|
||||
loopData->inflationStream = new InflationStream;
|
||||
loopData->deflationStream = new DeflationStream;
|
||||
loopData->deflationStream = new DeflationStream(CompressOptions::DEDICATED_COMPRESSOR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,9 +164,10 @@ public:
|
||||
res->writeHeader("Sec-WebSocket-Protocol", secWebSocketProtocol.substr(0, secWebSocketProtocol.find(',')));
|
||||
}
|
||||
|
||||
/* Negotiate compression */
|
||||
/* Negotiate compression, we may use a smaller compression window than we negotiate */
|
||||
bool perMessageDeflate = false;
|
||||
bool slidingDeflateWindow = false;
|
||||
/* We are always allowed to share compressor, if perMessageDeflate */
|
||||
int compressOptions = behavior.compression & SHARED_COMPRESSOR;
|
||||
if (behavior.compression != DISABLED) {
|
||||
std::string_view extensions = req->getHeader("sec-websocket-extensions");
|
||||
if (extensions.length()) {
|
||||
@@ -205,7 +197,7 @@ public:
|
||||
|
||||
/* Is the server allowed to compress with a sliding window? */
|
||||
if (!(extensionsNegotiator.getNegotiatedOptions() & SERVER_NO_CONTEXT_TAKEOVER)) {
|
||||
slidingDeflateWindow = true;
|
||||
compressOptions = behavior.compression;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -231,7 +223,7 @@ public:
|
||||
|
||||
/* Initialize websocket with any moved backpressure intact */
|
||||
httpContext->upgradeToWebSocket(
|
||||
webSocket->init(perMessageDeflate, slidingDeflateWindow, std::move(backpressure))
|
||||
webSocket->init(perMessageDeflate, compressOptions, std::move(backpressure))
|
||||
);
|
||||
|
||||
/* Arm idleTimeout */
|
||||
|
||||
+58
-2
@@ -20,6 +20,28 @@
|
||||
#ifndef UWS_PERMESSAGEDEFLATE_H
|
||||
#define UWS_PERMESSAGEDEFLATE_H
|
||||
|
||||
/* We always define these options no matter if ZLIB is enabled or not */
|
||||
namespace uWS {
|
||||
/* Compress options (really more like PerMessageDeflateOptions) */
|
||||
enum CompressOptions : int {
|
||||
/* Compression disabled */
|
||||
DISABLED = 0,
|
||||
/* We compress using a shared non-sliding window. No added memory usage, worse compression. */
|
||||
SHARED_COMPRESSOR = 1,
|
||||
/* We compress using a dedicated sliding window. Major memory usage added, better compression of similarly repeated messages. */
|
||||
DEDICATED_COMPRESSOR = 2,
|
||||
/* Flags for limiting memory usage of dedicated compressor */
|
||||
DEDICATED_COMPRESSOR_2KB = 2 | 4,
|
||||
DEDICATED_COMPRESSOR_4KB = 2 | 8,
|
||||
DEDICATED_COMPRESSOR_8KB = 2 | 16,
|
||||
DEDICATED_COMPRESSOR_16KB = 2 | 32,
|
||||
DEDICATED_COMPRESSOR_32KB = 2 | 64,
|
||||
DEDICATED_COMPRESSOR_64KB = 2 | 128,
|
||||
DEDICATED_COMPRESSOR_128KB = 2 | 256,
|
||||
DEDICATED_COMPRESSOR_256KB = 2 | 512
|
||||
};
|
||||
}
|
||||
|
||||
#ifndef UWS_NO_ZLIB
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
@@ -68,8 +90,42 @@ struct ZlibContext {
|
||||
struct DeflationStream {
|
||||
z_stream deflationStream = {};
|
||||
|
||||
DeflationStream() {
|
||||
deflateInit2(&deflationStream, 1, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
|
||||
DeflationStream(int compressOptions) {
|
||||
|
||||
/* Sliding inflator should be about 44kb by default, less than compressor */
|
||||
|
||||
/* Memory usage is given by 2 ^ (windowBits + 2) + 2 ^ (memLevel + 9) */
|
||||
int windowBits = -15, memLevel = 8;
|
||||
|
||||
if (compressOptions == DEDICATED_COMPRESSOR_2KB) {
|
||||
windowBits = -8;
|
||||
memLevel = 1;
|
||||
} else if (compressOptions == DEDICATED_COMPRESSOR_4KB) {
|
||||
windowBits = -9;
|
||||
memLevel = 2;
|
||||
} else if (compressOptions == DEDICATED_COMPRESSOR_8KB) {
|
||||
windowBits = -10;
|
||||
memLevel = 3;
|
||||
} else if (compressOptions == DEDICATED_COMPRESSOR_16KB) {
|
||||
windowBits = -11;
|
||||
memLevel = 4;
|
||||
} else if (compressOptions == DEDICATED_COMPRESSOR_32KB) {
|
||||
windowBits = -12;
|
||||
memLevel = 5;
|
||||
} else if (compressOptions == DEDICATED_COMPRESSOR_64KB) {
|
||||
windowBits = -13;
|
||||
memLevel = 6;
|
||||
} else if (compressOptions == DEDICATED_COMPRESSOR_128KB) {
|
||||
windowBits = -14;
|
||||
memLevel = 7;
|
||||
} else if (compressOptions == DEDICATED_COMPRESSOR_256KB) {
|
||||
windowBits = -15;
|
||||
memLevel = 8;
|
||||
}
|
||||
|
||||
/* DEDICATED_COMPRESSOR_256KB is the same as DEDICATED_COMPRESSOR */
|
||||
|
||||
deflateInit2(&deflationStream, 1, Z_DEFLATED, windowBits, memLevel, Z_DEFAULT_STRATEGY);
|
||||
}
|
||||
|
||||
/* Deflate and optionally reset */
|
||||
|
||||
+2
-2
@@ -33,8 +33,8 @@ struct WebSocket : AsyncSocket<SSL> {
|
||||
private:
|
||||
typedef AsyncSocket<SSL> Super;
|
||||
|
||||
void *init(bool perMessageDeflate, bool slidingCompression, std::string &&backpressure) {
|
||||
new (us_socket_ext(SSL, (us_socket_t *) this)) WebSocketData(perMessageDeflate, slidingCompression, std::move(backpressure));
|
||||
void *init(bool perMessageDeflate, int compressOptions, std::string &&backpressure) {
|
||||
new (us_socket_ext(SSL, (us_socket_t *) this)) WebSocketData(perMessageDeflate, compressOptions, std::move(backpressure));
|
||||
return this;
|
||||
}
|
||||
public:
|
||||
|
||||
+3
-3
@@ -45,12 +45,12 @@ private:
|
||||
/* We could be a subscriber */
|
||||
Subscriber *subscriber = nullptr;
|
||||
public:
|
||||
WebSocketData(bool perMessageDeflate, bool slidingCompression, std::string &&backpressure) : AsyncSocketData<false>(std::move(backpressure)), WebSocketState<true>() {
|
||||
WebSocketData(bool perMessageDeflate, int compressOptions, std::string &&backpressure) : AsyncSocketData<false>(std::move(backpressure)), WebSocketState<true>() {
|
||||
compressionStatus = perMessageDeflate ? ENABLED : DISABLED;
|
||||
|
||||
/* Initialize the dedicated sliding window */
|
||||
if (perMessageDeflate && slidingCompression) {
|
||||
deflationStream = new DeflationStream;
|
||||
if (perMessageDeflate && (compressOptions & CompressOptions::DEDICATED_COMPRESSOR)) {
|
||||
deflationStream = new DeflationStream(compressOptions);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user