mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
wip
This commit is contained in:
@@ -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 = 0x8000000000000000;
|
||||
constexpr uint64_t STATE_IS_CHUNKED = 0x4000000000000000;
|
||||
constexpr uint64_t STATE_SIZE_MASK = 0x3FFFFFFFFFFFFFFF;
|
||||
constexpr uint64_t STATE_IS_ERROR = 0xFFFFFFFFFFFFFFFF;
|
||||
constexpr uint64_t STATE_SIZE_OVERFLOW = 0x0F00000000000000;
|
||||
|
||||
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) {
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace uWS {
|
||||
digit = (unsigned char) (digit - ('A' - ':'));
|
||||
}
|
||||
|
||||
unsigned int number = ((unsigned int) digit - (unsigned int) '0');
|
||||
uint64_t number = ((uint64_t) digit - (uint64_t) '0');
|
||||
|
||||
if (number > 16 || (chunkSize(state) & STATE_SIZE_OVERFLOW)) {
|
||||
state = STATE_IS_ERROR;
|
||||
@@ -59,7 +59,7 @@ 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;
|
||||
|
||||
@@ -78,30 +78,30 @@ namespace uWS {
|
||||
}
|
||||
}
|
||||
|
||||
inline void decChunkSize(unsigned int &state, unsigned int by) {
|
||||
inline void decChunkSize(uint64_t &state, uint64_t by) {
|
||||
|
||||
//unsigned int bits = state & STATE_IS_CHUNKED;
|
||||
//uint64_t bits = state & STATE_IS_CHUNKED;
|
||||
|
||||
state = (state & ~STATE_SIZE_MASK) | (chunkSize(state) - by);
|
||||
|
||||
//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<std::string_view> getNextChunk(std::string_view &data, unsigned int &state, bool trailer = false) {
|
||||
static std::optional<std::string_view> getNextChunk(std::string_view &data, uint64_t &state, bool trailer = false) {
|
||||
while (data.length()) {
|
||||
|
||||
// if in "drop trailer mode", just drop up to what we have as size
|
||||
@@ -166,7 +166,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 {
|
||||
@@ -174,7 +174,7 @@ namespace uWS {
|
||||
emitSoon = data;
|
||||
}
|
||||
}
|
||||
decChunkSize(state, (unsigned int) data.length());
|
||||
decChunkSize(state, (uint64_t) data.length());
|
||||
state |= STATE_IS_CHUNKED;
|
||||
// new: decrease data by its size (bug)
|
||||
data.remove_prefix(data.length()); // ny bug fix för getNextChunk
|
||||
@@ -194,10 +194,10 @@ namespace uWS {
|
||||
|
||||
std::string_view *data;
|
||||
std::optional<std::string_view> 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -199,29 +199,29 @@ namespace uWS
|
||||
|
||||
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;
|
||||
/* This guy really has only 62 bits since we reserve two highest bits to chunked encoding parsing state */
|
||||
std::uint64_t remainingStreamingBytes = 0;
|
||||
|
||||
const size_t MAX_FALLBACK_SIZE = 1024 * 4;
|
||||
|
||||
/* Returns UINT_MAX on error. Maximum 999999999 is allowed. */
|
||||
static unsigned int toUnsignedInteger(std::string_view str)
|
||||
/* Returns UINT64_MAX on error. Maximum 999999999999999999 is allowed. */
|
||||
static std::uint64_t toUnsignedInteger(std::string_view str)
|
||||
{
|
||||
/* We assume at least 32-bit integer giving us safely 999999999 (9 number of 9s) */
|
||||
if (str.length() > 9)
|
||||
/* We assume 999999999999999999 (18 number of 9s) */
|
||||
if (str.length() > 18)
|
||||
{
|
||||
return UINT_MAX;
|
||||
return UINT64_MAX;
|
||||
}
|
||||
|
||||
unsigned int unsignedIntegerValue = 0;
|
||||
uint64_t unsignedIntegerValue = 0;
|
||||
for (char c : str)
|
||||
{
|
||||
/* As long as the letter is 0-9 we cannot overflow. */
|
||||
if (c < '0' || c > '9')
|
||||
{
|
||||
return UINT_MAX;
|
||||
return UINT64_MAX;
|
||||
}
|
||||
unsignedIntegerValue = unsignedIntegerValue * 10u + ((unsigned int)c - (unsigned int)'0');
|
||||
unsignedIntegerValue = unsignedIntegerValue * 10ull + ((uint64_t)c - (uint64_t)'0');
|
||||
}
|
||||
return unsignedIntegerValue;
|
||||
}
|
||||
@@ -474,7 +474,7 @@ namespace uWS
|
||||
* or [consumed, nullptr] for "break; I am closed or upgraded to websocket"
|
||||
* or [whatever, fullptr] for "break and close me, I am a parser error!" */
|
||||
template <int CONSUME_MINIMALLY>
|
||||
std::pair<unsigned int, void *> fenceAndConsumePostPadded(char *data, unsigned int length, void *user, void *reserved, HttpRequest *req, MoveOnlyFunction<void *(void *, HttpRequest *)> &requestHandler, MoveOnlyFunction<void *(void *, std::string_view, bool)> &dataHandler)
|
||||
std::pair<uint64_t, void *> fenceAndConsumePostPadded(char *data, uint64_t length, void *user, void *reserved, HttpRequest *req, MoveOnlyFunction<void *(void *, HttpRequest *)> &requestHandler, MoveOnlyFunction<void *(void *, std::string_view, bool)> &dataHandler)
|
||||
{
|
||||
|
||||
/* How much data we CONSUMED (to throw away) */
|
||||
@@ -574,16 +574,16 @@ namespace uWS
|
||||
{
|
||||
return {0, FULLPTR};
|
||||
}
|
||||
unsigned int consumed = (length - (unsigned int)dataToConsume.length());
|
||||
uint64_t consumed = (length - (uint64_t)dataToConsume.length());
|
||||
data = (char *)dataToConsume.data();
|
||||
length = (unsigned int)dataToConsume.length();
|
||||
length = (uint64_t)dataToConsume.length();
|
||||
consumedTotal += consumed;
|
||||
}
|
||||
}
|
||||
else if (contentLengthString.length())
|
||||
{
|
||||
remainingStreamingBytes = toUnsignedInteger(contentLengthString);
|
||||
if (remainingStreamingBytes == UINT_MAX)
|
||||
if (remainingStreamingBytes == UINT16_MAX)
|
||||
{
|
||||
/* Parser error */
|
||||
return {0, FULLPTR};
|
||||
@@ -591,7 +591,7 @@ namespace uWS
|
||||
|
||||
if (!CONSUME_MINIMALLY)
|
||||
{
|
||||
unsigned int emittable = std::min<unsigned int>(remainingStreamingBytes, length);
|
||||
uint64_t emittable = std::min<uint64_t>(remainingStreamingBytes, length);
|
||||
dataHandler(user, std::string_view(data, emittable), emittable == remainingStreamingBytes);
|
||||
remainingStreamingBytes -= emittable;
|
||||
|
||||
@@ -616,7 +616,7 @@ namespace uWS
|
||||
}
|
||||
|
||||
public:
|
||||
void *consumePostPadded(char *data, unsigned int length, void *user, void *reserved, MoveOnlyFunction<void *(void *, HttpRequest *)> &&requestHandler, MoveOnlyFunction<void *(void *, std::string_view, bool)> &&dataHandler, MoveOnlyFunction<void *(void *)> &&errorHandler)
|
||||
void *consumePostPadded(char *data, uint64_t length, void *user, void *reserved, MoveOnlyFunction<void *(void *, HttpRequest *)> &&requestHandler, MoveOnlyFunction<void *(void *, std::string_view, bool)> &&dataHandler, MoveOnlyFunction<void *(void *)> &&errorHandler)
|
||||
{
|
||||
/* This resets BloomFilter by construction, but later we also reset it again.
|
||||
* Optimize this to skip resetting twice (req could be made global) */
|
||||
@@ -638,7 +638,7 @@ namespace uWS
|
||||
return FULLPTR;
|
||||
}
|
||||
data = (char *)dataToConsume.data();
|
||||
length = (unsigned int)dataToConsume.length();
|
||||
length = (uint64_t)dataToConsume.length();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -688,7 +688,7 @@ namespace uWS
|
||||
fallback.append(data, maxCopyDistance);
|
||||
|
||||
// break here on break
|
||||
std::pair<unsigned int, void *> consumed = fenceAndConsumePostPadded<true>(fallback.data(), (unsigned int)fallback.length(), user, reserved, &req, requestHandler, dataHandler);
|
||||
std::pair<uint64_t, void *> consumed = fenceAndConsumePostPadded<true>(fallback.data(), (unsigned int)fallback.length(), user, reserved, &req, requestHandler, dataHandler);
|
||||
if (consumed.second != user)
|
||||
{
|
||||
return consumed.second;
|
||||
@@ -759,7 +759,7 @@ namespace uWS
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<unsigned int, void *> consumed = fenceAndConsumePostPadded<false>(data, length, user, reserved, &req, requestHandler, dataHandler);
|
||||
std::pair<uint64_t, void *> consumed = fenceAndConsumePostPadded<false>(data, length, user, reserved, &req, requestHandler, dataHandler);
|
||||
if (consumed.second != user)
|
||||
{
|
||||
return consumed.second;
|
||||
|
||||
Reference in New Issue
Block a user