Bläddra i källkod

Add two new fuzzers (#2412)

The goal is to increase code coverage by way of OSS-Fuzz. A recent code
coverage report is available at
https://storage.googleapis.com/oss-fuzz-coverage/cpp-httplib/reports/20260326/linux/report.html

Signed-off-by: David Korczynski <david@adalogics.com>
DavidKorczynski 3 dagar sedan
förälder
incheckning
831b64bdeb
3 ändrade filer med 120 tillägg och 1 borttagningar
  1. 9 1
      test/fuzzing/Makefile
  2. 59 0
      test/fuzzing/header_parser_fuzzer.cc
  3. 52 0
      test/fuzzing/url_parser_fuzzer.cc

+ 9 - 1
test/fuzzing/Makefile

@@ -13,8 +13,10 @@ ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
 BROTLI_DIR = /usr/local/opt/brotli
 # 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
+
 # Runs all the tests and also fuzz tests against seed corpus.
-all : server_fuzzer
+all : $(FUZZERS)
 	./server_fuzzer corpus/*
 
 # Fuzz target, so that you can choose which $(LIB_FUZZING_ENGINE) to use.
@@ -23,5 +25,11 @@ server_fuzzer : server_fuzzer.cc ../../httplib.h
 	$(CXX) $(CXXFLAGS) -o $@  $<  $(ZLIB_SUPPORT)  $(LIB_FUZZING_ENGINE) -pthread -lanl
 	zip -q -r server_fuzzer_seed_corpus.zip corpus
 
+header_parser_fuzzer : header_parser_fuzzer.cc ../../httplib.h
+	$(CXX) $(CXXFLAGS) -o $@  $<  $(ZLIB_SUPPORT)  $(LIB_FUZZING_ENGINE) -pthread -lanl
+
+url_parser_fuzzer : url_parser_fuzzer.cc ../../httplib.h
+	$(CXX) $(CXXFLAGS) -o $@  $<  $(ZLIB_SUPPORT)  $(LIB_FUZZING_ENGINE) -pthread -lanl
+
 clean:
 	rm -f server_fuzzer pem *.0 *.o *.1 *.srl *.zip

+ 59 - 0
test/fuzzing/header_parser_fuzzer.cc

@@ -0,0 +1,59 @@
+#include <cstdint>
+#include <cstring>
+#include <string>
+
+#include <httplib.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+  if (size < 2) return 0;
+
+  uint8_t selector = data[0];
+  const char *payload = reinterpret_cast<const char *>(data + 1);
+  size_t payload_size = size - 1;
+  std::string input(payload, payload_size);
+
+  switch (selector % 7) {
+  case 0: {
+    // parse_range_header
+    httplib::Ranges ranges;
+    httplib::detail::parse_range_header(input, ranges);
+    break;
+  }
+  case 1: {
+    // parse_accept_header
+    std::vector<std::string> content_types;
+    httplib::detail::parse_accept_header(input, content_types);
+    break;
+  }
+  case 2: {
+    // extract_media_type with params
+    std::map<std::string, std::string> params;
+    httplib::detail::extract_media_type(input, &params);
+    break;
+  }
+  case 3: {
+    // parse_multipart_boundary
+    std::string boundary;
+    httplib::detail::parse_multipart_boundary(input, boundary);
+    break;
+  }
+  case 4: {
+    // parse_disposition_params
+    httplib::Params params;
+    httplib::detail::parse_disposition_params(input, params);
+    break;
+  }
+  case 5: {
+    // parse_http_date
+    httplib::detail::parse_http_date(input);
+    break;
+  }
+  case 6: {
+    // can_compress_content_type
+    httplib::detail::can_compress_content_type(input);
+    break;
+  }
+  }
+
+  return 0;
+}

+ 52 - 0
test/fuzzing/url_parser_fuzzer.cc

@@ -0,0 +1,52 @@
+#include <cstdint>
+#include <cstring>
+#include <string>
+
+#include <httplib.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+  if (size < 2) return 0;
+
+  // Use first byte to select which parsing function to exercise
+  uint8_t selector = data[0];
+  const char *payload = reinterpret_cast<const char *>(data + 1);
+  size_t payload_size = size - 1;
+  std::string input(payload, payload_size);
+
+  switch (selector % 6) {
+  case 0: {
+    // parse_query_text
+    httplib::Params params;
+    httplib::detail::parse_query_text(payload, payload_size, params);
+    break;
+  }
+  case 1: {
+    // decode_query_component
+    httplib::decode_query_component(input, true);
+    httplib::decode_query_component(input, false);
+    break;
+  }
+  case 2: {
+    // decode_path_component
+    httplib::decode_path_component(input);
+    break;
+  }
+  case 3: {
+    // encode_query_component
+    httplib::encode_query_component(input);
+    break;
+  }
+  case 4: {
+    // normalize_query_string
+    httplib::detail::normalize_query_string(input);
+    break;
+  }
+  case 5: {
+    // is_valid_path
+    httplib::detail::is_valid_path(input);
+    break;
+  }
+  }
+
+  return 0;
+}