Add randomly chunked HTTP parsing stress test, fix bugs
This commit is contained in:
+40
-3
@@ -58,6 +58,10 @@ struct HttpRequest {
|
|||||||
headers->valueLength = std::max<int>(0, headers->valueLength - 9);
|
headers->valueLength = std::max<int>(0, headers->valueLength - 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cursor == nullptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return cursor - data;
|
return cursor - data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +102,7 @@ struct HttpRequest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class HttpParser {
|
class HttpParser {
|
||||||
private:
|
public://private:
|
||||||
std::string fallback;
|
std::string fallback;
|
||||||
int remainingStreamingBytes = 0;
|
int remainingStreamingBytes = 0;
|
||||||
|
|
||||||
@@ -134,6 +138,8 @@ public:
|
|||||||
int emittable = std::min(remainingStreamingBytes, length);
|
int emittable = std::min(remainingStreamingBytes, length);
|
||||||
dataHandler(user, std::string_view(data, emittable));
|
dataHandler(user, std::string_view(data, emittable));
|
||||||
remainingStreamingBytes -= emittable;
|
remainingStreamingBytes -= emittable;
|
||||||
|
|
||||||
|
data += emittable; // denna var buggen?
|
||||||
length -= emittable;
|
length -= emittable;
|
||||||
|
|
||||||
ret += emittable;
|
ret += emittable;
|
||||||
@@ -177,9 +183,39 @@ public:
|
|||||||
fallback.reserve(maxCopyDistance + 32); // padding should be same as libus
|
fallback.reserve(maxCopyDistance + 32); // padding should be same as libus
|
||||||
fallback.append(data, maxCopyDistance);
|
fallback.append(data, maxCopyDistance);
|
||||||
|
|
||||||
|
// helst ska denna inte emitta någon data alls, vi gör det efteråt!
|
||||||
if (int consumed = fenceAndConsumePostPadded<true>(fallback.data(), fallback.length(), user, &req, requestHandler, dataHandler); consumed) {
|
if (int consumed = fenceAndConsumePostPadded<true>(fallback.data(), fallback.length(), user, &req, requestHandler, dataHandler); consumed) {
|
||||||
|
|
||||||
|
// I guess?
|
||||||
|
fallback.clear();
|
||||||
|
|
||||||
data += consumed - had;
|
data += consumed - had;
|
||||||
length -= consumed - had;
|
length -= consumed - had;
|
||||||
|
|
||||||
|
// ska vi inte tömma fallback här?
|
||||||
|
|
||||||
|
|
||||||
|
// exakt samma if-sats som ovan!
|
||||||
|
if (remainingStreamingBytes) {
|
||||||
|
// at this point we reset the timeout timer, we are streaming and we got a chunk
|
||||||
|
|
||||||
|
if (remainingStreamingBytes >= length) {
|
||||||
|
dataHandler(user, std::string_view(data, length));
|
||||||
|
remainingStreamingBytes -= length;
|
||||||
|
// no change to the socket here! we read all data in the buffer, return
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
dataHandler(user, std::string_view(data, remainingStreamingBytes));
|
||||||
|
|
||||||
|
data += remainingStreamingBytes;
|
||||||
|
length -= remainingStreamingBytes;
|
||||||
|
|
||||||
|
remainingStreamingBytes = 0;
|
||||||
|
|
||||||
|
// okay we are done with that, let's parse some more
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (fallback.length() == MAX_FALLBACK_SIZE) {
|
if (fallback.length() == MAX_FALLBACK_SIZE) {
|
||||||
// here we failed to parse any header in the 4kb we were given!
|
// here we failed to parse any header in the 4kb we were given!
|
||||||
@@ -191,6 +227,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int consumed = fenceAndConsumePostPadded<false>(data, length, user, &req, requestHandler, dataHandler);
|
int consumed = fenceAndConsumePostPadded<false>(data, length, user, &req, requestHandler, dataHandler);
|
||||||
|
|
||||||
data += consumed;
|
data += consumed;
|
||||||
length -= consumed;
|
length -= consumed;
|
||||||
|
|
||||||
@@ -198,8 +235,8 @@ public:
|
|||||||
if (length < MAX_FALLBACK_SIZE) {
|
if (length < MAX_FALLBACK_SIZE) {
|
||||||
fallback.append(data, length);
|
fallback.append(data, length);
|
||||||
} else {
|
} else {
|
||||||
// invalid http!
|
std::cout << "tail is invalid http!" << std::endl;
|
||||||
std::cout << "invalid http! fuck off!" << std::endl;
|
exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+58
-6
@@ -5,20 +5,72 @@
|
|||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
// todo: random test of chunked http parsing of randomly generated requests
|
||||||
void testHttpParserPerformance() {
|
void testHttpParserPerformance() {
|
||||||
|
|
||||||
char data[] = "GET /hello.htm HTTP/1.1\r\n"
|
char headers[] = "GET /hello.htm HTTP/1.1\r\n"
|
||||||
"User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)\r\n"
|
"User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)\r\n"
|
||||||
"Host: www.tutorialspoint.com\r\n"
|
"Host: www.tutorialspoint.com\r\n"
|
||||||
"Accept-Language: en-us\r\n"
|
"Accept-Language: en-us\r\n"
|
||||||
"Accept-Encoding: gzip, deflate\r\n"
|
"Accept-Encoding: gzip, deflate\r\n"
|
||||||
"Connection: Keep-Alive\r\n\r\n ";
|
"Connection: Keep-Alive\r\n"
|
||||||
|
"Content-length: 1048576\r\n\r\n";
|
||||||
|
|
||||||
|
const int requestLength = sizeof(headers) - 1 + 1048576;
|
||||||
|
char *request = (char *) malloc(requestLength + 32);
|
||||||
|
memset(request, 0, requestLength);
|
||||||
|
memcpy(request, headers, sizeof(headers) - 1);
|
||||||
|
|
||||||
|
char *data = (char *) malloc(requestLength * 10);
|
||||||
|
int length = requestLength * 10;
|
||||||
|
//int currentOffset = 0;
|
||||||
|
|
||||||
|
|
||||||
|
int maxChunkSize = 10000;
|
||||||
|
char *paddedBuffer = (char *) malloc(maxChunkSize + 32);
|
||||||
|
|
||||||
|
// dela upp dessa 10 i 5 segment
|
||||||
HttpParser httpParser;
|
HttpParser httpParser;
|
||||||
|
|
||||||
int validRequests = 0;
|
int validRequests = 0;
|
||||||
|
size_t dataBytes = 0;
|
||||||
|
|
||||||
auto start = std::chrono::high_resolution_clock::now();
|
for (int i = 0; i < 10; i++) {
|
||||||
|
memcpy(data + requestLength * i, request, requestLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < 1000; j++) {
|
||||||
|
for (int currentOffset = 0; currentOffset != length; ) {
|
||||||
|
|
||||||
|
int chunkSize = rand() % 10000;
|
||||||
|
if (currentOffset + chunkSize > length) {
|
||||||
|
chunkSize = length - currentOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// kpiera skiten
|
||||||
|
memcpy(paddedBuffer, data + currentOffset, chunkSize);
|
||||||
|
|
||||||
|
httpParser.consumePostPadded(/*data + currentOffset*/ paddedBuffer, chunkSize, nullptr, [&validRequests](void *user, HttpRequest *req) {
|
||||||
|
|
||||||
|
validRequests++;
|
||||||
|
std::cout << "validRequests: " << validRequests << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
}, [&dataBytes](void *, std::string_view data) {
|
||||||
|
//std::cout << "data bytes: " << data.length() << std::endl;
|
||||||
|
dataBytes += data.length();
|
||||||
|
}, [](void *) {
|
||||||
|
|
||||||
|
std::cout << "Error!" << std::endl;
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
|
||||||
|
currentOffset += chunkSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Data bytes: " << dataBytes << std::endl;
|
||||||
|
|
||||||
|
/*auto start = std::chrono::high_resolution_clock::now();
|
||||||
for (int i = 0; i < 10000000; i++) {
|
for (int i = 0; i < 10000000; i++) {
|
||||||
httpParser.consumePostPadded(data, sizeof(data) - 2, nullptr, [&validRequests](void *user, HttpRequest *req) {
|
httpParser.consumePostPadded(data, sizeof(data) - 2, nullptr, [&validRequests](void *user, HttpRequest *req) {
|
||||||
validRequests++;
|
validRequests++;
|
||||||
@@ -28,9 +80,9 @@ void testHttpParserPerformance() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
auto stop = std::chrono::high_resolution_clock::now();
|
auto stop = std::chrono::high_resolution_clock::now();*/
|
||||||
|
|
||||||
std::cout << "Parsed " << validRequests << " in " << std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count() << "ms" << std::endl;
|
//std::cout << "Parsed " << validRequests << " in " << std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count() << "ms" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TESTS_H
|
#endif // TESTS_H
|
||||||
|
|||||||
Reference in New Issue
Block a user