http: Implement HTTPRequest class

HTTP Request message:
https://datatracker.ietf.org/doc/html/rfc1945#section-5

Request Line aka Control Line aka first line:
https://datatracker.ietf.org/doc/html/rfc1945#section-5.1

See message_read_status() in libevent http.c for how
`MORE_DATA_EXPECTED` is handled there
This commit is contained in:
Matthew Zipkin
2024-10-16 14:18:45 -04:00
parent ad50aa4a0f
commit 9463e98781
3 changed files with 317 additions and 0 deletions

View File

@@ -8,9 +8,11 @@
#include <functional>
#include <optional>
#include <span>
#include <stdexcept>
#include <string>
#include <rpc/protocol.h>
#include <util/byte_units.h>
#include <util/strencodings.h>
#include <util/string.h>
@@ -192,6 +194,10 @@ private:
};
namespace http_bitcoin {
using util::LineReader;
//! Shortest valid request line, used by libevent in evhttp_parse_request_line()
constexpr size_t MIN_REQUEST_LINE_LENGTH = std::string_view("GET / HTTP/1.0").size();
//! Maximum size of each headers line in an HTTP request,
//! also the maximum size of all headers total.
@@ -199,6 +205,15 @@ namespace http_bitcoin {
//! And libevent http.c evhttp_parse_headers_()
constexpr size_t MAX_HEADERS_SIZE{8192};
//! Maximum size of an HTTP request body
constexpr uint64_t MAX_BODY_SIZE{32_MiB};
//! Thrown when a request body exceeds MAX_BODY_SIZE
//! so the server can reply with more specific code 413 (content too large) vs general 400 (bad request)
struct ContentTooLargeError : std::runtime_error {
using std::runtime_error::runtime_error;
};
class HTTPHeaders
{
public:
@@ -258,6 +273,30 @@ public:
std::string StringifyHeaders() const;
};
class HTTPRequest
{
public:
std::string m_method;
std::string m_target;
HTTPVersion m_version;
HTTPHeaders m_headers;
std::string m_body;
/**
* Methods that attempt to parse HTTP request fields line-by-line
* from a receive buffer.
* @param[in] reader A LineReader object constructed over a span of data.
* @returns true If the request field was parsed.
* false If there was not enough data in the buffer to complete the field.
* @throws std::runtime_error if data is invalid.
*/
/// @{
bool LoadControlData(LineReader& reader);
bool LoadHeaders(LineReader& reader);
bool LoadBody(LineReader& reader);
/// @}
};
} // namespace http_bitcoin
#endif // BITCOIN_HTTPSERVER_H