fuzz: switch http_libevent::HTTPRequest to http_bitcoin::HTTPRequest
What changed, and why it matters
This commit updates a fuzz test—a special automated test that feeds random data to a piece of code to find bugs. The test previously used Bitcoin Core's old libevent-based HTTP request parser and worked around a known crash in that parser. The commit switches the test to use Bitcoin Core's newer internal HTTP request parser. This is a test-only cleanup and does not change the code that real Bitcoin nodes run to handle network traffic.
No immediate action required. Treat as routine test maintenance. If reviewing the newer http_bitcoin parser, ensure it has its own fuzz coverage and that header/body size limits are correctly enforced.
Security signals we found
Removes a fuzz-test-only workaround for a libevent nullptr dereference in evhttp_parse_request_line
Switches fuzzing target to the newer http_bitcoin HTTP parser implementation
No changes to production networking, consensus, or wallet code
Evidence from the diff
The fuzz target src/test/fuzz/http_request.cpp is refactored from http_libevent::HTTPRequest to http_bitcoin::HTTPRequest. It removes direct libevent evhttp_parse_firstline_/evhttp_parse_headers_ calls, the associated PROXY-request nullptr-dereference workaround, and the manual evhttp_request/evbuffer lifecycle. The new harness feeds fuzzed bytes into http_bitcoin::HTTPRequest::LoadControlData/LoadHeaders/LoadBody via a LineReader. No production HTTP server or RPC code is modified.
Changed components
src/test/fuzz/http_request.cppInspect captured patch +14 / −34
diff --git a/src/test/fuzz/http_request.cpp b/src/test/fuzz/http_request.cpp
index 916fcb64..c992edcd 100644
--- a/src/test/fuzz/http_request.cpp
+++ b/src/test/fuzz/http_request.cpp
@@ -10,61 +10,41 @@
#include <util/signalinterrupt.h>
#include <util/strencodings.h>
-#include <event2/buffer.h>
-#include <event2/event.h>
-#include <event2/http.h>
-#include <event2/http_struct.h>
-
#include <cassert>
#include <cstdint>
#include <string>
#include <vector>
-extern "C" int evhttp_parse_firstline_(struct evhttp_request*, struct evbuffer*);
-extern "C" int evhttp_parse_headers_(struct evhttp_request*, struct evbuffer*);
std::string_view RequestMethodString(HTTPRequestMethod m);
FUZZ_TARGET(http_request)
{
- using http_libevent::HTTPRequest;
+ using http_bitcoin::HTTPRequest;
+ using http_bitcoin::MAX_HEADERS_SIZE;
+ using util::LineReader;
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
- evhttp_request* evreq = evhttp_request_new(nullptr, nullptr);
- assert(evreq != nullptr);
- evreq->kind = EVHTTP_REQUEST;
- evbuffer* evbuf = evbuffer_new();
- assert(evbuf != nullptr);
- const std::vector<uint8_t> http_buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, 4096);
- evbuffer_add(evbuf, http_buffer.data(), http_buffer.size());
- // Avoid constructing requests that will be interpreted by libevent as PROXY requests to avoid triggering
- // a nullptr dereference. The dereference (req->evcon->http_server) takes place in evhttp_parse_request_line
- // and is a consequence of our hacky but necessary use of the internal function evhttp_parse_firstline_ in
- // this fuzzing harness. The workaround is not aesthetically pleasing, but it successfully avoids the troublesome
- // code path. " http:// HTTP/1.1\n" was a crashing input prior to this workaround.
- const std::string http_buffer_str = ToLower(std::string{http_buffer.begin(), http_buffer.end()});
- if (http_buffer_str.find(" http://") != std::string::npos || http_buffer_str.find(" https://") != std::string::npos ||
- evhttp_parse_firstline_(evreq, evbuf) != 1 || evhttp_parse_headers_(evreq, evbuf) != 1) {
- evbuffer_free(evbuf);
- evhttp_request_free(evreq);
+ const std::vector<std::byte> http_buffer{ConsumeRandomLengthByteVector<std::byte>(fuzzed_data_provider, 4096)};
+
+ HTTPRequest http_request;
+ LineReader reader(http_buffer, MAX_HEADERS_SIZE);
+ try {
+ if (!http_request.LoadControlData(reader)) return;
+ if (!http_request.LoadHeaders(reader)) return;
+ if (!http_request.LoadBody(reader)) return;
+ } catch (const std::runtime_error&) {
return;
}
- util::SignalInterrupt interrupt;
- HTTPRequest http_request{evreq, interrupt, true};
const HTTPRequestMethod request_method = http_request.GetRequestMethod();
(void)RequestMethodString(request_method);
(void)http_request.GetURI();
(void)http_request.GetHeader("Host");
- const std::string header = fuzzed_data_provider.ConsumeRandomLengthString(16);
+ std::string header = fuzzed_data_provider.ConsumeRandomLengthString(16);
(void)http_request.GetHeader(header);
- (void)http_request.WriteHeader(header, fuzzed_data_provider.ConsumeRandomLengthString(16));
+ (void)http_request.WriteHeader(std::string(header), fuzzed_data_provider.ConsumeRandomLengthString(16));
(void)http_request.GetHeader(header);
const std::string body = http_request.ReadBody();
assert(body.empty());
- const CService service = http_request.GetPeer();
- assert(service.ToStringAddrPort() == "[::]:0");
-
- evbuffer_free(evbuf);
- evhttp_request_free(evreq);
}
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.