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_DIR = /usr/local/opt/brotli
|
||||||
# BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec
|
# 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.
|
# Runs all the tests and also fuzz tests against seed corpus.
|
||||||
all : $(FUZZERS)
|
all : $(FUZZERS)
|
||||||
@@ -41,5 +41,8 @@ multipart_parser_fuzzer : multipart_parser_fuzzer.cc ../../httplib.h
|
|||||||
websocket_fuzzer : websocket_fuzzer.cc ../../httplib.h
|
websocket_fuzzer : websocket_fuzzer.cc ../../httplib.h
|
||||||
$(CXX) $(CXXFLAGS) -o $@ $< $(ZLIB_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread -lanl
|
$(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:
|
clean:
|
||||||
rm -f server_fuzzer pem *.0 *.o *.1 *.srl *.zip
|
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