5#include <bitcoin-build-config.h>
30#include <condition_variable>
39#include <unordered_map>
84 if (subnet.Match(netaddr))
99 for (
const std::string& strAllow :
gArgs.
GetArgs(
"-rpcallowip")) {
101 if (!subnet.IsValid()) {
103 Untranslated(
strprintf(
"Invalid -rpcallowip subnet specification: %s. Valid values are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0), a network/CIDR (e.g. 1.2.3.4/24), all ipv4 (0.0.0.0/0), or all ipv6 (::/0). RFC4193 is allowed only if -cjdnsreachable=0.", strAllow)),
109 std::string strAllowed;
111 strAllowed += subnet.ToString() +
" ";
121 case GET:
return "GET";
122 case POST:
return "POST";
123 case HEAD:
return "HEAD";
124 case PUT:
return "PUT";
125 case UNKNOWN:
return "unknown";
141 hreq->GetPeer().ToStringAddrPort());
147 std::string strURI = hreq->GetURI();
150 std::vector<HTTPPathHandler>::const_iterator i = pathHandlers.begin();
151 std::vector<HTTPPathHandler>::const_iterator iend = pathHandlers.end();
152 for (; i != iend; ++i) {
155 match = (strURI == i->prefix);
157 match = strURI.starts_with(i->prefix);
159 path = strURI.substr(i->prefix.size());
167 LogWarning(
"Request rejected because http work queue depth exceeded, it can be increased with the -rpcworkqueue= setting");
172 auto item = [req = hreq, in_path = std::move(path), fn = i->handler]() {
175 fn(req.get(), in_path);
177 }
catch (
const std::exception& e) {
178 LogWarning(
"Unexpected error while processing request for '%s'. Error msg: '%s'", req->
GetURI(), e.what());
181 LogWarning(
"Unknown error while processing request for '%s'", req->
GetURI());
182 err_msg =
"unknown error";
191 Assume(hreq.use_count() == 1);
211 std::vector<std::pair<std::string, uint16_t>> endpoints;
219 endpoints.emplace_back(
"::1", http_port);
220 endpoints.emplace_back(
"127.0.0.1", http_port);
222 LogWarning(
"Option -rpcallowip was specified without -rpcbind; this doesn't usually make sense");
225 LogWarning(
"Option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect");
228 for (
const std::string& strRPCBind :
gArgs.
GetArgs(
"-rpcbind")) {
229 uint16_t port{http_port};
235 endpoints.emplace_back(host, port);
251 std::vector<HTTPPathHandler>::iterator i = pathHandlers.begin();
252 std::vector<HTTPPathHandler>::iterator iend = pathHandlers.end();
253 for (; i != iend; ++i)
254 if (i->prefix ==
prefix && i->exactMatch == exactMatch)
259 pathHandlers.erase(i);
277 std::vector<std::string_view>
ret;
280 ret.push_back(item.second);
288 m_headers.emplace_back(std::move(key), std::move(value));
293 auto moved = std::ranges::remove_if(
m_headers, [key] (
auto& pair) {
296 m_headers.erase(moved.begin(), moved.end());
307 const std::string_view& line = *maybe_line;
322 if (line.find_first_of(
"\r\n\0", 0, 3) != std::string_view::npos)
throw std::runtime_error(
"Header contains invalid character");
327 const size_t pos{line.find(
':')};
328 if (pos == std::string_view::npos)
throw std::runtime_error(
"HTTP header missing colon (:)");
332 std::string_view key = line.substr(0, pos);
333 if (key.find_first_of(
" \t\n\r\f\v") != std::string_view::npos)
throw std::runtime_error(
"Invalid header field-name contains whitespace");
335 std::string value =
util::TrimString(std::string_view(line).substr(pos + 1));
340 if (key.empty())
throw std::runtime_error(
"Empty HTTP header name");
343 Write(std::string(key), std::move(value));
358 for (
const auto& [key, value] :
m_headers) {
359 out += key +
": " + value +
"\r\n";
370 return strprintf(
"HTTP/%d.%d %d %s\r\n%s",
381 if (!maybe_line)
return false;
382 const std::string_view& request_line = *maybe_line;
391 if (request_line.find(
'\0') != std::string_view::npos)
throw std::runtime_error(
"Invalid request line contains NUL");
393 const std::vector<std::string_view> parts{Split<std::string_view>(request_line,
" ")};
394 if (parts.size() != 3)
throw std::runtime_error(
"HTTP request line malformed");
396 if (parts[0] ==
"GET") {
398 }
else if (parts[0] ==
"POST") {
400 }
else if (parts[0] ==
"HEAD") {
402 }
else if (parts[0] ==
"PUT") {
410 if (parts[2].rfind(
"HTTP/") != 0)
throw std::runtime_error(
"HTTP request line malformed");
414 const std::vector<std::string_view> version_parts{Split<std::string_view>(parts[2].substr(5),
".")};
415 if (version_parts.size() != 2)
throw std::runtime_error(
"HTTP request line malformed");
416 if (version_parts[0].size() != 1 || version_parts[1].size() != 1)
throw std::runtime_error(
"HTTP bad version");
417 auto major = ToIntegral<uint8_t>(version_parts[0]);
418 auto minor = ToIntegral<uint8_t>(version_parts[1]);
419 if (!major || !minor || major != 1 || minor > 9)
throw std::runtime_error(
"HTTP bad version");
435 if (transfer_encoding_header &&
ToLower(transfer_encoding_header.value()) ==
"chunked") {
442 if (!maybe_chunk_size)
return false;
446 std::string_view chunk_size_noext{maybe_chunk_size.value()};
447 const auto semicolon_pos = chunk_size_noext.find(
';');
448 if (semicolon_pos != chunk_size_noext.npos) {
449 chunk_size_noext.remove_suffix(chunk_size_noext.size() - semicolon_pos);
453 if (!
m_chunk_size)
throw std::runtime_error(
"Cannot parse chunk length value");
479 const uint64_t buffer_has{std::min(chunk_need,
static_cast<uint64_t
>(
reader.
Remaining()))};
496 if (!crlf.value().empty())
throw std::runtime_error(
"Improperly terminated chunk");
509 if (content_length_values.empty())
return true;
513 const auto& first_content_length_value{content_length_values[0]};
514 for (
size_t i = 1; i < content_length_values.size(); ++i) {
515 if (content_length_values[i] != first_content_length_value)
throw std::runtime_error(
"Differing Content-Length values");
518 const auto content_length{ToIntegral<uint64_t>(first_content_length_value)};
519 if (!content_length)
throw std::runtime_error(
"Cannot parse Content-Length value");
525 const uint64_t body_need{*content_length -
m_body.size()};
526 const uint64_t buffer_has{std::min(body_need,
static_cast<uint64_t
>(
reader.
Remaining()))};
531 return m_body.size() == *content_length;
550 bool needs_body{status !=
HTTP_NO_CONTENT && (status < 100 || status >= 200)};
551 bool needs_content_length{
false};
553 bool keep_alive{
false};
561 if (connection_header &&
ToLower(connection_header.value()) ==
"keep-alive") {
566 if (needs_body) needs_content_length =
true;
572 const int64_t now_seconds{TicksSinceEpoch<std::chrono::seconds>(
NodeClock::now())};
576 if (needs_body) needs_content_length =
true;
583 if (needs_content_length) {
589 res.
headers.
Write(
"Content-Type",
"text/html; charset=ISO-8859-1");
593 if (connection_header &&
ToLower(connection_header.value()) ==
"close") {
602 client->Send(res, reply_body, keep_alive);
612 const auto headers_bytes{std::as_bytes(std::span{
headers})};
614 bool send_buffer_was_empty{
false};
618 send_buffer_was_empty = m_send_buffer.empty();
619 m_send_buffer.insert(m_send_buffer.end(), headers_bytes.begin(), headers_bytes.end());
624 m_send_buffer.insert(m_send_buffer.end(), reply_body.begin(), reply_body.end());
634 if (!send_buffer_was_empty) m_send_ready =
true;
639 "HTTPResponse (status code: %d size: %lld) added to send buffer for client %s (id=%llu)",
641 headers_bytes.size() + reply_body.size(),
649 if (send_buffer_was_empty) {
659 if (std::shared_ptr c{
m_client.lock()}) {
676 size_t start = uri.find(
'?');
677 if (start == std::string::npos)
return std::nullopt;
678 size_t end = uri.find(
'#', start);
679 if (end == std::string::npos) {
682 const std::string_view query{uri.data() + start + 1, end - start - 1};
684 const std::vector<std::string_view> params{Split<std::string_view>(query,
"&")};
685 for (
const std::string_view& param : params) {
686 size_t delim = param.find(
'=');
687 if (key ==
UrlDecode(param.substr(0, delim))) {
688 if (delim == std::string::npos) {
691 return std::string(
UrlDecode(param.substr(delim + 1)));
711 sockaddr_storage storage;
712 auto sa =
reinterpret_cast<sockaddr*
>(&storage);
713 socklen_t len{
sizeof(storage)};
729 "Cannot set SO_REUSEADDR on %s listen socket: %s, continuing anyway",
740 "Cannot set IPV6_V6ONLY on %s listen socket: %s, continuing anyway",
746 int prot_level{PROTECTION_LEVEL_UNRESTRICTED};
747 if (sock->SetSockOpt(IPPROTO_IPV6,
748 IPV6_PROTECTION_LEVEL,
752 "Cannot set IPV6_PROTECTION_LEVEL on %s listen socket: %s, continuing anyway",
779 m_listen.emplace_back(std::move(sock));
811 Assume(std::ranges::any_of(
m_listen, [&](
const auto& sock) {
return sock.get() == &listen_sock; }));
813 sockaddr_storage storage;
814 socklen_t len{
sizeof(storage)};
815 auto sa =
reinterpret_cast<sockaddr*
>(&storage);
817 auto sock{listen_sock.
Accept(sa, &len)};
823 "Cannot accept new connection: %s",
832 "Unknown socket family");
837 LogDebug(
BCLog::HTTP,
"Connection from %s rejected: Client network is not allowed HTTP access\n",
848 return m_next_id.fetch_add(1, std::memory_order_relaxed);
853 if (!sock->IsSelectable()) {
855 "connection from %s dropped: non-selectable socket",
869 m_connected.push_back(std::make_shared<HTTPRemoteClient>(
id, addr, std::move(sock)));
874 "HTTP Connection accepted from %s (id=%llu)",
889 const std::shared_ptr<HTTPRemoteClient>&
client{it->second};
899 if (!
client->MaybeSendBytesFromBuffer()) {
904 if (recv_ready || err_ready) {
914 m_request_dispatcher(std::move(request));
932 "Permanent read error from %s (id=%llu): %s",
938 }
else if (nrecv == 0) {
941 "Received EOF from %s (id=%llu)",
967 const auto it = events_per_sock.find(sock);
968 if (it != events_per_sock.end() && it->second.occurred &
Sock::RecvEvent) {
975 if (!sock_accepted)
break;
998 std::shared_ptr<Sock> sock{http_client->GetSock()};
1011 return io_readiness;
1023 if (io_readiness.events_per_sock.empty() ||
1025 !io_readiness.events_per_sock.begin()->first->WaitMany(
SELECT_TIMEOUT,
1026 io_readiness.events_per_sock)) {
1046 if (
client->m_req_busy)
return nullptr;
1058 "HTTP request body too large from client %s (id=%llu): %s",
1064 client->m_disconnect =
true;
1066 }
catch (
const std::runtime_error& e) {
1069 "Error reading HTTP request from client %s (id=%llu): %s",
1076 client->m_disconnect =
true;
1084 "Received a %s request for %s from %s (id=%llu)",
1090 client->m_req_busy =
true;
1091 return std::move(
client->m_req);
1099 const auto now{Now<SteadySeconds>()};
1102 return client->MaybeDisconnect(now,
1120 const bool is_idle{rpcservertimeout.count() > 0 &&
1129 "HTTP client idle timeout %s (id=%llu)",
1136 if (disconnect_all) {
1154 "Disconnecting HTTP client %s (id=%llu)",
1164 LogWarning(
"Force-disconnecting %d HTTP client(s) that did not disconnect gracefully",
m_connected.size());
1216 if (!m_send_buffer.empty()) {
1231 bytes_sent = m_sock->Send(m_send_buffer.data(),
1232 m_send_buffer.size(),
1236 if (bytes_sent < 0) {
1241 m_send_ready =
true;
1248 "Error sending HTTP response data to client %s (id=%llu): %s",
1252 m_send_ready =
false;
1261 Assume(
static_cast<size_t>(bytes_sent) <= m_send_buffer.size());
1262 m_send_buffer.erase(m_send_buffer.begin(),
1263 m_send_buffer.begin() + bytes_sent);
1267 "Sent %d bytes to client %s (id=%llu)",
1275 if (m_send_buffer.empty()) {
1276 m_send_ready =
false;
1287 m_send_ready =
true;
1311 std::vector<std::pair<std::string, uint16_t>> endpoints{
GetBindAddresses()};
1312 bool bind_success{
false};
1313 for (
const auto& [address_string, port] : endpoints) {
1314 LogInfo(
"Binding RPC on address %s port %i", address_string, port);
1315 const std::optional<CService> addr{
Lookup(address_string, port,
false)};
1317 if (addr->IsBindAny()) {
1318 LogWarning(
"The RPC server is not safe to expose to untrusted networks such as the public internet");
1320 auto result{
g_http_server->BindAndStartListening(addr.value())};
1322 LogWarning(
"Binding RPC on address %s failed: %s", addr->ToStringAddrPort(), result.error());
1324 bind_success =
true;
1327 LogWarning(
"Could not bind RPC on address %s port %i: Address lookup failed.", address_string, port);
1331 if (!bind_success) {
1332 LogError(
"Unable to bind any endpoint for RPC server");
1347 LogInfo(
"Starting HTTP server with %d worker threads", rpcThreads);
1382 LogWarning(
"Timeout waiting for HTTP clients to disconnect gracefully, continuing shutdown");
1385 std::this_thread::sleep_for(50ms);
const CBaseChainParams & BaseParams()
Return the currently selected parameters.
#define Assume(val)
Assume is the identity function.
std::vector< std::string > GetArgs(const std::string &strArg) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return a vector of strings of the given argument.
std::string GetArg(const std::string &strArg, const std::string &strDefault) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return string argument or default value.
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
btcsignals::signal< void(const bilingual_str &message, unsigned int style)> ThreadSafeMessageBox
Show message box.
A combination of a network address (CNetAddr) and a (TCP) port.
bool SetSockAddr(const struct sockaddr *paddr, socklen_t addrlen)
Set CService from a network sockaddr.
sa_family_t GetSAFamily() const
Get the address family.
bool GetSockAddr(struct sockaddr *paddr, socklen_t *addrlen) const
Obtain the IPv4/6 socket address this represents.
std::string ToStringAddrPort() const
virtual bool sleep_for(Clock::duration rel_time) EXCLUSIVE_LOCKS_REQUIRED(!mut)
Sleep for the given duration.
Different type to mark Mutex at global scope.
std::atomic_bool m_disconnect
Flag this client for disconnection on next loop.
Mutex m_send_mutex
Response data destined for this client.
void Send(const HTTPResponse &res, std::span< const std::byte > reply_body, bool keep_alive) EXCLUSIVE_LOCKS_REQUIRED(!m_send_mutex
const std::string m_origin
IP:port of connected client, cached for logging purposes.
bool MaybeDisconnect(std::chrono::time_point< SteadyClock > now, std::chrono::seconds rpcservertimeout, bool disconnect_all)
static std::unique_ptr< HTTPRequest > TryReadRequest(const std::shared_ptr< HTTPRemoteClient > &client)
Try to read an HTTPRequest from a client's receive buffer.
const HTTPServer::Id m_id
ID provided by HTTPServer upon connection and instantiation.
std::string m_recv_buffer
In lieu of an intermediate transport class like p2p uses, we copy data from the socket buffer to the ...
void ReadRequest(HTTPRequest &req)
Try to read an HTTP request from the receive buffer.
std::atomic< SteadySeconds > m_idle_since
Timestamp of last send or receive activity, used for -rpcservertimeout.
bool MaybeSendBytesFromBuffer() EXCLUSIVE_LOCKS_REQUIRED(!m_send_mutex
Push data (if there is any) from client's m_send_buffer to the connected socket.
Mutex m_sock_mutex
Mutex that serializes the Send() and Recv() calls on m_sock.
std::atomic_bool m_connection_busy
Initialized to true while server waits for first request from client.
void Receive() EXCLUSIVE_LOCKS_REQUIRED(!m_sock_mutex)
std::atomic_bool m_keep_alive
Client has requested to keep the connection open after all requests have been responded to.
std::atomic_bool m_req_busy
Set to true by the I/O thread when a request is popped off and passed to a worker thread,...
void WriteHeader(std::string &&hdr, std::string &&value)
std::optional< uint64_t > m_chunk_size
std::optional< std::string > GetQueryParameter(std::string_view key) const
std::string GetURI() const
bool LoadHeaders(util::LineReader &reader)
bool LoadControlData(util::LineReader &reader)
Methods that attempt to parse HTTP request fields line-by-line from a receive buffer.
std::weak_ptr< HTTPRemoteClient > m_client
Pointer to the client that made the request so we know who to respond to.
std::optional< std::string > GetHeader(std::string_view hdr) const
HTTPRequestMethod m_method
bool LoadBody(util::LineReader &reader)
void SetState(State state)
void WriteReply(HTTPStatusCode status, std::span< const std::byte > reply_body={})
HTTPHeaders m_response_headers
Response headers may be set in advance before response body is known.
std::atomic< Id > m_next_id
The id to assign to the next created connection.
void ThreadSocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_request_dispatcher_mutex)
Check connected and listening sockets for IO readiness and process them accordingly.
void JoinSocketsThreads()
Join (wait for) the threads started by StartSocketsThreads() to exit.
std::vector< std::shared_ptr< HTTPRemoteClient > > m_connected
List of HTTPRemoteClients with connected sockets.
int m_rpcmaxconnections
Maximum amount of concurrent connections.
CThreadInterrupt m_interrupt_net
This is signaled when network activity should cease.
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.
std::atomic_bool m_disconnect_all_clients
Flag used during shutdown.
Id GetNewId()
Generate an id for a newly created connection.
void DisconnectClients()
Close underlying socket connections for flagged clients by removing their shared pointer from m_conne...
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.
std::vector< CSubNet > m_allow_subnets
List of subnets to allow HTTP connections from.
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.
std::vector< std::shared_ptr< Sock > > m_listen
List of listening sockets.
std::atomic_bool m_stop_accepting
Flag used during shutdown to stop accepting new connections.
void SocketHandlerListening(const Sock::EventsPerSock &events_per_sock)
Accept incoming connections, one from each read-ready listening socket.
IOReadiness GenerateWaitSockets() const
Generate a collection of sockets to check for IO readiness.
std::thread m_thread_socket_handler
Thread that sends to and receives from sockets and accepts connections.
uint64_t Id
Each connection is assigned an unique id of this type.
std::chrono::seconds m_rpcservertimeout
Idle timeout after which clients are disconnected.
void StopListening()
Stop listening by closing all listening sockets.
size_t GetConnectionsCount() const
Get the number of HTTPRemoteClients we are connected to.
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...
bool ClientAllowed(const CNetAddr &netaddr) const
Check an incoming connection's source IP against the allow list.
bool InitHTTPAllowList()
Parse the user's -rpcallowip settings and populate m_allow_subnets.
Mutex m_request_dispatcher_mutex
std::unique_ptr< Sock > AcceptConnection(const Sock &listen_sock, CService &addr)
Accept a connection.
void StartSocketsThreads()
Start the necessary threads for sockets IO.
RAII helper class that manages a socket and closes it automatically when it goes out of scope.
static constexpr Event RecvEvent
If passed to Wait(), then it will wait for readiness to read from the socket.
virtual std::unique_ptr< Sock > Accept(sockaddr *addr, socklen_t *addr_len) const
accept(2) wrapper.
static constexpr Event SendEvent
If passed to Wait(), then it will wait for readiness to send to the socket.
static constexpr Event ErrorEvent
Ignored if passed to Wait(), but could be set in the occurred events if an exceptional condition has ...
std::unordered_map< std::shared_ptr< const Sock >, Events, HashSharedPtrSock, EqualSharedPtrSock > EventsPerSock
On which socket to wait for what events in WaitMany().
Fixed-size thread pool for running arbitrary tasks concurrently.
void Start(int num_workers) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Start worker threads.
util::Expected< Future< F >, SubmitError > Submit(F &&fn) noexcept EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Enqueues a new task for asynchronous execution.
void Stop() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Stop all worker threads and wait for them to exit.
void Interrupt() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Stop accepting new tasks and begin asynchronous shutdown.
size_t WorkQueueSize() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
The util::Expected class provides a standard way for low-level functions to return either error value...
size_t Consumed() const
Returns number of bytes already read from buffer.
std::optional< std::string_view > ReadLine() LIFETIMEBOUND
Returns a string from current iterator position up to (but not including) next and advances iterator...
size_t Remaining() const
Returns remaining size of bytes in buffer.
std::string_view ReadLength(size_t len) LIFETIMEBOUND
Returns string from current iterator position of specified length if possible and advances iterator o...
The util::Unexpected class represents an unexpected value stored in util::Expected.
#define WSAGetLastError()
static std::vector< std::pair< std::string, uint16_t > > GetBindAddresses()
static void WriteNoStoreErrorReply(HTTPRequest &req, HTTPStatusCode status, std::string_view reply={})
void InterruptHTTPServer()
Interrupt HTTP server threads.
static ThreadPool g_threadpool_http("http")
Http thread pool - future: encapsulate in HttpContext
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.
void StartHTTPServer()
Start HTTP server.
static void RejectRequest(std::unique_ptr< HTTPRequest > hreq)
std::string_view RequestMethodString(HTTPRequestMethod m)
HTTP request method as string - use for logging only.
bool InitHTTPServer()
Initialize HTTP server.
static void MaybeDispatchRequestToWorker(std::shared_ptr< HTTPRequest > hreq)
std::optional< std::string > GetQueryParameterFromUri(const std::string_view uri, const std::string_view key)
static constexpr auto SELECT_TIMEOUT
The set of sockets cannot be modified while waiting, so the sleep time needs to be small to avoid new...
static std::unique_ptr< HTTPServer > g_http_server
HTTP module state.
static constexpr int SOCKET_OPTION_TRUE
Explicit alias for setting socket option methods.
static int g_max_queue_depth
void StopHTTPServer()
Stop HTTP server.
static std::vector< HTTPPathHandler > pathHandlers GUARDED_BY(g_httppathhandlers_mutex)
static GlobalMutex g_httppathhandlers_mutex
Handlers for (sub)paths.
constexpr int DEFAULT_MAX_HTTP_CONNECTIONS
Maximum number of connected HTTP clients.
std::function< void(HTTPRequest *req, const std::string &)> HTTPRequestHandler
Handler for requests to a certain HTTP path.
constexpr int DEFAULT_HTTP_SERVER_TIMEOUT
constexpr int DEFAULT_HTTP_THREADS
The default value for -rpcthreads.
constexpr int DEFAULT_HTTP_WORKQUEUE
The default value for -rpcworkqueue.
CClientUIInterface uiInterface
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...
#define LogDebug(category,...)
is a home for simple string functions returning descriptive messages that are used in RPC and GUI int...
constexpr uint64_t MAX_BODY_SIZE
Maximum size of an HTTP request body.
constexpr size_t MIN_REQUEST_LINE_LENGTH
Shortest valid request line, used by libevent in evhttp_parse_request_line()
constexpr size_t MAX_HEADERS_SIZE
Maximum size of each headers line in an HTTP request, also the maximum size of all headers total.
bilingual_str InvalidPortErrMsg(const std::string &optname, const std::string &invalid_value)
std::string_view TrimStringView(std::string_view str, std::string_view pattern=" \f\n\r\t\v")
void TraceThread(std::string_view thread_name, std::function< void()> thread_func)
A wrapper for do-something-once thread functions.
std::string ToString(const T &t)
Locale-independent version of std::to_string.
std::string TrimString(std::string_view str, std::string_view pattern=" \f\n\r\t\v")
std::vector< T > Split(const std::span< const char > &sp, std::string_view separators, bool include_sep=false)
Split a string on any char found in separators, returning a vector.
CSubNet LookupSubNet(const std::string &subnet_str)
Parse and resolve a specified subnet string into the appropriate internal representation.
std::vector< CNetAddr > LookupHost(const std::string &name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
Resolve a host string to its corresponding network addresses.
std::vector< CService > Lookup(const std::string &name, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function)
Resolve a service string to its corresponding service.
std::function< std::unique_ptr< Sock >(int, int, int)> CreateSock
Socket factory.
bool(* handler)(const std::any &context, HTTPRequest *req, const std::string &strReq)
std::string_view HTTPStatusReasonString(HTTPStatusCode code)
Mapping of HTTP status codes to short string explanation.
HTTPStatusCode
HTTP status codes.
@ HTTP_SERVICE_UNAVAILABLE
@ HTTP_INTERNAL_SERVER_ERROR
std::string NetworkErrorString(int err)
Return readable error string for a network error code.
bool IOErrorIsPermanent(int err)
HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler)
HTTPRequestHandler handler
std::string StringifyHeaders() const
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.
static time_point now() noexcept
Return current system time or mocked time, if set.
Auxiliary requested/occurred events to wait for in WaitMany().
Thrown when a request body exceeds MAX_BODY_SIZE (or will exceed, in chunked transfer) so the server ...
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
constexpr std::string_view SubmitErrorString(const ThreadPool::SubmitError err) noexcept
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
std::string UrlDecode(std::string_view url_encoded)
bool CaseInsensitiveEqual(std::string_view s1, std::string_view s2)
Locale-independent, ASCII-only comparator.
bool SplitHostPort(std::string_view in, uint16_t &portOut, std::string &hostOut)
Splits socket address string into host string and port value.
std::string ToLower(std::string_view str)
Returns the lowercase equivalent of the given string.
std::string FormatRFC1123DateTime(int64_t time)
RFC1123 formatting https://www.rfc-editor.org/rfc/rfc1123#section-5.2.14 Used in HTTP/1....