Add memory limited dedicated compressors
This commit is contained in:
@@ -27,19 +27,10 @@
|
|||||||
#include "WebSocket.h"
|
#include "WebSocket.h"
|
||||||
#include "WebSocketExtensions.h"
|
#include "WebSocketExtensions.h"
|
||||||
#include "WebSocketHandshake.h"
|
#include "WebSocketHandshake.h"
|
||||||
|
#include "PerMessageDeflate.h"
|
||||||
|
|
||||||
namespace uWS {
|
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>
|
template <bool SSL>
|
||||||
struct TemplatedApp {
|
struct TemplatedApp {
|
||||||
private:
|
private:
|
||||||
@@ -130,7 +121,7 @@ public:
|
|||||||
if (!loopData->zlibContext) {
|
if (!loopData->zlibContext) {
|
||||||
loopData->zlibContext = new ZlibContext;
|
loopData->zlibContext = new ZlibContext;
|
||||||
loopData->inflationStream = new InflationStream;
|
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(',')));
|
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 perMessageDeflate = false;
|
||||||
bool slidingDeflateWindow = false;
|
/* We are always allowed to share compressor, if perMessageDeflate */
|
||||||
|
int compressOptions = behavior.compression & SHARED_COMPRESSOR;
|
||||||
if (behavior.compression != DISABLED) {
|
if (behavior.compression != DISABLED) {
|
||||||
std::string_view extensions = req->getHeader("sec-websocket-extensions");
|
std::string_view extensions = req->getHeader("sec-websocket-extensions");
|
||||||
if (extensions.length()) {
|
if (extensions.length()) {
|
||||||
@@ -205,7 +197,7 @@ public:
|
|||||||
|
|
||||||
/* Is the server allowed to compress with a sliding window? */
|
/* Is the server allowed to compress with a sliding window? */
|
||||||
if (!(extensionsNegotiator.getNegotiatedOptions() & SERVER_NO_CONTEXT_TAKEOVER)) {
|
if (!(extensionsNegotiator.getNegotiatedOptions() & SERVER_NO_CONTEXT_TAKEOVER)) {
|
||||||
slidingDeflateWindow = true;
|
compressOptions = behavior.compression;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,7 +223,7 @@ public:
|
|||||||
|
|
||||||
/* Initialize websocket with any moved backpressure intact */
|
/* Initialize websocket with any moved backpressure intact */
|
||||||
httpContext->upgradeToWebSocket(
|
httpContext->upgradeToWebSocket(
|
||||||
webSocket->init(perMessageDeflate, slidingDeflateWindow, std::move(backpressure))
|
webSocket->init(perMessageDeflate, compressOptions, std::move(backpressure))
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Arm idleTimeout */
|
/* Arm idleTimeout */
|
||||||
|
|||||||
+58
-2
@@ -20,6 +20,28 @@
|
|||||||
#ifndef UWS_PERMESSAGEDEFLATE_H
|
#ifndef UWS_PERMESSAGEDEFLATE_H
|
||||||
#define 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
|
#ifndef UWS_NO_ZLIB
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -68,8 +90,42 @@ struct ZlibContext {
|
|||||||
struct DeflationStream {
|
struct DeflationStream {
|
||||||
z_stream deflationStream = {};
|
z_stream deflationStream = {};
|
||||||
|
|
||||||
DeflationStream() {
|
DeflationStream(int compressOptions) {
|
||||||
deflateInit2(&deflationStream, 1, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
|
|
||||||
|
/* 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 */
|
/* Deflate and optionally reset */
|
||||||
|
|||||||
+2
-2
@@ -33,8 +33,8 @@ struct WebSocket : AsyncSocket<SSL> {
|
|||||||
private:
|
private:
|
||||||
typedef AsyncSocket<SSL> Super;
|
typedef AsyncSocket<SSL> Super;
|
||||||
|
|
||||||
void *init(bool perMessageDeflate, bool slidingCompression, std::string &&backpressure) {
|
void *init(bool perMessageDeflate, int compressOptions, std::string &&backpressure) {
|
||||||
new (us_socket_ext(SSL, (us_socket_t *) this)) WebSocketData(perMessageDeflate, slidingCompression, std::move(backpressure));
|
new (us_socket_ext(SSL, (us_socket_t *) this)) WebSocketData(perMessageDeflate, compressOptions, std::move(backpressure));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
|
|||||||
+3
-3
@@ -45,12 +45,12 @@ private:
|
|||||||
/* We could be a subscriber */
|
/* We could be a subscriber */
|
||||||
Subscriber *subscriber = nullptr;
|
Subscriber *subscriber = nullptr;
|
||||||
public:
|
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;
|
compressionStatus = perMessageDeflate ? ENABLED : DISABLED;
|
||||||
|
|
||||||
/* Initialize the dedicated sliding window */
|
/* Initialize the dedicated sliding window */
|
||||||
if (perMessageDeflate && slidingCompression) {
|
if (perMessageDeflate && (compressOptions & CompressOptions::DEDICATED_COMPRESSOR)) {
|
||||||
deflationStream = new DeflationStream;
|
deflationStream = new DeflationStream(compressOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user