Reject chunk size overflow, non-hex chunk size
This commit is contained in:
+21
-5
@@ -32,6 +32,12 @@ 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;
|
||||
|
||||
inline unsigned int chunkSize(unsigned int 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) {
|
||||
@@ -45,10 +51,17 @@ namespace uWS {
|
||||
digit = (unsigned char) (digit - ('A' - ':'));
|
||||
}
|
||||
|
||||
unsigned int number = ((unsigned int) digit - (unsigned int) '0');
|
||||
|
||||
if (number > 16 || (chunkSize(state) & STATE_SIZE_OVERFLOW)) {
|
||||
state = STATE_IS_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
// extract state bits
|
||||
unsigned int bits = /*state &*/ STATE_IS_CHUNKED;
|
||||
|
||||
state = (state & STATE_SIZE_MASK) * 16u + ((unsigned int) digit - (unsigned int) '0');
|
||||
state = (state & STATE_SIZE_MASK) * 16u + number;
|
||||
|
||||
state |= bits;
|
||||
data.remove_prefix(1);
|
||||
@@ -65,10 +78,6 @@ namespace uWS {
|
||||
}
|
||||
}
|
||||
|
||||
inline unsigned int chunkSize(unsigned int state) {
|
||||
return state & STATE_SIZE_MASK;
|
||||
}
|
||||
|
||||
inline void decChunkSize(unsigned int &state, unsigned int by) {
|
||||
|
||||
//unsigned int bits = state & STATE_IS_CHUNKED;
|
||||
@@ -87,6 +96,10 @@ namespace uWS {
|
||||
return state & ~STATE_SIZE_MASK;
|
||||
}
|
||||
|
||||
inline bool isParsingInvalidChunkedEncoding(unsigned int state) {
|
||||
return state == STATE_IS_ERROR;
|
||||
}
|
||||
|
||||
/* Returns next chunk (empty or not), or if all data was consumed, nullopt is returned. */
|
||||
static std::optional<std::string_view> getNextChunk(std::string_view &data, unsigned int &state, bool trailer = false) {
|
||||
|
||||
@@ -115,6 +128,9 @@ namespace uWS {
|
||||
|
||||
if (!hasChunkSize(state)) {
|
||||
consumeHexNumber(data, state);
|
||||
if (isParsingInvalidChunkedEncoding(state)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (hasChunkSize(state) && chunkSize(state) == 2) {
|
||||
|
||||
//printf("Setting state to trailer-parsing and emitting empty chunk\n");
|
||||
|
||||
@@ -481,6 +481,9 @@ private:
|
||||
for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) {
|
||||
dataHandler(user, chunk, chunk.length() == 0);
|
||||
}
|
||||
if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {
|
||||
return {0, FULLPTR};
|
||||
}
|
||||
unsigned int consumed = (length - (unsigned int) dataToConsume.length());
|
||||
data = (char *) dataToConsume.data();
|
||||
length = (unsigned int) dataToConsume.length();
|
||||
@@ -530,6 +533,9 @@ public:
|
||||
for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) {
|
||||
dataHandler(user, chunk, chunk.length() == 0);
|
||||
}
|
||||
if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) {
|
||||
return FULLPTR;
|
||||
}
|
||||
data = (char *) dataToConsume.data();
|
||||
length = (unsigned int) dataToConsume.length();
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user