From 21dea23fc6a4b2fc7902f31b0c4c2f097d9b50aa Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Fri, 21 Feb 2025 12:26:18 -0400 Subject: [PATCH] Upgrade uWebSockets to v20.73.0 (#211) Signed-off-by: Juan Cruz Viotti --- DEPENDENCIES | 2 +- vendor/uwebsockets.mask | 1 + vendor/uwebsockets/src/Loop.h | 16 +++++---- vendor/uwebsockets/src/PerMessageDeflate.h | 42 +++++++--------------- vendor/uwebsockets/src/TopicTree.h | 2 +- vendor/uwebsockets/src/WebSocket.h | 9 +++-- vendor/uwebsockets/src/WebSocketProtocol.h | 14 ++++---- 7 files changed, 36 insertions(+), 50 deletions(-) diff --git a/DEPENDENCIES b/DEPENDENCIES index ca8f0660..2b79cdc4 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -2,5 +2,5 @@ vendorpull https://github.com/sourcemeta/vendorpull 70342aaf458e6cb80baeb5b71890 core https://github.com/sourcemeta/core 47ba2307b9bfab9fb378386207b3172c97ed1363 bearssl https://www.bearssl.org/git/BearSSL 8ef7680081c61b486622f2d983c0d3d21e83caad zlib https://github.com/madler/zlib 51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf -uwebsockets https://github.com/uNetworking/uWebSockets v20.72.0 +uwebsockets https://github.com/uNetworking/uWebSockets v20.73.0 curl https://github.com/curl/curl curl-8_12_1 diff --git a/vendor/uwebsockets.mask b/vendor/uwebsockets.mask index 11e6317c..8e9fea74 100644 --- a/vendor/uwebsockets.mask +++ b/vendor/uwebsockets.mask @@ -23,3 +23,4 @@ uSockets/Makefile uSockets/module.modulemap uSockets/README.md h1spec +libdeflate diff --git a/vendor/uwebsockets/src/Loop.h b/vendor/uwebsockets/src/Loop.h index b612b6ec..61c2e089 100644 --- a/vendor/uwebsockets/src/Loop.h +++ b/vendor/uwebsockets/src/Loop.h @@ -126,15 +126,17 @@ struct Loop { LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this); - /* Initialize loop's deflate inflate streams */ - if (!loopData->zlibContext) { - loopData->zlibContext = new ZlibContext; - loopData->inflationStream = new InflationStream(CompressOptions::DEDICATED_DECOMPRESSOR); - loopData->deflationStream = new DeflationStream(CompressOptions::DEDICATED_COMPRESSOR); + if (compress) { + /* Initialize loop's deflate inflate streams */ + if (!loopData->zlibContext) { + loopData->zlibContext = new ZlibContext; + loopData->inflationStream = new InflationStream(CompressOptions::DEDICATED_DECOMPRESSOR); + loopData->deflationStream = new DeflationStream(CompressOptions::DEDICATED_COMPRESSOR); + } + + preparedMessage.compressedMessage = loopData->deflationStream->deflate(loopData->zlibContext, {preparedMessage.originalMessage.data(), preparedMessage.originalMessage.length()}, true); } - preparedMessage.compressedMessage = loopData->deflationStream->deflate(loopData->zlibContext, {preparedMessage.originalMessage.data(), preparedMessage.originalMessage.length()}, true); - return preparedMessage; } diff --git a/vendor/uwebsockets/src/PerMessageDeflate.h b/vendor/uwebsockets/src/PerMessageDeflate.h index 17832c71..5918e0ab 100644 --- a/vendor/uwebsockets/src/PerMessageDeflate.h +++ b/vendor/uwebsockets/src/PerMessageDeflate.h @@ -150,21 +150,6 @@ struct DeflationStream { /* Deflate and optionally reset. You must not deflate an empty string. */ std::string_view deflate(ZlibContext *zlibContext, std::string_view raw, bool reset) { -#ifdef UWS_USE_LIBDEFLATE - /* Run a fast path in case of shared_compressor */ - if (reset) { - size_t written = 0; - static unsigned char buf[1024 + 1]; - - written = libdeflate_deflate_compress(zlibContext->compressor, raw.data(), raw.length(), buf, 1024); - - if (written) { - memcpy(&buf[written], "\x00", 1); - return std::string_view((char *) buf, written + 1); - } - } -#endif - /* Odd place to clear this one, fix */ zlibContext->dynamicDeflationBuffer.clear(); @@ -228,20 +213,19 @@ struct InflationStream { std::optional inflate(ZlibContext *zlibContext, std::string_view compressed, size_t maxPayloadLength, bool reset) { #ifdef UWS_USE_LIBDEFLATE - /* Try fast path first */ - size_t written = 0; - static char buf[1024]; - - /* We have to pad 9 bytes and restore those bytes when done since 9 is more than 6 of next WebSocket message */ - char tmp[9]; - memcpy(tmp, (char *) compressed.data() + compressed.length(), 9); - memcpy((char *) compressed.data() + compressed.length(), "\x00\x00\xff\xff\x01\x00\x00\xff\xff", 9); - libdeflate_result res = libdeflate_deflate_decompress(zlibContext->decompressor, compressed.data(), compressed.length() + 9, buf, 1024, &written); - memcpy((char *) compressed.data() + compressed.length(), tmp, 9); - - if (res == 0) { - /* Fast path wins */ - return std::string_view(buf, written); + /* Try fast path first (assuming single DEFLATE block) */ + size_t written = 0, consumed; + zlibContext->dynamicInflationBuffer.clear(); + zlibContext->dynamicInflationBuffer.reserve(maxPayloadLength); + + ((char *)compressed.data())[0] |= 0x1; // BFINAL = 1 + libdeflate_result res = libdeflate_deflate_decompress_ex(zlibContext->decompressor, compressed.data(), compressed.length(), zlibContext->dynamicInflationBuffer.data(), maxPayloadLength, &consumed, &written); + + if (res == 0 && consumed == compressed.length()) { + return std::string_view(zlibContext->dynamicInflationBuffer.data(), written); + } else { + /* We can only end up here if the first DEFLATE block was not the last, so mark it as such */ + ((char *)compressed.data())[0] &= ~0x1; // BFINAL = 0 } #endif diff --git a/vendor/uwebsockets/src/TopicTree.h b/vendor/uwebsockets/src/TopicTree.h index 67a9a161..16b3f716 100644 --- a/vendor/uwebsockets/src/TopicTree.h +++ b/vendor/uwebsockets/src/TopicTree.h @@ -202,7 +202,7 @@ struct TopicTree { /* Remove us from topic */ topicPtr->erase(s); - int newCount = topicPtr->size(); + int newCount = (int) topicPtr->size(); /* If there is no subscriber to this topic, remove it */ if (!topicPtr->size()) { diff --git a/vendor/uwebsockets/src/WebSocket.h b/vendor/uwebsockets/src/WebSocket.h index 874c1f2d..199e2f44 100644 --- a/vendor/uwebsockets/src/WebSocket.h +++ b/vendor/uwebsockets/src/WebSocket.h @@ -101,12 +101,11 @@ struct WebSocket : AsyncSocket { } /* Experimental */ - void sendPrepared(PreparedMessage &preparedMessage) { - if (hasNegotiatedCompression() && preparedMessage.compressedMessage.length() < preparedMessage.originalMessage.length()) { - send({preparedMessage.compressedMessage.data(), preparedMessage.compressedMessage.length()}, (OpCode) preparedMessage.opCode, uWS::CompressFlags::ALREADY_COMPRESSED); - } else { - send({preparedMessage.originalMessage.data(), preparedMessage.originalMessage.length()}, (OpCode) preparedMessage.opCode); + SendStatus sendPrepared(PreparedMessage &preparedMessage) { + if (preparedMessage.compressed && hasNegotiatedCompression() && preparedMessage.compressedMessage.length() < preparedMessage.originalMessage.length()) { + return send({preparedMessage.compressedMessage.data(), preparedMessage.compressedMessage.length()}, (OpCode) preparedMessage.opCode, uWS::CompressFlags::ALREADY_COMPRESSED); } + return send({preparedMessage.originalMessage.data(), preparedMessage.originalMessage.length()}, (OpCode) preparedMessage.opCode); } /* Send or buffer a WebSocket frame, compressed or not. Returns BACKPRESSURE on increased user space backpressure, diff --git a/vendor/uwebsockets/src/WebSocketProtocol.h b/vendor/uwebsockets/src/WebSocketProtocol.h index a37120d2..15d57a91 100644 --- a/vendor/uwebsockets/src/WebSocketProtocol.h +++ b/vendor/uwebsockets/src/WebSocketProtocol.h @@ -28,13 +28,13 @@ namespace uWS { /* We should not overcomplicate these */ -const std::string_view ERR_TOO_BIG_MESSAGE("Received too big message"); -const std::string_view ERR_WEBSOCKET_TIMEOUT("WebSocket timed out from inactivity"); -const std::string_view ERR_INVALID_TEXT("Received invalid UTF-8"); -const std::string_view ERR_TOO_BIG_MESSAGE_INFLATION("Received too big message, or other inflation error"); -const std::string_view ERR_INVALID_CLOSE_PAYLOAD("Received invalid close payload"); -const std::string_view ERR_PROTOCOL("Received invalid WebSocket frame"); -const std::string_view ERR_TCP_FIN("Received TCP FIN before WebSocket close frame"); +constexpr std::string_view ERR_TOO_BIG_MESSAGE("Received too big message"); +constexpr std::string_view ERR_WEBSOCKET_TIMEOUT("WebSocket timed out from inactivity"); +constexpr std::string_view ERR_INVALID_TEXT("Received invalid UTF-8"); +constexpr std::string_view ERR_TOO_BIG_MESSAGE_INFLATION("Received too big message, or other inflation error"); +constexpr std::string_view ERR_INVALID_CLOSE_PAYLOAD("Received invalid close payload"); +constexpr std::string_view ERR_PROTOCOL("Received invalid WebSocket frame"); +constexpr std::string_view ERR_TCP_FIN("Received TCP FIN before WebSocket close frame"); enum OpCode : unsigned char { CONTINUATION = 0,