Coverage Report

Created: 2026-09-23 07:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wt/fuzz/fuzz-cgi.C
Line
Count
Source
1
/*
2
 * Copyright (C) 2026 Emweb bv, Herent, Belgium.
3
 *
4
 * See the LICENSE file for terms of use.
5
 */
6
7
#include <stdint.h>
8
#include <stddef.h>
9
#include <sstream>
10
#include <string>
11
#include <vector>
12
13
#include "Wt/WSslInfo.h"
14
#include "web/CgiParser.h"
15
#include "web/WebRequest.h"
16
17
2.45k
#define kMaxInputLength 65536
18
19
// Minimal WebRequest used to drive CgiParser without a server/socket; modelled
20
// on the MockRequest in test/private/EventDecodeTest.C. The fuzz bytes are the
21
// request body fed through in().
22
class FuzzRequest : public Wt::WebRequest {
23
public:
24
0
  bool supportsTransferWebSocketResourceSocket() override { return false; }
25
0
  void flush(WT_MAYBE_UNUSED ResponseState state, WT_MAYBE_UNUSED const WriteCallback& callback) override { }
26
5.47k
  std::istream &in() override { return in_; }
27
0
  std::ostream &out() override { return out_; }
28
0
  std::ostream &err() override { return err_; }
29
0
  void setRedirect(WT_MAYBE_UNUSED const std::string& url) override { }
30
0
  void setStatus(WT_MAYBE_UNUSED int status) override { }
31
0
  int status() override { return 0; }
32
0
  void setContentType(const std::string &value) override { contentType_ = value; }
33
2.44k
  const char *contentType() const override { return contentType_.c_str(); }
34
0
  void setContentLength(int64_t length) override { contentLength_ = length; }
35
2.44k
  int64_t contentLength() const override { return contentLength_; }
36
0
  void addHeader(WT_MAYBE_UNUSED const std::string& name, WT_MAYBE_UNUSED const std::string& value) override { }
37
0
  void insertHeader(WT_MAYBE_UNUSED const std::string &name, WT_MAYBE_UNUSED const std::string &value) override { }
38
0
  const char *envValue(WT_MAYBE_UNUSED const char *name) const override { return nullptr; }
39
0
  const std::string &serverName() const override { return s_; }
40
0
  const std::string &serverPort() const override { return s_; }
41
0
  const std::string &scriptName() const override { return s_; }
42
2.44k
  const char *requestMethod() const override { return requestMethod_.c_str(); }
43
2.44k
  const std::string &queryString() const override { return s_; }
44
0
  const std::string &pathInfo() const override { return s_; }
45
0
  const std::string &remoteAddr() const override { return s_; }
46
0
  const char *urlScheme() const override { return s_.c_str(); }
47
0
  const char *headerValue(WT_MAYBE_UNUSED const char* name) const override { return nullptr; }
48
0
  std::vector<Wt::Http::Message::Header> headers() const override { return {}; }
49
0
  std::unique_ptr<Wt::WSslInfo> sslInfo(const Wt::Configuration &) const override { return nullptr; }
50
51
  std::string contentType_;
52
  int64_t contentLength_ = 0;
53
  std::stringstream in_;
54
  std::stringstream out_;
55
  std::stringstream err_;
56
  std::string requestMethod_ = "POST";
57
  std::string s_;
58
};
59
60
// Fuzzes CgiParser (src/web/CgiParser.C): the multipart/form-data and
61
// x-www-form-urlencoded request-body parser.
62
2.45k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
63
2.45k
  if (Size < 1 || Size > kMaxInputLength) {
64
10
    return 0;
65
10
  }
66
67
2.44k
  const uint8_t selector = Data[0];
68
2.44k
  const char *body = reinterpret_cast<const char *>(Data + 1);
69
2.44k
  const size_t bodyLen = Size - 1;
70
71
2.44k
  FuzzRequest request;
72
2.44k
  request.in_.write(body, bodyLen);
73
2.44k
  request.contentLength_ = static_cast<int64_t>(bodyLen);
74
75
2.44k
  if ((selector & 1) == 0) {
76
1.23k
    request.contentType_ = "multipart/form-data; boundary=AaB03x";
77
1.23k
  } else {
78
1.21k
    request.contentType_ = "application/x-www-form-urlencoded";
79
1.21k
  }
80
81
2.44k
  try {
82
2.44k
    Wt::CgiParser parser(/*maxRequestSize=*/1 << 20, /*maxFormData=*/1 << 20);
83
2.44k
    parser.parse(request, Wt::CgiParser::ReadDefault);
84
2.44k
  } catch (...) {
85
1.22k
  }
86
87
2.44k
  return 0;
88
2.44k
}