From e0394289b6db96e3f0f5b5a2c4b660a71efea5f6 Mon Sep 17 00:00:00 2001 From: Alex Hultman Date: Tue, 26 Dec 2023 09:04:57 +0100 Subject: [PATCH] Experimental: bump 30 bit receive limit to 62 bit --- src/ChunkedEncoding.h | 34 +++++++++++++++++----------------- src/HttpParser.h | 12 ++++++------ tests/ChunkedEncoding.cpp | 8 ++++---- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/ChunkedEncoding.h b/src/ChunkedEncoding.h index a9b0162..9ecffd6 100644 --- a/src/ChunkedEncoding.h +++ b/src/ChunkedEncoding.h @@ -29,18 +29,18 @@ namespace uWS { - constexpr uint32_t STATE_HAS_SIZE = 0x80000000; - constexpr uint32_t STATE_IS_CHUNKED = 0x40000000; - constexpr uint32_t STATE_SIZE_MASK = 0x3FFFFFFF; - constexpr uint32_t STATE_IS_ERROR = 0xFFFFFFFF; - constexpr uint32_t STATE_SIZE_OVERFLOW = 0x0F000000; + constexpr uint64_t STATE_HAS_SIZE = 1ull << (sizeof(uint64_t) * 8 - 1);//0x80000000; + constexpr uint64_t STATE_IS_CHUNKED = 1ull << (sizeof(uint64_t) * 8 - 2);//0x40000000; + constexpr uint64_t STATE_SIZE_MASK = ~(3ull << (sizeof(uint64_t) * 8 - 2));//0x3FFFFFFF; + constexpr uint64_t STATE_IS_ERROR = ~0ull;//0xFFFFFFFF; + constexpr uint64_t STATE_SIZE_OVERFLOW = 0x0Full << (sizeof(uint64_t) * 8 - 8);//0x0F000000; - inline unsigned int chunkSize(unsigned int state) { + inline uint64_t chunkSize(uint64_t state) { return state & STATE_SIZE_MASK; } /* Reads hex number until CR or out of data to consume. Updates state. Returns bytes consumed. */ - inline void consumeHexNumber(std::string_view &data, unsigned int &state) { + inline void consumeHexNumber(std::string_view &data, uint64_t &state) { /* Consume everything higher than 32 */ while (data.length() && data.data()[0] > 32) { @@ -59,9 +59,9 @@ namespace uWS { } // extract state bits - unsigned int bits = /*state &*/ STATE_IS_CHUNKED; + uint64_t bits = /*state &*/ STATE_IS_CHUNKED; - state = (state & STATE_SIZE_MASK) * 16u + number; + state = (state & STATE_SIZE_MASK) * 16ull + number; state |= bits; data.remove_prefix(1); @@ -78,7 +78,7 @@ namespace uWS { } } - inline void decChunkSize(unsigned int &state, unsigned int by) { + inline void decChunkSize(uint64_t &state, unsigned int by) { //unsigned int bits = state & STATE_IS_CHUNKED; @@ -87,21 +87,21 @@ namespace uWS { //state |= bits; } - inline bool hasChunkSize(unsigned int state) { + inline bool hasChunkSize(uint64_t state) { return state & STATE_HAS_SIZE; } /* Are we in the middle of parsing chunked encoding? */ - inline bool isParsingChunkedEncoding(unsigned int state) { + inline bool isParsingChunkedEncoding(uint64_t state) { return state & ~STATE_SIZE_MASK; } - inline bool isParsingInvalidChunkedEncoding(unsigned int state) { + inline bool isParsingInvalidChunkedEncoding(uint64_t state) { return state == STATE_IS_ERROR; } /* Returns next chunk (empty or not), or if all data was consumed, nullopt is returned. */ - static std::optional getNextChunk(std::string_view &data, unsigned int &state, bool trailer = false) { + static std::optional getNextChunk(std::string_view &data, uint64_t &state, bool trailer = false) { while (data.length()) { @@ -167,7 +167,7 @@ namespace uWS { /* We will consume all our input data */ std::string_view emitSoon; if (chunkSize(state) > 2) { - unsigned int maximalAppEmit = chunkSize(state) - 2; + uint64_t maximalAppEmit = chunkSize(state) - 2; if (data.length() > maximalAppEmit) { emitSoon = data.substr(0, maximalAppEmit); } else { @@ -195,10 +195,10 @@ namespace uWS { std::string_view *data; std::optional chunk; - unsigned int *state; + uint64_t *state; bool trailer; - ChunkIterator(std::string_view *data, unsigned int *state, bool trailer = false) : data(data), state(state), trailer(trailer) { + ChunkIterator(std::string_view *data, uint64_t *state, bool trailer = false) : data(data), state(state), trailer(trailer) { chunk = uWS::getNextChunk(*data, *state, trailer); } diff --git a/src/HttpParser.h b/src/HttpParser.h index 5ff6cbd..ec11e6f 100644 --- a/src/HttpParser.h +++ b/src/HttpParser.h @@ -180,7 +180,7 @@ struct HttpParser { private: std::string fallback; /* This guy really has only 30 bits since we reserve two highest bits to chunked encoding parsing state */ - unsigned int remainingStreamingBytes = 0; + uint64_t remainingStreamingBytes = 0; /* Returns UINT_MAX on error. Maximum 999999999 is allowed. */ static unsigned int toUnsignedInteger(std::string_view str) { @@ -506,7 +506,7 @@ private: } if (!CONSUME_MINIMALLY) { - unsigned int emittable = std::min(remainingStreamingBytes, length); + unsigned int emittable = (unsigned int) std::min(remainingStreamingBytes, length); dataHandler(user, std::string_view(data, emittable), emittable == remainingStreamingBytes); remainingStreamingBytes -= emittable; @@ -561,8 +561,8 @@ public: } else { void *returnedUser = dataHandler(user, std::string_view(data, remainingStreamingBytes), true); - data += remainingStreamingBytes; - length -= remainingStreamingBytes; + data += (unsigned int) remainingStreamingBytes; + length -= (unsigned int) remainingStreamingBytes; remainingStreamingBytes = 0; @@ -617,8 +617,8 @@ public: } else { void *returnedUser = dataHandler(user, std::string_view(data, remainingStreamingBytes), true); - data += remainingStreamingBytes; - length -= remainingStreamingBytes; + data += (unsigned int) remainingStreamingBytes; + length -= (unsigned int) remainingStreamingBytes; remainingStreamingBytes = 0; diff --git a/tests/ChunkedEncoding.cpp b/tests/ChunkedEncoding.cpp index 0aa955b..2e6fd67 100644 --- a/tests/ChunkedEncoding.cpp +++ b/tests/ChunkedEncoding.cpp @@ -7,7 +7,7 @@ #include "../src/ChunkedEncoding.h" -void consumeChunkEncoding(int maxConsume, std::string_view &chunkEncoded, unsigned int &state) { +void consumeChunkEncoding(int maxConsume, std::string_view &chunkEncoded, uint64_t &state) { //int maxConsume = 200; if (uWS::isParsingChunkedEncoding(state)) { @@ -80,7 +80,7 @@ void runBetterTest(unsigned int maxConsume) { std::string buffer = ss.str(); std::string_view chunkEncoded = buffer; - unsigned int state = 0; + uint64_t state = 0; if (uWS::isParsingChunkedEncoding(state)) { std::abort(); @@ -128,7 +128,7 @@ void runTest(unsigned int maxConsume) { unsigned int stoppedWithClearState = 0; /* Begin with a clear state and the full data */ - unsigned int state = 0; + uint64_t state = 0; unsigned int chunkOffset = 0; std::string_view chunkEncoded = buffer; @@ -200,7 +200,7 @@ void testWithoutTrailer() { std::string buffer = ss.str(); std::string_view dataToConsume(buffer.data(), buffer.length()); - unsigned int state = uWS::STATE_IS_CHUNKED; + uint64_t state = uWS::STATE_IS_CHUNKED; for (auto chunk : uWS::ChunkIterator(&dataToConsume, &state)) {