mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-11-13 17:00:40 +00:00
Add sse_parser_fuzzer for detail::SSEParser (#2665)
Feed the event stream to the parser in chunks and abort if the reported events, ids and retries differ from parsing it in one piece. Also run with a length limit to cover the early-stop path.
This commit is contained in:
1 parent
8c5fd6aa08
commit
53a7f4964e
2 files changed
+53
-1
No files matched your search
@@ -13,7 +13,7 @@ ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
|
||||
BROTLI_DIR = /usr/local/opt/brotli
|
||||
# BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec
|
||||
|
||||
FUZZERS = server_fuzzer url_parser_fuzzer header_parser_fuzzer client_fuzzer multipart_parser_fuzzer websocket_fuzzer
|
||||
FUZZERS = server_fuzzer url_parser_fuzzer header_parser_fuzzer client_fuzzer multipart_parser_fuzzer websocket_fuzzer sse_parser_fuzzer
|
||||
|
||||
# Runs all the tests and also fuzz tests against seed corpus.
|
||||
all : $(FUZZERS)
|
||||
@@ -41,5 +41,8 @@ multipart_parser_fuzzer : multipart_parser_fuzzer.cc ../../httplib.h
|
||||
websocket_fuzzer : websocket_fuzzer.cc ../../httplib.h
|
||||
$(CXX) $(CXXFLAGS) -o $@ $< $(ZLIB_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread -lanl
|
||||
|
||||
sse_parser_fuzzer : sse_parser_fuzzer.cc ../../httplib.h
|
||||
$(CXX) $(CXXFLAGS) -o $@ $< $(ZLIB_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread -lanl
|
||||
|
||||
clean:
|
||||
rm -f server_fuzzer pem *.0 *.o *.1 *.srl *.zip
|
||||
@@ -0,0 +1,49 @@
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
#include <httplib.h>
|
||||
|
||||
namespace {
|
||||
|
||||
// Feeds the stream in chunks and records every handler call in order
|
||||
std::string parse_in_chunks(const std::string &stream, size_t chunk,
|
||||
size_t max_event_length) {
|
||||
std::string trace;
|
||||
httplib::detail::SSEParser parser(
|
||||
[&](const httplib::sse::SSEMessage &msg) {
|
||||
trace += "event[" + msg.event + "|" + msg.data + "|" + msg.id + "]";
|
||||
},
|
||||
[&](const std::string &id) { trace += "id[" + id + "]"; },
|
||||
[&](int retry_ms) { trace += "retry[" + std::to_string(retry_ms) + "]"; },
|
||||
max_event_length);
|
||||
|
||||
for (size_t off = 0; off < stream.size(); off += chunk) {
|
||||
if (!parser.parse(stream.data() + off,
|
||||
std::min(chunk, stream.size() - off))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return trace;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
if (size < 2 || size > 65536) { return 0; }
|
||||
|
||||
// First byte selects the chunk size, the rest is the event stream
|
||||
auto chunk = static_cast<size_t>(data[0]) + 1;
|
||||
std::string stream(reinterpret_cast<const char *>(data + 1), size - 1);
|
||||
|
||||
// Without a length limit, chunking must not change what is reported
|
||||
auto whole = parse_in_chunks(stream, stream.size(), 0);
|
||||
auto chunked = parse_in_chunks(stream, chunk, 0);
|
||||
if (whole != chunked) { std::abort(); }
|
||||
|
||||
// With a limit, only check that the parser stops cleanly
|
||||
parse_in_chunks(stream, chunk, 64);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user