/src/cpp-httplib/test/fuzzing/client_fuzzer.cc
Line | Count | Source |
1 | | #include <cstdint> |
2 | | #include <cstring> |
3 | | #include <httplib.h> |
4 | | |
5 | | class FuzzedStream : public httplib::Stream { |
6 | | public: |
7 | | FuzzedStream(const uint8_t *data, size_t size) |
8 | 1.96k | : data_(data), size_(size), read_pos_(0) {} |
9 | | |
10 | 2.12M | ssize_t read(char *ptr, size_t size) override { |
11 | 2.12M | if (size + read_pos_ > size_) { size = size_ - read_pos_; } |
12 | 2.12M | memcpy(ptr, data_ + read_pos_, size); |
13 | 2.12M | read_pos_ += size; |
14 | 2.12M | return static_cast<ssize_t>(size); |
15 | 2.12M | } |
16 | | |
17 | 1.96k | ssize_t write(const char *ptr, size_t size) override { |
18 | 1.96k | request_.append(ptr, size); |
19 | 1.96k | return static_cast<ssize_t>(size); |
20 | 1.96k | } |
21 | | |
22 | 0 | ssize_t write(const char *ptr) { return write(ptr, strlen(ptr)); } |
23 | | |
24 | 0 | ssize_t write(const std::string &s) { return write(s.data(), s.size()); } |
25 | | |
26 | 0 | bool is_readable() const override { return true; } |
27 | | |
28 | 0 | bool wait_readable() const override { return true; } |
29 | | |
30 | 0 | bool wait_writable() const override { return true; } |
31 | | |
32 | 0 | void get_remote_ip_and_port(std::string &ip, int &port) const override { |
33 | 0 | ip = "127.0.0.1"; |
34 | 0 | port = 8080; |
35 | 0 | } |
36 | | |
37 | 0 | void get_local_ip_and_port(std::string &ip, int &port) const override { |
38 | 0 | ip = "127.0.0.1"; |
39 | 0 | port = 8080; |
40 | 0 | } |
41 | | |
42 | 0 | socket_t socket() const override { return 0; } |
43 | | |
44 | 0 | time_t duration() const override { return 0; }; |
45 | | |
46 | | private: |
47 | | const uint8_t *data_; |
48 | | size_t size_; |
49 | | size_t read_pos_; |
50 | | std::string request_; |
51 | | }; |
52 | | |
53 | | class FuzzableClient : public httplib::ClientImpl { |
54 | | public: |
55 | 1.96k | FuzzableClient() : httplib::ClientImpl("localhost", 8080) {} |
56 | | |
57 | 1.96k | void ProcessFuzzedResponse(FuzzedStream &stream, const std::string &method) { |
58 | 1.96k | httplib::Request req; |
59 | 1.96k | req.method = method; |
60 | 1.96k | req.path = "/"; |
61 | 1.96k | httplib::Response res; |
62 | 1.96k | bool close_connection = false; |
63 | 1.96k | httplib::Error error = httplib::Error::Success; |
64 | | |
65 | 1.96k | process_request(stream, req, res, close_connection, error); |
66 | 1.96k | } |
67 | | }; |
68 | | |
69 | 3.50k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
70 | 3.50k | if (size < 1) return 0; |
71 | | |
72 | 3.50k | FuzzedStream stream{data + 1, size - 1}; |
73 | 3.50k | FuzzableClient client; |
74 | | |
75 | | // Use the first byte to select method |
76 | 3.50k | std::string method; |
77 | 3.50k | switch (data[0] % 6) { |
78 | 725 | case 0: method = "GET"; break; |
79 | 618 | case 1: method = "POST"; break; |
80 | 815 | case 2: method = "PUT"; break; |
81 | 279 | case 3: method = "PATCH"; break; |
82 | 523 | case 4: method = "DELETE"; break; |
83 | 541 | case 5: method = "OPTIONS"; break; |
84 | 3.50k | } |
85 | | |
86 | 3.50k | client.ProcessFuzzedResponse(stream, method); |
87 | 3.50k | return 0; |
88 | 3.50k | } |