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:
DavidKorczynski
2026-04-29 03:05:29 +01:00
committed by GitHub
parent 13e866bdb0
commit 0cbeafe6a4
2 changed files with 93 additions and 1 deletions

View 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;
}