5#ifndef BITCOIN_HTTPSERVER_H
6#define BITCOIN_HTTPSERVER_H
25#include <util/threadinterrupt.h>
85 using std::runtime_error::runtime_error;
96 std::optional<std::string>
FindFirst(std::string_view key)
const;
101 std::vector<std::string_view>
FindAll(std::string_view key)
const;
102 void Write(std::string&& key, std::string&& value);
122 std::vector<std::pair<std::string, std::string>>
m_headers;
186 WriteReply(status, std::as_bytes(std::span{reply_body_view}));
195 std::pair<bool, std::string>
GetHeader(std::string_view hdr)
const;
197 void WriteHeader(std::string&& hdr, std::string&& value);
208 explicit HTTPServer(std::function<
void(std::unique_ptr<HTTPRequest>&&)> func)
209 : m_request_dispatcher{
std::move(func)} {}
268 m_request_dispatcher = std::move(func));
346 std::unordered_map<Sock::EventsPerSock::key_type,
347 std::shared_ptr<HTTPRemoteClient>,
464 std::vector<std::byte> m_recv_buffer{};
474 std::atomic_bool m_req_busy{
false};
482 std::vector<std::byte> m_send_buffer
GUARDED_BY(m_send_mutex);
517 std::atomic_bool m_connection_busy{
true};
522 std::atomic_bool m_keep_alive{
false};
529 std::atomic_bool m_disconnect{
false};
537 : m_id(id), m_addr(addr), m_origin(addr.ToStringAddrPort()), m_sock{
std::move(socket)}, m_idle_since{
Now<
SteadySeconds>()} {}
#define Assume(val)
Assume is the identity function.
A combination of a network address (CNetAddr) and a (TCP) port.
A helper class for interruptible sleeps.
RAII helper class that manages a socket and closes it automatically when it goes out of scope.
std::unordered_map< std::shared_ptr< const Sock >, Events, HashSharedPtrSock, EqualSharedPtrSock > EventsPerSock
On which socket to wait for what events in WaitMany().
std::deque< std::unique_ptr< HTTPRequest > > m_req_queue
Requests from a client must be processed in the order in which they were received,...
std::shared_ptr< Sock > m_sock GUARDED_BY(m_sock_mutex)
Underlying socket.
std::vector< std::byte > m_send_buffer GUARDED_BY(m_send_mutex)
Mutex m_sock_mutex
Mutex that serializes the Send() and Recv() calls on m_sock.
std::atomic< SteadySeconds > m_idle_since
Timestamp of last send or receive activity, used for -rpcservertimeout.
const HTTPServer::Id m_id
ID provided by HTTPServer upon connection and instantiation.
Mutex m_send_mutex
Response data destined for this client.
HTTPRemoteClient(HTTPServer::Id id, const CService &addr, std::unique_ptr< Sock > socket)
HTTPRemoteClient(const HTTPRemoteClient &)=delete
const CService m_addr
Remote address of connected client.
const std::string m_origin
IP:port of connected client, cached for logging purposes.
bool m_send_ready GUARDED_BY(m_send_mutex)
Set true by worker threads after writing a response to m_send_buffer.
HTTPRemoteClient & operator=(const HTTPRemoteClient &)=delete
std::string GetURI() const
HTTPHeaders m_response_headers
Response headers may be set in advance before response body is known.
HTTPRequestMethod m_method
std::optional< std::string > GetQueryParameter(std::string_view key) const
std::string ReadBody() const
HTTPRequest()
Construct with a null client for unit tests.
bool LoadHeaders(LineReader &reader)
std::pair< bool, std::string > GetHeader(std::string_view hdr) const
void WriteHeader(std::string &&hdr, std::string &&value)
std::shared_ptr< HTTPRemoteClient > m_client
Pointer to the client that made the request so we know who to respond to.
bool LoadControlData(LineReader &reader)
Methods that attempt to parse HTTP request fields line-by-line from a receive buffer.
HTTPRequestMethod GetRequestMethod() const
void WriteReply(HTTPStatusCode status, std::span< const std::byte > reply_body={})
HTTPRequest(std::shared_ptr< HTTPRemoteClient > client)
void WriteReply(HTTPStatusCode status, std::string_view reply_body_view)
bool LoadBody(LineReader &reader)
std::string StringifyHeaders() const
void NewSockAccepted(std::unique_ptr< Sock > &&sock, const CService &addr)
After a new socket with a client has been created, configure its flags, make a new HTTPRemoteClient a...
void ThreadSocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_request_dispatcher_mutex)
Check connected and listening sockets for IO readiness and process them accordingly.
std::function< void(std::unique_ptr< HTTPRequest > &&)> m_request_dispatcher GUARDED_BY(m_request_dispatcher_mutex)
std::vector< std::shared_ptr< Sock > > m_listen
List of listening sockets.
size_t GetConnectionsCount() const
Get the number of HTTPRemoteClients we are connected to.
CThreadInterrupt m_interrupt_net
This is signaled when network activity should cease.
std::atomic_bool m_disconnect_all_clients
Flag used during shutdown.
void DisconnectClients()
Close underlying socket connections for flagged clients by removing their shared pointer from m_conne...
void StopListening()
Stop listening by closing all listening sockets.
void SocketHandlerListening(const Sock::EventsPerSock &events_per_sock)
Accept incoming connections, one from each read-ready listening socket.
std::vector< std::shared_ptr< HTTPRemoteClient > > m_connected
List of HTTPRemoteClients with connected sockets.
void SetServerTimeout(std::chrono::seconds seconds)
Set the idle client timeout (-rpcservertimeout)
IOReadiness GenerateWaitSockets() const
Generate a collection of sockets to check for IO readiness.
std::atomic< Id > m_next_id
The id to assign to the next created connection.
void StartSocketsThreads()
Start the necessary threads for sockets IO.
size_t GetListeningSocketCount() const
Get the number of sockets the server is bound to and listening on.
void MaybeDispatchRequestsFromClient(const std::shared_ptr< HTTPRemoteClient > &client) const EXCLUSIVE_LOCKS_REQUIRED(!m_request_dispatcher_mutex)
Try to read HTTPRequests from a client's receive buffer.
void JoinSocketsThreads()
Join (wait for) the threads started by StartSocketsThreads() to exit.
std::chrono::seconds m_rpcservertimeout
Idle timeout after which clients are disconnected.
HTTPServer(std::function< void(std::unique_ptr< HTTPRequest > &&)> func)
std::thread m_thread_socket_handler
Thread that sends to and receives from sockets and accepts connections.
std::unique_ptr< Sock > AcceptConnection(const Sock &listen_sock, CService &addr)
Accept a connection.
void ClearConnectedClients()
Force-remove all remaining clients from m_connected without waiting for graceful disconnection.
std::atomic< size_t > m_connected_size
The number of connected sockets.
util::Expected< void, std::string > BindAndStartListening(const CService &to)
Bind to a new address:port, start listening and add the listen socket to m_listen.
Id GetNewId()
Generate an id for a newly created connection.
void StopAccepting()
Stop accepting new connections in the I/O loop.
Mutex m_request_dispatcher_mutex
std::atomic_bool m_stop_accepting
Flag used during shutdown to stop accepting new connections.
void SetRequestHandler(std::function< void(std::unique_ptr< HTTPRequest > &&)> func) EXCLUSIVE_LOCKS_REQUIRED(!m_request_dispatcher_mutex)
Update the request handler method.
void DisconnectAllClients()
Start disconnecting clients when possible in the I/O loop.
void InterruptNet()
Stop network activity.
void SocketHandlerConnected(const IOReadiness &io_readiness) const EXCLUSIVE_LOCKS_REQUIRED(!m_request_dispatcher_mutex)
Do the read/write for connected sockets that are ready for IO.
uint64_t Id
Each connection is assigned an unique id of this type.
The util::Expected class provides a standard way for low-level functions to return either error value...
Helper class that manages an interrupt flag, and allows a thread or signal to interrupt another threa...
static const int DEFAULT_HTTP_SERVER_TIMEOUT
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
Unregister handler for prefix.
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
Register handler for prefix.
static const int DEFAULT_HTTP_WORKQUEUE
The default value for -rpcworkqueue.
static const int DEFAULT_HTTP_THREADS
The default value for -rpcthreads.
std::function< void(http_bitcoin::HTTPRequest *req, const std::string &)> HTTPRequestHandler
Handler for requests to a certain HTTP path.
constexpr size_t MIN_REQUEST_LINE_LENGTH
Shortest valid request line, used by libevent in evhttp_parse_request_line()
void StartHTTPServer()
Start HTTP server.
std::optional< std::string > GetQueryParameterFromUri(const std::string_view uri, const std::string_view key)
constexpr uint64_t MAX_BODY_SIZE
Maximum size of an HTTP request body.
constexpr size_t MAX_HEADERS_SIZE
Maximum size of each headers line in an HTTP request, also the maximum size of all headers total.
void StopHTTPServer()
Stop HTTP server.
void InterruptHTTPServer()
Interrupt HTTP server threads.
bool InitHTTPServer()
Initialize HTTP server.
bool(* handler)(const std::any &context, HTTPRequest *req, const std::string &strReq)
HTTPStatusCode
HTTP status codes.
@ HTTP_INTERNAL_SERVER_ERROR
Thrown when a request body exceeds MAX_BODY_SIZE (or will exceed, in chunked transfer) so the server ...
Info about which socket has which event ready and a reverse map back to the HTTPRemoteClient that own...
std::unordered_map< Sock::EventsPerSock::key_type, std::shared_ptr< HTTPRemoteClient >, Sock::HashSharedPtrSock, Sock::EqualSharedPtrSock > httpclients_per_sock
Map of socket -> HTTPRemoteClient.
Sock::EventsPerSock events_per_sock
Map of socket -> socket events.
uint8_t major
Default HTTP protocol version 1.1 is used by error responses when a request is unreadable.
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
#define EXCLUSIVE_LOCKS_REQUIRED(...)
T Now()
Return the current time point cast to the given precision.
std::chrono::time_point< std::chrono::steady_clock, std::chrono::seconds > SteadySeconds