server_fuzzer.cc 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. #include <cstdint>
  2. #include <httplib.h>
  3. class FuzzedStream : public httplib::Stream {
  4. public:
  5. FuzzedStream(const uint8_t *data, size_t size)
  6. : data_(data), size_(size), read_pos_(0) {}
  7. ssize_t read(char *ptr, size_t size) override {
  8. if (size + read_pos_ > size_) { size = size_ - read_pos_; }
  9. memcpy(ptr, data_ + read_pos_, size);
  10. read_pos_ += size;
  11. // Like SocketStream, pull in more than was asked for, which the line
  12. // reader then takes through buffered_data(), so both of its paths run.
  13. buffered_end_ =
  14. (std::max)(buffered_end_, (std::min)(size_, read_pos_ + 4096));
  15. return static_cast<ssize_t>(size);
  16. }
  17. const char *buffered_data(size_t &size) const override {
  18. size = buffered_end_ > read_pos_ ? buffered_end_ - read_pos_ : 0;
  19. return size ? reinterpret_cast<const char *>(data_ + read_pos_) : nullptr;
  20. }
  21. void consume_buffered(size_t size) override { read_pos_ += size; }
  22. ssize_t write(const char *ptr, size_t size) override {
  23. response_.append(ptr, size);
  24. return static_cast<int>(size);
  25. }
  26. ssize_t write(const char *ptr) { return write(ptr, strlen(ptr)); }
  27. ssize_t write(const std::string &s) { return write(s.data(), s.size()); }
  28. bool is_readable() const override { return true; }
  29. bool wait_readable() const override { return true; }
  30. bool wait_writable() const override { return true; }
  31. void get_remote_ip_and_port(std::string &ip, int &port) const override {
  32. ip = "127.0.0.1";
  33. port = 8080;
  34. }
  35. void get_local_ip_and_port(std::string &ip, int &port) const override {
  36. ip = "127.0.0.1";
  37. port = 8080;
  38. }
  39. socket_t socket() const override { return 0; }
  40. time_t duration() const override { return 0; };
  41. private:
  42. const uint8_t *data_;
  43. size_t size_;
  44. size_t read_pos_;
  45. size_t buffered_end_ = 0;
  46. std::string response_;
  47. };
  48. class FuzzableServer : public httplib::Server {
  49. public:
  50. void ProcessFuzzedRequest(FuzzedStream &stream) {
  51. bool connection_close = false;
  52. process_request(stream,
  53. /*remote_addr=*/"",
  54. /*remote_port =*/0,
  55. /*local_addr=*/"",
  56. /*local_port =*/0,
  57. /*last_connection=*/false, connection_close, nullptr);
  58. }
  59. };
  60. static FuzzableServer g_server;
  61. extern "C" int LLVMFuzzerInitialize(int * /*argc*/, char *** /*argv*/) {
  62. g_server.Get(R"(.*)",
  63. [&](const httplib::Request & /*req*/, httplib::Response &res) {
  64. res.set_content("response content", "text/plain");
  65. });
  66. g_server.Post(R"(.*)",
  67. [&](const httplib::Request & /*req*/, httplib::Response &res) {
  68. res.set_content("response content", "text/plain");
  69. });
  70. g_server.Put(R"(.*)",
  71. [&](const httplib::Request & /*req*/, httplib::Response &res) {
  72. res.set_content("response content", "text/plain");
  73. });
  74. g_server.Patch(R"(.*)",
  75. [&](const httplib::Request & /*req*/, httplib::Response &res) {
  76. res.set_content("response content", "text/plain");
  77. });
  78. g_server.Delete(
  79. R"(.*)", [&](const httplib::Request & /*req*/, httplib::Response &res) {
  80. res.set_content("response content", "text/plain");
  81. });
  82. g_server.Options(
  83. R"(.*)", [&](const httplib::Request & /*req*/, httplib::Response &res) {
  84. res.set_content("response content", "text/plain");
  85. });
  86. return 0;
  87. }
  88. extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  89. FuzzedStream stream{data, size};
  90. g_server.ProcessFuzzedRequest(stream);
  91. return 0;
  92. }