Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2015-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#ifndef BITCOIN_HTTPSERVER_H6#define BITCOIN_HTTPSERVER_H8#include <atomic>9#include <functional>10#include <memory>11#include <optional>12#include <span>13#include <stdexcept>14#include <string>15#include <vector>17#include <netaddress.h>18#include <rpc/protocol.h>19#include <util/byte_units.h>20#include <util/expected.h>21#include <util/sock.h>22#include <util/strencodings.h>23#include <util/string.h>24#include <util/threadinterrupt.h>25#include <util/time.h>27namespace util {28class SignalInterrupt;29} // namespace util31/**32* The default value for `-rpcthreads`. This number of threads will be created at startup.33*/34inline constexpr int DEFAULT_HTTP_THREADS=16;36/**37* The default value for `-rpcworkqueue`. This is the maximum depth of the work queue,38* we don't allocate this number of work queue items upfront.39*/40inline constexpr int DEFAULT_HTTP_WORKQUEUE=64;42inline constexpr int DEFAULT_HTTP_SERVER_TIMEOUT=30;44/**45* Maximum number of connected HTTP clients46*/47inline constexpr int DEFAULT_MAX_HTTP_CONNECTIONS = 16;49enum class HTTPRequestMethod {50UNKNOWN,51GET,52POST,53HEAD,54PUT55};57class HTTPRequest;59/** Handler for requests to a certain HTTP path */60using HTTPRequestHandler = std::function<void(HTTPRequest* req, const std::string&)>;62/** Register handler for prefix.63* If multiple handlers match a prefix, the first-registered one will64* be invoked.65*/66void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler);67/** Unregister handler for prefix */68void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch);70namespace bitcoin_http {71//! Shortest valid request line, used by libevent in evhttp_parse_request_line()72inline constexpr size_t MIN_REQUEST_LINE_LENGTH = std::string_view("GET / HTTP/1.0").size();74//! Maximum size of each headers line in an HTTP request,75//! also the maximum size of all headers total.76//! See https://github.com/bitcoin/bitcoin/pull/685977//! And libevent http.c evhttp_parse_headers_()78inline constexpr size_t MAX_HEADERS_SIZE{8192};80//! Maximum size of an HTTP request body received from a client.81//! Also used to limit data queued for sending back to client.82inline constexpr uint64_t MAX_BODY_SIZE{32_MiB};84//! Thrown when a request body exceeds MAX_BODY_SIZE (or *will* exceed, in chunked transfer)85//! so the server can reply with more specific code 413 (content too large) vs general 400 (bad request)86struct ContentTooLargeError : std::runtime_error {87using std::runtime_error::runtime_error;88};89} // namespace bitcoin_http91class HTTPHeaders92{93public:94/**95* @param[in] key The field-name of the header to search for96* @returns The value of the first header that matches the provided key97* nullopt if key is not found98*/99std::optional<std::string> FindFirst(std::string_view key) const;100/**101* @param[in] key The field-name of the header to search for102* @returns Views into all values matching the provided key (valid while this object is alive)103*/104std::vector<std::string_view> FindAll(std::string_view key) const;105void Write(std::string&& key, std::string&& value);106/**107* @param[in] key The field-name of the header to search for and delete108*/109void RemoveAll(std::string_view key);110/**111* @param[in] reader A LineReader instance initialized with the client's receive buffer.112* @param[in] write Whether or not to write the parsed data to the object after validation.113* @returns false if LineReader hits the end of the buffer before reading an114* \n, meaning that we are still waiting on more data from the client.115* true after reading an entire HTTP headers section, terminated116* by an empty line and \n.117* @throws on exceeded read limit and on bad headers syntax (e.g. no ":" in a line)118*/119bool Read(util::LineReader& reader, bool write = true);120std::string Stringify() const;122private:123/**124* Headers can have duplicate field names, so we use a vector of key-value pairs instead of a map.125* https://httpwg.org/specs/rfc9110.html#rfc.section.5.2126*/127std::vector<std::pair<std::string, std::string>> m_headers;129//! Track total bytes consumed in Read() for limit checks130size_t m_consumed{0};131};133struct HTTPVersion {134/**135* Default HTTP protocol version 1.1 is used by error responses136* when a request is unreadable.137*/138/// @{139uint8_t major{1};140uint8_t minor{1};141/// @}142};144struct HTTPResponse {145HTTPVersion version;146HTTPStatusCode status{HTTP_INTERNAL_SERVER_ERROR};147HTTPHeaders headers;149std::string StringifyHeaders() const;150};152class HTTPRemoteClient;154class HTTPRequest155{156public:157explicit HTTPRequest(const std::shared_ptr<HTTPRemoteClient>& client) : m_client{client} {}158//! Construct with a null client for unit tests159explicit HTTPRequest() : m_client{} {}161/**162* Methods that attempt to parse HTTP request fields line-by-line163* from a receive buffer.164* @param[in] reader A LineReader object constructed over a span of data.165* @returns true If the request field was parsed.166* false If there was not enough data in the buffer to complete the field.167* @throws std::runtime_error if data is invalid.168*/169/// @{170bool LoadControlData(util::LineReader& reader);171bool LoadHeaders(util::LineReader& reader);172bool LoadBody(util::LineReader& reader);173/// @}175void WriteReply(HTTPStatusCode status, std::span<const std::byte> reply_body = {});176void WriteReply(HTTPStatusCode status, std::string_view reply_body_view)177{178WriteReply(status, std::as_bytes(std::span{reply_body_view}));179}181const HTTPVersion& GetVersion() const { return m_version; }182std::shared_ptr<HTTPRemoteClient> GetClient() const { return m_client.lock(); }184// These methods reimplement the API from http_libevent::HTTPRequest185// for downstream JSONRPC and REST modules.186std::string GetURI() const { return m_target; }187CService GetPeer() const;188HTTPRequestMethod GetRequestMethod() const { return m_method; }189std::optional<std::string> GetQueryParameter(std::string_view key) const;190std::optional<std::string> GetHeader(std::string_view hdr) const;191std::string ReadBody() const { return m_body; }192void WriteHeader(std::string&& hdr, std::string&& value);193std::optional<uint64_t> GetChunkSize() const { return m_chunk_size; }194uint64_t GetChunkProgress() const { return m_chunk_read; }196enum class State {197Init,198NeedsHeaders,199NeedsBody,200Complete,201Error202};203State GetState() const { return m_state; }204void SetState(State state) { m_state = state; }206private:207HTTPRequestMethod m_method;208std::string m_target;209HTTPVersion m_version;210HTTPHeaders m_headers;211std::string m_body;213//! Pointer to the client that made the request so we know who to respond to.214std::weak_ptr<HTTPRemoteClient> m_client;216//! Response headers may be set in advance before response body is known217HTTPHeaders m_response_headers;219// If a large request is sent with "Transfer-encoding: chunked" we may220// read the chunk size in a separate I/O loop iteration than the chunk221// of data itself. Store the chunk size value here until the chunk is read.222std::optional<uint64_t> m_chunk_size;223// We may also read a large chunk over multiple loop iterations.224// Track the progress of the chunk here.225uint64_t m_chunk_read{0};227State m_state = State::Init;228};230class HTTPServer231{232public:233/**234* Each connection is assigned an unique id of this type.235*/236using Id = uint64_t;238explicit HTTPServer(std::function<void(std::unique_ptr<HTTPRequest>&&)> func)239: m_request_dispatcher{std::move(func)} {}241virtual ~HTTPServer()242{243Assume(!m_thread_socket_handler.joinable()); // Missing call to JoinSocketsThreads()244Assume(m_connected.empty()); // Missing call to DisconnectClients(), or disconnect flags not set245Assume(m_listen.empty()); // Missing call to StopListening()246}248/**249* Parse the user's -rpcallowip settings and populate m_allow_subnets250*/
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.