Bitcoin Core 31.99.0
P2P Digital Currency
httpserver.h
Go to the documentation of this file.
1// Copyright (c) 2015-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#ifndef BITCOIN_HTTPSERVER_H
6#define BITCOIN_HTTPSERVER_H
7
8#include <atomic>
9#include <functional>
10#include <memory>
11#include <optional>
12#include <span>
13#include <stdexcept>
14#include <string>
15#include <vector>
16
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>
26
27namespace util {
28class SignalInterrupt;
29} // namespace util
30
34inline constexpr int DEFAULT_HTTP_THREADS=16;
35
40inline constexpr int DEFAULT_HTTP_WORKQUEUE=64;
41
42inline constexpr int DEFAULT_HTTP_SERVER_TIMEOUT=30;
43
45 UNKNOWN,
46 GET,
47 POST,
48 HEAD,
49 PUT
50};
51
52namespace http_bitcoin {
53 class HTTPRequest;
54}
56using HTTPRequestHandler = std::function<void(http_bitcoin::HTTPRequest* req, const std::string&)>;
57
62void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler);
64void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch);
65
66namespace http_bitcoin {
68
70inline constexpr size_t MIN_REQUEST_LINE_LENGTH = std::string_view("GET / HTTP/1.0").size();
71
76inline constexpr size_t MAX_HEADERS_SIZE{8192};
77
79inline constexpr uint64_t MAX_BODY_SIZE{32_MiB};
80
83struct ContentTooLargeError : std::runtime_error {
84 using std::runtime_error::runtime_error;
85};
86
88{
89public:
95 std::optional<std::string> FindFirst(std::string_view key) const;
100 std::vector<std::string_view> FindAll(std::string_view key) const;
101 void Write(std::string&& key, std::string&& value);
105 void RemoveAll(std::string_view key);
115 bool Read(util::LineReader& reader, bool write = true);
116 std::string Stringify() const;
117
118private:
123 std::vector<std::pair<std::string, std::string>> m_headers;
124
126 size_t m_consumed{0};
127};
128
135 uint8_t major{1};
136 uint8_t minor{1};
138};
139
140
142{
143public:
145
148
149 std::string StringifyHeaders() const;
150};
151
152class HTTPRemoteClient;
153
155{
156public:
158 std::string m_target;
161 std::string m_body;
162
164 std::weak_ptr<HTTPRemoteClient> m_client;
165
168
169 explicit HTTPRequest(const std::shared_ptr<HTTPRemoteClient>& client) : m_client{client} {}
171 explicit HTTPRequest() : m_client{} {}
172
186
187 void WriteReply(HTTPStatusCode status, std::span<const std::byte> reply_body = {});
188 void WriteReply(HTTPStatusCode status, std::string_view reply_body_view)
189 {
190 WriteReply(status, std::as_bytes(std::span{reply_body_view}));
191 }
192
193 // These methods reimplement the API from http_libevent::HTTPRequest
194 // for downstream JSONRPC and REST modules.
195 std::string GetURI() const { return m_target; }
196 CService GetPeer() const;
198 std::optional<std::string> GetQueryParameter(std::string_view key) const;
199 std::pair<bool, std::string> GetHeader(std::string_view hdr) const;
200 std::string ReadBody() const { return m_body; }
201 void WriteHeader(std::string&& hdr, std::string&& value);
202
203 enum class State {
204 Init,
205 NeedsHeaders,
206 NeedsBody,
207 Complete,
208 Error
209 };
210 State GetState() const { return m_state; }
211 void SetState(State state) { m_state = state; }
212
213 // If a large request is sent with "Transfer-encoding: chunked" we may
214 // read the chunk size in a separate I/O loop iteration than the chunk
215 // of data itself. Store the chunk size value here until the chunk is read.
216 std::optional<uint64_t> m_chunk_size;
217 // We may also read a large chunk over multiple loop iterations.
218 // Track the progress of the chunk here.
219 uint64_t m_chunk_read{0};
220
221private:
223};
224
226{
227public:
231 using Id = uint64_t;
232
233 explicit HTTPServer(std::function<void(std::unique_ptr<HTTPRequest>&&)> func)
234 : m_request_dispatcher{std::move(func)} {}
235
236 virtual ~HTTPServer()
237 {
238 Assume(!m_thread_socket_handler.joinable()); // Missing call to JoinSocketsThreads()
239 Assume(m_connected.empty()); // Missing call to DisconnectClients(), or disconnect flags not set
240 Assume(m_listen.empty()); // Missing call to StopListening()
241 }
242
246 bool InitHTTPAllowList();
247
254
258 void StopListening();
259
263 size_t GetListeningSocketCount() const { return m_listen.size(); }
264
268 size_t GetConnectionsCount() const { return m_connected_size.load(std::memory_order_acquire); }
269
273 void StartSocketsThreads();
274
278 void JoinSocketsThreads();
279
284
289
294 void SetRequestHandler(std::function<void(std::unique_ptr<HTTPRequest>&&)> func)
296 {
298 m_request_dispatcher = std::move(func));
299 }
300
308
312 void SetServerTimeout(std::chrono::seconds seconds) { m_rpcservertimeout = seconds; }
313
319
320private:
324 std::vector<std::shared_ptr<Sock>> m_listen;
325
329 std::atomic<Id> m_next_id{0};
330
337 std::vector<std::shared_ptr<HTTPRemoteClient>> m_connected;
338
343 std::atomic_bool m_stop_accepting{false};
344
350 std::atomic_bool m_disconnect_all_clients{false};
351
357 std::atomic<size_t> m_connected_size{0};
358
363 struct IOReadiness {
370
376 std::unordered_map<Sock::EventsPerSock::key_type,
377 std::shared_ptr<HTTPRemoteClient>,
381 };
382
387
393
394 /*
395 * What to do with HTTP requests once received, validated and parsed.
396 * Set in main thread by server start and interrupt but read in
397 * worker threads.
398 */
401 std::function<void(std::unique_ptr<HTTPRequest>&&)> m_request_dispatcher GUARDED_BY(m_request_dispatcher_mutex);
403
408
412 std::vector<CSubNet> m_allow_subnets;
413
417 bool ClientAllowed(const CNetAddr& netaddr) const;
418
425 std::unique_ptr<Sock> AcceptConnection(const Sock& listen_sock, CService& addr);
426
430 Id GetNewId();
431
438 void NewSockAccepted(std::unique_ptr<Sock>&& sock, const CService& addr);
439
444 void SocketHandlerConnected(const IOReadiness& io_readiness) const
446
451 void SocketHandlerListening(const Sock::EventsPerSock& events_per_sock);
452
459
465
473 void MaybeDispatchRequestsFromClient(const std::shared_ptr<HTTPRemoteClient>& client) const
475
482 void DisconnectClients();
483};
484
485std::optional<std::string> GetQueryParameterFromUri(std::string_view uri, std::string_view key);
486
488{
489public:
492
495
497 const std::string m_origin;
498
504 std::string m_recv_buffer{};
505
509 std::unique_ptr<HTTPRequest> m_req;
510
513 std::atomic_bool m_req_busy{false};
514
521 std::vector<std::byte> m_send_buffer GUARDED_BY(m_send_mutex);
523
532 bool m_send_ready GUARDED_BY(m_send_mutex){false};
533
540
548 std::shared_ptr<Sock> m_sock GUARDED_BY(m_sock_mutex);
549
556 std::atomic_bool m_connection_busy{true};
557
561 std::atomic_bool m_keep_alive{false};
562
568 std::atomic_bool m_disconnect{false};
569
573 std::atomic<SteadySeconds> m_idle_since;
574
575 explicit HTTPRemoteClient(HTTPServer::Id id, const CService& addr, std::unique_ptr<Sock> socket)
576 : m_id(id), m_addr(addr), m_origin(addr.ToStringAddrPort()), m_sock{std::move(socket)}, m_idle_since{Now<SteadySeconds>()} {}
577
578 // Disable copies (should only be used as shared pointers)
581
588 void ReadRequest(HTTPRequest& req);
589
594 bool MaybeSendBytesFromBuffer() EXCLUSIVE_LOCKS_REQUIRED(!m_send_mutex, !m_sock_mutex);
595};
596
600bool InitHTTPServer();
601
606void StartHTTPServer();
607
610
612void StopHTTPServer();
613} // namespace http_bitcoin
614
615#endif // BITCOIN_HTTPSERVER_H
#define Assume(val)
Assume is the identity function.
Definition: check.h:128
Network address.
Definition: netaddress.h:113
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:530
A helper class for interruptible sleeps.
Definition: init.h:13
RAII helper class that manages a socket and closes it automatically when it goes out of scope.
Definition: sock.h:35
std::unordered_map< std::shared_ptr< const Sock >, Events, HashSharedPtrSock, EqualSharedPtrSock > EventsPerSock
On which socket to wait for what events in WaitMany().
Definition: sock.h:216
bool Read(util::LineReader &reader, bool write=true)
Definition: httpserver.cpp:301
void RemoveAll(std::string_view key)
Definition: httpserver.cpp:293
std::vector< std::string_view > FindAll(std::string_view key) const
Definition: httpserver.cpp:277
std::vector< std::pair< std::string, std::string > > m_headers
Headers can have duplicate field names, so we use a vector of key-value pairs instead of a map.
Definition: httpserver.h:123
size_t m_consumed
Track total bytes consumed in Read() for limit checks.
Definition: httpserver.h:126
std::string Stringify() const
Definition: httpserver.cpp:357
void Write(std::string &&key, std::string &&value)
Definition: httpserver.cpp:288
std::optional< std::string > FindFirst(std::string_view key) const
Definition: httpserver.cpp:267
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.
Definition: httpserver.h:539
std::atomic< SteadySeconds > m_idle_since
Timestamp of last send or receive activity, used for -rpcservertimeout.
Definition: httpserver.h:573
const HTTPServer::Id m_id
ID provided by HTTPServer upon connection and instantiation.
Definition: httpserver.h:491
Mutex m_send_mutex
Response data destined for this client.
Definition: httpserver.h:520
HTTPRemoteClient(HTTPServer::Id id, const CService &addr, std::unique_ptr< Sock > socket)
Definition: httpserver.h:575
HTTPRemoteClient(const HTTPRemoteClient &)=delete
const CService m_addr
Remote address of connected client.
Definition: httpserver.h:494
std::unique_ptr< HTTPRequest > m_req
Requests from a client must be processed in the order in which they were received,...
Definition: httpserver.h:509
const std::string m_origin
IP:port of connected client, cached for logging purposes.
Definition: httpserver.h:497
bool m_send_ready GUARDED_BY(m_send_mutex)
Set true by worker threads after writing a response to m_send_buffer.
Definition: httpserver.h:532
HTTPRemoteClient & operator=(const HTTPRemoteClient &)=delete
std::string GetURI() const
Definition: httpserver.h:195
State GetState() const
Definition: httpserver.h:210
HTTPHeaders m_response_headers
Response headers may be set in advance before response body is known.
Definition: httpserver.h:167
std::optional< uint64_t > m_chunk_size
Definition: httpserver.h:216
HTTPRequestMethod m_method
Definition: httpserver.h:157
std::optional< std::string > GetQueryParameter(std::string_view key) const
Definition: httpserver.cpp:664
std::string ReadBody() const
Definition: httpserver.h:200
HTTPRequest()
Construct with a null client for unit tests.
Definition: httpserver.h:171
bool LoadHeaders(LineReader &reader)
Definition: httpserver.cpp:428
std::pair< bool, std::string > GetHeader(std::string_view hdr) const
Definition: httpserver.cpp:696
void WriteHeader(std::string &&hdr, std::string &&value)
Definition: httpserver.cpp:702
std::weak_ptr< HTTPRemoteClient > m_client
Pointer to the client that made the request so we know who to respond to.
Definition: httpserver.h:164
CService GetPeer() const
Definition: httpserver.cpp:655
HTTPRequest(const std::shared_ptr< HTTPRemoteClient > &client)
Definition: httpserver.h:169
bool LoadControlData(LineReader &reader)
Methods that attempt to parse HTTP request fields line-by-line from a receive buffer.
Definition: httpserver.cpp:380
HTTPRequestMethod GetRequestMethod() const
Definition: httpserver.h:197
void WriteReply(HTTPStatusCode status, std::span< const std::byte > reply_body={})
Definition: httpserver.cpp:537
void SetState(State state)
Definition: httpserver.h:211
void WriteReply(HTTPStatusCode status, std::string_view reply_body_view)
Definition: httpserver.h:188
bool LoadBody(LineReader &reader)
Definition: httpserver.cpp:433
HTTPStatusCode m_status
Definition: httpserver.h:146
std::string StringifyHeaders() const
Definition: httpserver.cpp:370
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...
Definition: httpserver.cpp:850
void ThreadSocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_request_dispatcher_mutex)
Check connected and listening sockets for IO readiness and process them accordingly.
Definition: httpserver.cpp:998
bool InitHTTPAllowList()
Parse the user's -rpcallowip settings and populate m_allow_subnets.
Definition: httpserver.cpp:90
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.
Definition: httpserver.h:324
size_t GetConnectionsCount() const
Get the number of HTTPRemoteClients we are connected to.
Definition: httpserver.h:268
CThreadInterrupt m_interrupt_net
This is signaled when network activity should cease.
Definition: httpserver.h:386
std::atomic_bool m_disconnect_all_clients
Flag used during shutdown.
Definition: httpserver.h:350
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.
Definition: httpserver.cpp:783
void SocketHandlerListening(const Sock::EventsPerSock &events_per_sock)
Accept incoming connections, one from each read-ready listening socket.
Definition: httpserver.cpp:950
std::vector< std::shared_ptr< HTTPRemoteClient > > m_connected
List of HTTPRemoteClients with connected sockets.
Definition: httpserver.h:337
void SetServerTimeout(std::chrono::seconds seconds)
Set the idle client timeout (-rpcservertimeout)
Definition: httpserver.h:312
std::vector< CSubNet > m_allow_subnets
List of subnets to allow HTTP connections from.
Definition: httpserver.h:412
IOReadiness GenerateWaitSockets() const
Generate a collection of sockets to check for IO readiness.
Definition: httpserver.cpp:970
std::atomic< Id > m_next_id
The id to assign to the next created connection.
Definition: httpserver.h:329
void StartSocketsThreads()
Start the necessary threads for sockets IO.
Definition: httpserver.cpp:788
size_t GetListeningSocketCount() const
Get the number of sockets the server is bound to and listening on.
Definition: httpserver.h:263
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.
Definition: httpserver.cpp:800
bool ClientAllowed(const CNetAddr &netaddr) const
Check an incoming connection's source IP against the allow list.
Definition: httpserver.cpp:79
std::chrono::seconds m_rpcservertimeout
Idle timeout after which clients are disconnected.
Definition: httpserver.h:407
HTTPServer(std::function< void(std::unique_ptr< HTTPRequest > &&)> func)
Definition: httpserver.h:233
std::thread m_thread_socket_handler
Thread that sends to and receives from sockets and accepts connections.
Definition: httpserver.h:392
std::unique_ptr< Sock > AcceptConnection(const Sock &listen_sock, CService &addr)
Accept a connection.
Definition: httpserver.cpp:807
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.
Definition: httpserver.h:357
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.
Definition: httpserver.cpp:707
Id GetNewId()
Generate an id for a newly created connection.
Definition: httpserver.cpp:845
void StopAccepting()
Stop accepting new connections in the I/O loop.
Definition: httpserver.h:307
std::atomic_bool m_stop_accepting
Flag used during shutdown to stop accepting new connections.
Definition: httpserver.h:343
void SetRequestHandler(std::function< void(std::unique_ptr< HTTPRequest > &&)> func) EXCLUSIVE_LOCKS_REQUIRED(!m_request_dispatcher_mutex)
Update the request handler method.
Definition: httpserver.h:294
void DisconnectAllClients()
Start disconnecting clients when possible in the I/O loop.
Definition: httpserver.h:288
void InterruptNet()
Stop network activity.
Definition: httpserver.h:283
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.
Definition: httpserver.cpp:877
uint64_t Id
Each connection is assigned an unique id of this type.
Definition: httpserver.h:231
The util::Expected class provides a standard way for low-level functions to return either error value...
Definition: expected.h:44
Helper class that manages an interrupt flag, and allows a thread or signal to interrupt another threa...
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
Unregister handler for prefix.
Definition: httpserver.cpp:249
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
Register handler for prefix.
Definition: httpserver.cpp:242
constexpr int DEFAULT_HTTP_SERVER_TIMEOUT
Definition: httpserver.h:42
constexpr int DEFAULT_HTTP_THREADS
The default value for -rpcthreads.
Definition: httpserver.h:34
constexpr int DEFAULT_HTTP_WORKQUEUE
The default value for -rpcworkqueue.
Definition: httpserver.h:40
std::function< void(http_bitcoin::HTTPRequest *req, const std::string &)> HTTPRequestHandler
Handler for requests to a certain HTTP path.
Definition: httpserver.h:56
HTTPRequestMethod
Definition: httpserver.h:44
util::LineReader reader
std::unique_ptr< ProxyClient< messages::FooInterface > > client
std::thread thread
Thread variable should be after other struct members so the thread does not start until the other mem...
constexpr size_t MIN_REQUEST_LINE_LENGTH
Shortest valid request line, used by libevent in evhttp_parse_request_line()
Definition: httpserver.h:70
void StartHTTPServer()
Start HTTP server.
std::optional< std::string > GetQueryParameterFromUri(const std::string_view uri, const std::string_view key)
Definition: httpserver.cpp:671
constexpr uint64_t MAX_BODY_SIZE
Maximum size of an HTTP request body.
Definition: httpserver.h:79
constexpr size_t MAX_HEADERS_SIZE
Maximum size of each headers line in an HTTP request, also the maximum size of all headers total.
Definition: httpserver.h:76
void StopHTTPServer()
Stop HTTP server.
void InterruptHTTPServer()
Interrupt HTTP server threads.
bool InitHTTPServer()
Initialize HTTP server.
const char * prefix
Definition: rest.cpp:1180
bool(* handler)(const std::any &context, HTTPRequest *req, const std::string &strReq)
Definition: rest.cpp:1181
HTTPStatusCode
HTTP status codes.
Definition: protocol.h:11
@ HTTP_INTERNAL_SERVER_ERROR
Definition: protocol.h:20
Thrown when a request body exceeds MAX_BODY_SIZE (or will exceed, in chunked transfer) so the server ...
Definition: httpserver.h:83
Info about which socket has which event ready and a reverse map back to the HTTPRemoteClient that own...
Definition: httpserver.h:363
std::unordered_map< Sock::EventsPerSock::key_type, std::shared_ptr< HTTPRemoteClient >, Sock::HashSharedPtrSock, Sock::EqualSharedPtrSock > httpclients_per_sock
Map of socket -> HTTPRemoteClient.
Definition: httpserver.h:380
Sock::EventsPerSock events_per_sock
Map of socket -> socket events.
Definition: httpserver.h:369
uint8_t major
Default HTTP protocol version 1.1 is used by error responses when a request is unreadable.
Definition: httpserver.h:135
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:299
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:49
T Now()
Return the current time point cast to the given precision.
Definition: time.h:135
std::chrono::time_point< std::chrono::steady_clock, std::chrono::seconds > SteadySeconds
Definition: time.h:38