diff --git a/src/httpserver.h b/src/httpserver.h --- a/src/httpserver.h +++ b/src/httpserver.h @@ -77,7 +77,7 @@ bool replySent; public: - explicit HTTPRequest(struct evhttp_request *req); + explicit HTTPRequest(struct evhttp_request *req, bool replySent = false); ~HTTPRequest(); enum RequestMethod { UNKNOWN, GET, POST, HEAD, PUT, OPTIONS }; diff --git a/src/httpserver.cpp b/src/httpserver.cpp --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -200,7 +200,7 @@ } /** HTTP request method as string - use for logging only */ -static std::string RequestMethodString(HTTPRequest::RequestMethod m) { +std::string RequestMethodString(HTTPRequest::RequestMethod m) { switch (m) { case HTTPRequest::GET: return "GET"; @@ -549,8 +549,8 @@ evtimer_add(ev, tv); } } -HTTPRequest::HTTPRequest(struct evhttp_request *_req) - : req(_req), replySent(false) {} +HTTPRequest::HTTPRequest(struct evhttp_request *_req, bool _replySent) + : req(_req), replySent(_replySent) {} HTTPRequest::~HTTPRequest() { if (!replySent) { // Keep track of whether reply was sent to avoid request leaks diff --git a/src/test/fuzz/CMakeLists.txt b/src/test/fuzz/CMakeLists.txt --- a/src/test/fuzz/CMakeLists.txt +++ b/src/test/fuzz/CMakeLists.txt @@ -94,6 +94,7 @@ flatfile float hex + http_request integer key key_io diff --git a/src/test/fuzz/http_request.cpp b/src/test/fuzz/http_request.cpp new file mode 100644 --- /dev/null +++ b/src/test/fuzz/http_request.cpp @@ -0,0 +1,63 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +extern "C" int evhttp_parse_firstline_(struct evhttp_request *, + struct evbuffer *); +extern "C" int evhttp_parse_headers_(struct evhttp_request *, + struct evbuffer *); +std::string RequestMethodString(HTTPRequest::RequestMethod m); + +void test_one_input(const std::vector &buffer) { + 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 http_buffer = + ConsumeRandomLengthByteVector(fuzzed_data_provider, 4096); + evbuffer_add(evbuf, http_buffer.data(), http_buffer.size()); + if (evhttp_parse_firstline_(evreq, evbuf) != 1 || + evhttp_parse_headers_(evreq, evbuf) != 1) { + evbuffer_free(evbuf); + evhttp_request_free(evreq); + return; + } + + HTTPRequest http_request{evreq, true}; + const HTTPRequest::RequestMethod 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); + (void)http_request.GetHeader(header); + (void)http_request.WriteHeader( + 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.ToString() == "[::]:0"); + + evbuffer_free(evbuf); + evhttp_request_free(evreq); +}