mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-06-10 16:47:14 +00:00
Add client fuzzing harness (#2437)
Cover client request processing logic. The goal is to enable this running on OSS-Fuzz. Signed-off-by: David Korczynski <david@adalogics.com>
This commit is contained in:
@@ -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
|
FUZZERS = server_fuzzer url_parser_fuzzer header_parser_fuzzer client_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)
|
||||||
@@ -25,6 +25,10 @@ server_fuzzer : server_fuzzer.cc ../../httplib.h
|
|||||||
$(CXX) $(CXXFLAGS) -o $@ $< $(ZLIB_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread -lanl
|
$(CXX) $(CXXFLAGS) -o $@ $< $(ZLIB_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread -lanl
|
||||||
zip -q -r server_fuzzer_seed_corpus.zip corpus
|
zip -q -r server_fuzzer_seed_corpus.zip corpus
|
||||||
|
|
||||||
|
client_fuzzer : client_fuzzer.cc ../../httplib.h
|
||||||
|
$(CXX) $(CXXFLAGS) -o $@ $< $(ZLIB_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread -lanl
|
||||||
|
zip -q -r client_fuzzer_seed_corpus.zip corpus
|
||||||
|
|
||||||
header_parser_fuzzer : header_parser_fuzzer.cc ../../httplib.h
|
header_parser_fuzzer : header_parser_fuzzer.cc ../../httplib.h
|
||||||
$(CXX) $(CXXFLAGS) -o $@ $< $(ZLIB_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread -lanl
|
$(CXX) $(CXXFLAGS) -o $@ $< $(ZLIB_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread -lanl
|
||||||
|
|
||||||
|
|||||||
88
test/fuzzing/client_fuzzer.cc
Normal file
88
test/fuzzing/client_fuzzer.cc
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <httplib.h>
|
||||||
|
|
||||||
|
class FuzzedStream : public httplib::Stream {
|
||||||
|
public:
|
||||||
|
FuzzedStream(const uint8_t *data, size_t size)
|
||||||
|
: data_(data), size_(size), read_pos_(0) {}
|
||||||
|
|
||||||
|
ssize_t read(char *ptr, size_t size) override {
|
||||||
|
if (size + read_pos_ > size_) { size = size_ - read_pos_; }
|
||||||
|
memcpy(ptr, data_ + read_pos_, size);
|
||||||
|
read_pos_ += size;
|
||||||
|
return static_cast<ssize_t>(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t write(const char *ptr, size_t size) override {
|
||||||
|
request_.append(ptr, size);
|
||||||
|
return static_cast<ssize_t>(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t write(const char *ptr) { return write(ptr, strlen(ptr)); }
|
||||||
|
|
||||||
|
ssize_t write(const std::string &s) { return write(s.data(), s.size()); }
|
||||||
|
|
||||||
|
bool is_readable() const override { return true; }
|
||||||
|
|
||||||
|
bool wait_readable() const override { return true; }
|
||||||
|
|
||||||
|
bool wait_writable() const override { return true; }
|
||||||
|
|
||||||
|
void get_remote_ip_and_port(std::string &ip, int &port) const override {
|
||||||
|
ip = "127.0.0.1";
|
||||||
|
port = 8080;
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_local_ip_and_port(std::string &ip, int &port) const override {
|
||||||
|
ip = "127.0.0.1";
|
||||||
|
port = 8080;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket_t socket() const override { return 0; }
|
||||||
|
|
||||||
|
time_t duration() const override { return 0; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
const uint8_t *data_;
|
||||||
|
size_t size_;
|
||||||
|
size_t read_pos_;
|
||||||
|
std::string request_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FuzzableClient : public httplib::ClientImpl {
|
||||||
|
public:
|
||||||
|
FuzzableClient() : httplib::ClientImpl("localhost", 8080) {}
|
||||||
|
|
||||||
|
void ProcessFuzzedResponse(FuzzedStream &stream, const std::string &method) {
|
||||||
|
httplib::Request req;
|
||||||
|
req.method = method;
|
||||||
|
req.path = "/";
|
||||||
|
httplib::Response res;
|
||||||
|
bool close_connection = false;
|
||||||
|
httplib::Error error = httplib::Error::Success;
|
||||||
|
|
||||||
|
process_request(stream, req, res, close_connection, error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
|
if (size < 1) return 0;
|
||||||
|
|
||||||
|
FuzzedStream stream{data + 1, size - 1};
|
||||||
|
FuzzableClient client;
|
||||||
|
|
||||||
|
// Use the first byte to select method
|
||||||
|
std::string method;
|
||||||
|
switch (data[0] % 6) {
|
||||||
|
case 0: method = "GET"; break;
|
||||||
|
case 1: method = "POST"; break;
|
||||||
|
case 2: method = "PUT"; break;
|
||||||
|
case 3: method = "PATCH"; break;
|
||||||
|
case 4: method = "DELETE"; break;
|
||||||
|
case 5: method = "OPTIONS"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.ProcessFuzzedResponse(stream, method);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user