Do not expect a trailer after chunked body
This commit is contained in:
+10
-5
@@ -86,7 +86,7 @@ namespace uWS {
|
||||
}
|
||||
|
||||
/* Returns next chunk (empty or not), or if all data was consumed, nullopt is returned. */
|
||||
std::optional<std::string_view> getNextChunk(std::string_view &data, unsigned int &state) {
|
||||
std::optional<std::string_view> getNextChunk(std::string_view &data, unsigned int &state, bool trailer = false) {
|
||||
|
||||
while (data.length()) {
|
||||
|
||||
@@ -118,7 +118,11 @@ namespace uWS {
|
||||
//printf("Setting state to trailer-parsing and emitting empty chunk\n");
|
||||
|
||||
// set trailer state and increase size to 4
|
||||
state = 4 /*| STATE_IS_CHUNKED*/ | STATE_HAS_SIZE;
|
||||
if (trailer) {
|
||||
state = 4 /*| STATE_IS_CHUNKED*/ | STATE_HAS_SIZE;
|
||||
} else {
|
||||
state = 2 /*| STATE_IS_CHUNKED*/ | STATE_HAS_SIZE;
|
||||
}
|
||||
|
||||
return std::string_view(nullptr, 0);
|
||||
}
|
||||
@@ -174,9 +178,10 @@ namespace uWS {
|
||||
std::string_view *data;
|
||||
std::optional<std::string_view> chunk;
|
||||
unsigned int *state;
|
||||
bool trailer;
|
||||
|
||||
ChunkIterator(std::string_view *data, unsigned int *state) : data(data), state(state) {
|
||||
chunk = uWS::getNextChunk(*data, *state);
|
||||
ChunkIterator(std::string_view *data, unsigned int *state, bool trailer = false) : data(data), state(state), trailer(trailer) {
|
||||
chunk = uWS::getNextChunk(*data, *state, trailer);
|
||||
}
|
||||
|
||||
ChunkIterator() {
|
||||
@@ -203,7 +208,7 @@ namespace uWS {
|
||||
}
|
||||
|
||||
ChunkIterator &operator++() {
|
||||
chunk = uWS::getNextChunk(*data, *state);
|
||||
chunk = uWS::getNextChunk(*data, *state, trailer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
+133
-2
@@ -7,6 +7,99 @@
|
||||
|
||||
#include "../src/ChunkedEncoding.h"
|
||||
|
||||
void consumeChunkEncoding(int maxConsume, std::string_view &chunkEncoded, unsigned int &state) {
|
||||
//int maxConsume = 200;
|
||||
|
||||
if (uWS::isParsingChunkedEncoding(state)) {
|
||||
std::cout << "already in chunked parsing state!" << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
|
||||
// this should not break the parser
|
||||
state = uWS::STATE_IS_CHUNKED;
|
||||
|
||||
while (chunkEncoded.length()) {
|
||||
|
||||
/* Split up the chunkEncoded string into further chunks for parsing */
|
||||
std::string_view data = chunkEncoded.substr(0, std::min<size_t>(maxConsume, chunkEncoded.length()));
|
||||
unsigned int data_length_before_parsing = data.length();
|
||||
|
||||
for (auto chunk : uWS::ChunkIterator(&data, &state, true)) {
|
||||
}
|
||||
|
||||
/* Only remove that which was consumed */
|
||||
chunkEncoded.remove_prefix(data_length_before_parsing - data.length());
|
||||
|
||||
if (state == 0) {
|
||||
|
||||
if (chunkEncoded.length() == 0 || chunkEncoded.length() == 74) {
|
||||
break;
|
||||
} else {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
// should be fine
|
||||
state = uWS::STATE_IS_CHUNKED;
|
||||
|
||||
//std::cout << "remaining chunk:" << chunkEncoded.length() << std::endl;
|
||||
//std::abort();
|
||||
//break;
|
||||
}
|
||||
|
||||
/* Here we must be in parsingchunked state */
|
||||
if (!uWS::isParsingChunkedEncoding(state)) {
|
||||
std::cout << "not in parsing chunked strate!" << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void runBetterTest(unsigned int maxConsume) {
|
||||
/* A list of chunks */
|
||||
std::vector<std::string_view> chunks = {
|
||||
"Hello there I am the first segment",
|
||||
"Why hello there",
|
||||
"",
|
||||
"I am last?",
|
||||
"And I am a little longer but it doesn't matter",
|
||||
""
|
||||
};
|
||||
|
||||
/* Encode them in chunked encoding */
|
||||
std::stringstream ss;
|
||||
for (std::string_view chunk : chunks) {
|
||||
/* Generic chunked encoding format */
|
||||
ss << std::hex << chunk.length() << "\r\n" << chunk << "\r\n";
|
||||
|
||||
/* Every null chunk is followed by an empty trailer */
|
||||
if (chunk.length() == 0) {
|
||||
ss << "\r\n";
|
||||
}
|
||||
}
|
||||
std::string buffer = ss.str();
|
||||
std::string_view chunkEncoded = buffer;
|
||||
|
||||
unsigned int state = 0;
|
||||
|
||||
if (uWS::isParsingChunkedEncoding(state)) {
|
||||
std::abort();
|
||||
}
|
||||
consumeChunkEncoding(maxConsume, chunkEncoded, state);
|
||||
if (state != 0) {
|
||||
std::abort();
|
||||
}
|
||||
consumeChunkEncoding(maxConsume, chunkEncoded, state);
|
||||
if (state != 0) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
// consumeChunkEncoding(chunkEncoded) - consumes in further chunkes and does isParsingChunked checks
|
||||
// assume state == 0 and we still have bytes to parse (we should have consumed EXACTLY right bytes)
|
||||
// consumeChunkEncoding(chunkEncoded)
|
||||
// assume state == 0 and we have no bytes to consume
|
||||
}
|
||||
|
||||
void runTest(unsigned int maxConsume) {
|
||||
/* A list of chunks */
|
||||
std::vector<std::string_view> chunks = {
|
||||
@@ -39,6 +132,11 @@ void runTest(unsigned int maxConsume) {
|
||||
unsigned int chunkOffset = 0;
|
||||
std::string_view chunkEncoded = buffer;
|
||||
|
||||
// consumeChunkEncoding(chunkEncoded) - consumes in further chunkes and does isParsingChunked checks
|
||||
// assume state == 0 and we still have bytes to parse (we should have consumed EXACTLY right bytes)
|
||||
// consumeChunkEncoding(chunkEncoded)
|
||||
// assume state == 0 and we have no bytes to consume
|
||||
|
||||
// this while should be more like if original size or "is parsing chunked" (which tests the uWS::wantsChunkedParsing(state))
|
||||
while (chunkEncoded.length()) {
|
||||
/* Parse a small part of the given data */
|
||||
@@ -48,10 +146,9 @@ void runTest(unsigned int maxConsume) {
|
||||
unsigned int data_length_before_parsing = data.length();
|
||||
|
||||
|
||||
|
||||
/* Whatever chunk we emit, or part of chunk, it must match the expected one */
|
||||
//std::cout << "Calling parser now" << std::endl;
|
||||
for (auto chunk : uWS::ChunkIterator(&data, &state)) {
|
||||
for (auto chunk : uWS::ChunkIterator(&data, &state, true)) {
|
||||
std::cout << "<" << chunk << ">" << std::endl;
|
||||
|
||||
/* Run check here */
|
||||
@@ -87,7 +184,41 @@ void runTest(unsigned int maxConsume) {
|
||||
}
|
||||
}
|
||||
|
||||
void testWithoutTrailer() {
|
||||
/* A list of chunks */
|
||||
std::vector<std::string_view> chunks = {
|
||||
"Hello there I am the first segment",
|
||||
""
|
||||
};
|
||||
|
||||
/* Encode them in chunked encoding */
|
||||
std::stringstream ss;
|
||||
for (std::string_view chunk : chunks) {
|
||||
/* Generic chunked encoding format */
|
||||
ss << std::hex << chunk.length() << "\r\n" << chunk << "\r\n";
|
||||
}
|
||||
std::string buffer = ss.str();
|
||||
std::string_view dataToConsume(buffer.data(), buffer.length());
|
||||
|
||||
unsigned int state = uWS::STATE_IS_CHUNKED;
|
||||
|
||||
for (auto chunk : uWS::ChunkIterator(&dataToConsume, &state)) {
|
||||
|
||||
}
|
||||
|
||||
if (state) {
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
testWithoutTrailer();
|
||||
|
||||
for (int i = 1; i < 1000; i++) {
|
||||
runBetterTest(i);
|
||||
}
|
||||
|
||||
for (int i = 1; i < 1000; i++) {
|
||||
runTest(i);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user