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")) {
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());
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);
243 LogDebug(
BCLog::HTTP,
"Registering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch);
245 pathHandlers.emplace_back(prefix, exactMatch, handler);
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)
258 LogDebug(
BCLog::HTTP,
"Unregistering HTTP handler for %s (exactmatch %d)\n", prefix, 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");
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");
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;
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") {
601 if (std::shared_ptr client{
m_client.lock()}) {
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)};
740 "Cannot set SO_REUSEADDR on %s listen socket: %s, continuing anyway",
752 "Cannot set IPV6_V6ONLY on %s listen socket: %s, continuing anyway",
758 int prot_level{PROTECTION_LEVEL_UNRESTRICTED};
759 if (sock->SetSockOpt(IPPROTO_IPV6,
760 IPV6_PROTECTION_LEVEL,
764 "Cannot set IPV6_PROTECTION_LEVEL on %s listen socket: %s, continuing anyway",
791 m_listen.emplace_back(std::move(sock));
823 Assume(std::ranges::any_of(
m_listen, [&](
const auto& sock) {
return sock.get() == &listen_sock; }));
825 sockaddr_storage storage;
826 socklen_t len{
sizeof(storage)};
827 auto sa =
reinterpret_cast<sockaddr*
>(&storage);
829 auto sock{listen_sock.
Accept(sa, &len)};
835 "Cannot accept new connection: %s",
844 "Unknown socket family");
849 LogDebug(
BCLog::HTTP,
"Connection from %s rejected: Client network is not allowed HTTP access\n",
860 return m_next_id.fetch_add(1, std::memory_order_relaxed);
865 if (!sock->IsSelectable()) {
867 "connection from %s dropped: non-selectable socket",
881 m_connected.push_back(std::make_shared<HTTPRemoteClient>(
id, addr, std::move(sock)));
886 "HTTP Connection accepted from %s (id=%llu)",
901 const std::shared_ptr<HTTPRemoteClient>& client{it->second};
911 if (!client->MaybeSendBytesFromBuffer()) {
916 if (recv_ready || err_ready) {
926 m_request_dispatcher(std::move(
request));
944 "Permanent read error from %s (id=%llu): %s",
950 }
else if (nrecv == 0) {
953 "Received EOF from %s (id=%llu)",
973 "Received %d bytes from %s (id=%llu): total=%llu buffered=%zu",
989 const auto it = events_per_sock.find(sock);
990 if (it != events_per_sock.end() && it->second.occurred &
Sock::RecvEvent) {
997 if (!sock_accepted)
break;
1013 for (
const auto& sock :
m_listen) {
1020 std::shared_ptr<Sock> sock{http_client->GetSock()};
1044 if (http_client->ReadyToSend()) {
1046 }
else if (http_client->GetRequest() !=
nullptr || http_client->ReceiveBufferEmpty()) {
1055 return io_readiness;
1067 if (io_readiness.events_per_sock.empty() ||
1069 !io_readiness.events_per_sock.begin()->first->WaitMany(
SELECT_TIMEOUT,
1070 io_readiness.events_per_sock)) {
1090 if (client->m_req_busy)
return nullptr;
1092 if (!client->m_req) {
1093 client->m_req = std::make_unique<HTTPRequest>(client);
1098 client->ReadRequest(*client->m_req);
1102 "HTTP request body too large from client %s (id=%llu): %s",
1108 client->m_disconnect =
true;
1110 }
catch (
const std::runtime_error& e) {
1113 "Error reading HTTP request from client %s (id=%llu): %s",
1120 client->m_disconnect =
true;
1125 if (client->m_req->GetState() == HTTPRequest::State::Complete) {
1132 client->m_send_mutex,
1133 return client->m_send_buffer.size();)};
1137 "Received a %s request for %s from %s (id=%llu)",
1139 client->m_req->GetURI(),
1143 client->m_req_busy =
true;
1144 return std::move(client->m_req);
1155 return client->MaybeDisconnect(now,
1173 const bool is_idle{rpcservertimeout.count() > 0 &&
1182 "HTTP client idle timeout %s (id=%llu)",
1189 if (disconnect_all) {
1207 "Disconnecting HTTP client %s (id=%llu)",
1217 LogWarning(
"Force-disconnecting %d HTTP client(s) that did not disconnect gracefully",
m_connected.size());
1230 case HTTPRequest::State::Init:
1235 case HTTPRequest::State::NeedsHeaders:
1240 case HTTPRequest::State::NeedsBody:
1245 case HTTPRequest::State::Complete:
1248 case HTTPRequest::State::Error:
1269 if (!m_send_buffer.empty()) {
1284 bytes_sent = m_sock->Send(m_send_buffer.data(),
1285 m_send_buffer.size(),
1289 if (bytes_sent < 0) {
1294 m_send_ready =
true;
1301 "Error sending HTTP response data to client %s (id=%llu): %s",
1305 m_send_ready =
false;
1314 Assume(
static_cast<size_t>(bytes_sent) <= m_send_buffer.size());
1315 m_send_buffer.erase(m_send_buffer.begin(),
1316 m_send_buffer.begin() + bytes_sent);
1320 "Sent %d bytes to client %s (id=%llu)",
1328 if (m_send_buffer.empty()) {
1329 m_send_ready =
false;
1340 m_send_ready =
true;
1364 std::vector<std::pair<std::string, uint16_t>> endpoints{
GetBindAddresses()};
1365 bool bind_success{
false};
1366 for (
const auto& [address_string, port] : endpoints) {
1367 LogInfo(
"Binding RPC on address %s port %i", address_string, port);
1368 const std::optional<CService> addr{
Lookup(address_string, port,
false)};
1370 if (addr->IsBindAny()) {
1371 LogWarning(
"The RPC server is not safe to expose to untrusted networks such as the public internet");
1373 auto result{
g_http_server->BindAndStartListening(addr.value())};
1375 LogWarning(
"Binding RPC on address %s failed: %s", addr->ToStringAddrPort(), result.error());
1377 bind_success =
true;
1380 LogWarning(
"Could not bind RPC on address %s port %i: Address lookup failed.", address_string, port);
1384 if (!bind_success) {
1385 LogError(
"Unable to bind any endpoint for RPC server");
1400 LogInfo(
"Starting HTTP server with %d worker threads", rpcThreads);
1435 LogWarning(
"Timeout waiting for HTTP clients to disconnect gracefully, continuing shutdown");
1438 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
uint64_t m_total_bytes_received
Running total of bytes read from this client's socket.
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.
static std::unique_ptr< HTTPRequest > TryReadRequest(const std::shared_ptr< HTTPRemoteClient > &client) EXCLUSIVE_LOCKS_REQUIRED(!client -> m_send_mutex)
Try to read an HTTPRequest from a client's receive buffer.
bool MaybeDisconnect(std::chrono::time_point< SteadyClock > now, std::chrono::seconds rpcservertimeout, bool disconnect_all)
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
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
void Receive() EXCLUSIVE_LOCKS_REQUIRED(!m_sock_mutex)
std::atomic_bool m_keep_alive
std::atomic_bool m_req_busy
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
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 GlobalMutex g_httppathhandlers_mutex
Handlers for (sub)paths.
bilingual_str InvalidPortErrMsg(const std::string &optname, const std::string &invalid_value)
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.
std::optional< std::string > GetQueryParameterFromUri(std::string_view uri, std::string_view key)
LineReader reader("GET / HTTP/1.0\r\nHost: ", MAX_HEADERS_SIZE)
const std::string request
CClientUIInterface uiInterface
#define LogDebug(category,...)
constexpr uint64_t MAX_BODY_SIZE
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
bilingual_str InvalidPortErrMsg(const std::string &optname, const std::string &invalid_value)
std::vector< T > Split(std::span< const char > sp LIFETIMEBOUND, std::string_view separators, bool include_sep=false)
Split a string on any char found in separators, returning a vector.
void TraceThread(std::string_view thread_name, std::function< void()> thread_func)
A wrapper for do-something-once thread functions.
std::string_view TrimStringView(std::string_view str LIFETIMEBOUND, std::string_view pattern=" \f\n\r\t\v")
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")
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.
std::string_view HTTPStatusReasonString(HTTPStatusCode code)
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)
std::optional< T > ToIntegral(std::string_view str, size_t base=10)
Convert string to integral type T.
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().
#define WITH_LOCK(cs, code)
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....
constexpr auto TicksSinceEpoch(Timepoint t)
T Now()
Return the current time point cast to the given precision.