Bitcoin Core 32.99.0
P2P Digital Currency
httpserver.cpp
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#include <bitcoin-build-config.h> // IWYU pragma: keep
6
7#include <httpserver.h>
8
9#include <chainparamsbase.h>
10#include <common/args.h>
11#include <common/messages.h>
12#include <common/url.h>
13#include <compat/compat.h>
14#include <logging.h>
15#include <netbase.h>
16#include <node/interface_ui.h>
17#include <rpc/protocol.h>
18#include <span.h>
19#include <sync.h>
20#include <util/check.h>
22#include <util/sock.h>
23#include <util/strencodings.h>
24#include <util/thread.h>
25#include <util/threadnames.h>
26#include <util/threadpool.h>
27#include <util/time.h>
28#include <util/translation.h>
29
30#include <condition_variable>
31#include <cstdio>
32#include <cstdlib>
33#include <memory>
34#include <optional>
35#include <span>
36#include <string>
37#include <string_view>
38#include <thread>
39#include <unordered_map>
40#include <vector>
41
42#include <sys/types.h>
43#include <sys/stat.h>
44
47static constexpr auto SELECT_TIMEOUT{50ms};
48
50static constexpr int SOCKET_OPTION_TRUE{1};
51
54using namespace bitcoin_http;
55
57{
58 HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler):
59 prefix(_prefix), exactMatch(_exactMatch), handler(_handler)
60 {
61 }
62 std::string prefix;
65};
66
69static std::unique_ptr<HTTPServer> g_http_server{nullptr};
72static std::vector<HTTPPathHandler> pathHandlers GUARDED_BY(g_httppathhandlers_mutex);
76static int g_max_queue_depth{100};
77
79bool HTTPServer::ClientAllowed(const CNetAddr& netaddr) const
80{
81 if (!netaddr.IsValid())
82 return false;
83 for(const CSubNet& subnet : m_allow_subnets)
84 if (subnet.Match(netaddr))
85 return true;
86 return false;
87}
88
91{
92 // Must be run before StartSocketThreads() because ThreadSocketHandler()
93 // will check m_allow_subnets from the I/O thread.
95
96 m_allow_subnets.clear();
97 m_allow_subnets.emplace_back(LookupHost("127.0.0.1", false).value(), 8); // always allow IPv4 local subnet
98 m_allow_subnets.emplace_back(LookupHost("::1", false).value()); // always allow IPv6 localhost
99 for (const std::string& strAllow : gArgs.GetArgs("-rpcallowip")) {
100 const CSubNet subnet{LookupSubNet(strAllow)};
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)),
105 return false;
106 }
107 m_allow_subnets.push_back(subnet);
108 }
109 std::string strAllowed;
110 for (const CSubNet& subnet : m_allow_subnets)
111 strAllowed += subnet.ToString() + " ";
112 LogDebug(BCLog::HTTP, "Allowing HTTP connections from: %s\n", strAllowed);
113 return true;
114}
115
118{
119 switch (m) {
120 using enum HTTPRequestMethod;
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";
126 } // no default case, so the compiler can warn about missing cases
127 assert(false);
128}
129
130static void WriteNoStoreErrorReply(HTTPRequest& req, HTTPStatusCode status, std::string_view reply = {})
131{
132 req.WriteHeader("Cache-Control", "no-store");
133 req.WriteReply(status, reply);
134}
135
136static void MaybeDispatchRequestToWorker(std::shared_ptr<HTTPRequest> hreq)
137{
138 // Early reject unknown HTTP methods
139 if (hreq->GetRequestMethod() == HTTPRequestMethod::UNKNOWN) {
140 LogDebug(BCLog::HTTP, "HTTP request from %s rejected: Unknown HTTP request method\n",
141 hreq->GetPeer().ToStringAddrPort());
143 return;
144 }
145
146 // Find registered handler for prefix
147 std::string strURI = hreq->GetURI();
148 std::string path;
150 std::vector<HTTPPathHandler>::const_iterator i = pathHandlers.begin();
151 std::vector<HTTPPathHandler>::const_iterator iend = pathHandlers.end();
152 for (; i != iend; ++i) {
153 bool match = false;
154 if (i->exactMatch)
155 match = (strURI == i->prefix);
156 else
157 match = strURI.starts_with(i->prefix);
158 if (match) {
159 path = strURI.substr(i->prefix.size());
160 break;
161 }
162 }
163
164 // Dispatch to worker thread
165 if (i != iend) {
166 if (static_cast<int>(g_threadpool_http.WorkQueueSize()) >= g_max_queue_depth) {
167 LogWarning("Request rejected because http work queue depth exceeded, it can be increased with the -rpcworkqueue= setting");
168 WriteNoStoreErrorReply(*hreq, HTTP_SERVICE_UNAVAILABLE, "Work queue depth exceeded");
169 return;
170 }
171
172 auto item = [req = hreq, in_path = std::move(path), fn = i->handler]() {
173 std::string err_msg;
174 try {
175 fn(req.get(), in_path);
176 return;
177 } catch (const std::exception& e) {
178 LogWarning("Unexpected error while processing request for '%s'. Error msg: '%s'", req->GetURI(), e.what());
179 err_msg = e.what();
180 } catch (...) {
181 LogWarning("Unknown error while processing request for '%s'", req->GetURI());
182 err_msg = "unknown error";
183 }
184 // Reply so the client doesn't hang waiting for the response.
185 req->WriteHeader("Connection", "close");
186 // TODO: Implement specific error formatting for the REST and JSON-RPC servers responses.
188 };
189
190 if (auto res = g_threadpool_http.Submit(std::move(item)); !res.has_value()) {
191 Assume(hreq.use_count() == 1); // ensure request will be deleted
192 // Both SubmitError::Inactive and SubmitError::Interrupted mean shutdown
193 LogWarning("HTTP request rejected during server shutdown: '%s'", SubmitErrorString(res.error()));
194 WriteNoStoreErrorReply(*hreq, HTTP_SERVICE_UNAVAILABLE, "Request rejected during server shutdown");
195 return;
196 }
197 } else {
199 }
200}
201
202static void RejectRequest(std::unique_ptr<HTTPRequest> hreq)
203{
204 LogDebug(BCLog::HTTP, "Rejecting request while shutting down");
206}
207
208static std::vector<std::pair<std::string, uint16_t>> GetBindAddresses()
209{
210 uint16_t http_port{static_cast<uint16_t>(gArgs.GetIntArg("-rpcport", BaseParams().RPCPort()))};
211 std::vector<std::pair<std::string, uint16_t>> endpoints;
212
213 // Determine what addresses to bind to
214 // To prevent misconfiguration and accidental exposure of the RPC
215 // interface, require -rpcallowip and -rpcbind to both be specified
216 // together. If either is missing, ignore both values, bind to localhost
217 // instead, and log warnings.
218 if (gArgs.GetArgs("-rpcallowip").empty() || gArgs.GetArgs("-rpcbind").empty()) { // Default to loopback if not allowing external IPs
219 endpoints.emplace_back("::1", http_port);
220 endpoints.emplace_back("127.0.0.1", http_port);
221 if (!gArgs.GetArgs("-rpcallowip").empty()) {
222 LogWarning("Option -rpcallowip was specified without -rpcbind; this doesn't usually make sense");
223 }
224 if (!gArgs.GetArgs("-rpcbind").empty()) {
225 LogWarning("Option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect");
226 }
227 } else { // Specific bind addresses
228 for (const std::string& strRPCBind : gArgs.GetArgs("-rpcbind")) {
229 uint16_t port{http_port};
230 std::string host;
231 if (!SplitHostPort(strRPCBind, port, host)) {
232 LogError("%s\n", InvalidPortErrMsg("-rpcbind", strRPCBind).original);
233 return {}; // empty
234 }
235 endpoints.emplace_back(host, port);
236 }
237 }
238 return endpoints;
239}
240
241void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
242{
243 LogDebug(BCLog::HTTP, "Registering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch);
245 pathHandlers.emplace_back(prefix, exactMatch, handler);
246}
247
248void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
249{
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)
255 break;
256 if (i != iend)
257 {
258 LogDebug(BCLog::HTTP, "Unregistering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch);
259 pathHandlers.erase(i);
260 }
261}
262
263using util::Split;
264
265std::optional<std::string> HTTPHeaders::FindFirst(const std::string_view key) const
266{
267 for (const auto& item : m_headers) {
268 if (CaseInsensitiveEqual(key, item.first)) {
269 return item.second;
270 }
271 }
272 return std::nullopt;
273}
274
275std::vector<std::string_view> HTTPHeaders::FindAll(const std::string_view key) const
276{
277 std::vector<std::string_view> ret;
278 for (const auto& item : m_headers) {
279 if (CaseInsensitiveEqual(key, item.first)) {
280 ret.push_back(item.second);
281 }
282 }
283 return ret;
284}
285
286void HTTPHeaders::Write(std::string&& key, std::string&& value)
287{
288 m_headers.emplace_back(std::move(key), std::move(value));
289}
290
291void HTTPHeaders::RemoveAll(std::string_view key)
292{
293 auto moved = std::ranges::remove_if(m_headers, [key] (auto& pair) {
294 return CaseInsensitiveEqual(key, pair.first);
295 });
296 m_headers.erase(moved.begin(), moved.end());
297}
298
300{
301 // Headers https://httpwg.org/specs/rfc9110.html#rfc.section.6.3
302 // A sequence of Field Lines https://httpwg.org/specs/rfc9110.html#rfc.section.5.2
303 size_t start{reader.Consumed()};
304 while (auto maybe_line = reader.ReadLine()) {
305 if (reader.Consumed() - start + m_consumed > MAX_HEADERS_SIZE) throw std::runtime_error("HTTP headers exceed size limit");
306
307 const std::string_view& line = *maybe_line;
308
309 // An empty line indicates end of the headers section https://www.rfc-editor.org/rfc/rfc2616#section-4
310 if (line.empty()) {
311 // Ensure all headers are accounted for in case there is a chunked trailer
312 m_consumed += reader.Consumed() - start;
313 return true;
314 }
315
316 // "Field values containing CR, LF, or NUL characters are invalid and dangerous"
317 // https://httpwg.org/specs/rfc9110.html#rfc.section.5.5
318 // A sender MUST NOT generate a bare CR (a CR character not immediately followed by LF)
319 // within any protocol elements other than the content.
320 // A recipient of such a bare CR MUST consider that element to be invalid...
321 // https://httpwg.org/specs/rfc9112.html#rfc.section.2.2
322 if (line.find_first_of("\r\n\0", 0, 3) != std::string_view::npos) throw std::runtime_error("Header contains invalid character");
323
324 // Header line must have at least one ":"
325 // keys are not allowed to have delimiters like ":" but values are
326 // https://httpwg.org/specs/rfc9110.html#rfc.section.5.6.2
327 const size_t pos{line.find(':')};
328 if (pos == std::string_view::npos) throw std::runtime_error("HTTP header missing colon (:)");
329
330 // Whitespace is strictly not allowed in the field-name (key)
331 // https://www.rfc-editor.org/rfc/rfc9110.html#section-5.6.2
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");
334 // Whitespace is optional in the value and can be trimmed
335 std::string value = util::TrimString(std::string_view(line).substr(pos + 1));
336
337 // Header keys are Field Names: https://httpwg.org/specs/rfc9110.html#fields.names
338 // which consist of "tokens": https://httpwg.org/specs/rfc9110.html#rfc.section.5.6.2
339 // that can not be empty.
340 if (key.empty()) throw std::runtime_error("Empty HTTP header name");
341
342 if (write) {
343 Write(std::string(key), std::move(value));
344 }
345 }
346
347 // We have not received all the request headers yet.
348 // Keep track of how much data we have already consumed to enforce
349 // the total limit over multiple read operations.
350 m_consumed += reader.Consumed() - start;
351
352 return false;
353}
354
355std::string HTTPHeaders::Stringify() const
356{
357 std::string out;
358 for (const auto& [key, value] : m_headers) {
359 out += key + ": " + value + "\r\n";
360 }
361
362 // Headers are terminated by an empty line
363 out += "\r\n";
364
365 return out;
366}
367
369{
370 return strprintf("HTTP/%d.%d %d %s\r\n%s",
373 status,
376}
377
379{
380 auto maybe_line = reader.ReadLine();
381 if (!maybe_line) return false;
382 const std::string_view& request_line = *maybe_line;
383
384 // Request Line aka Control Data https://httpwg.org/specs/rfc9110.html#rfc.section.6.2
385 // Three words separated by spaces, terminated by \n or \r\n
386 if (request_line.length() < MIN_REQUEST_LINE_LENGTH) throw std::runtime_error("HTTP request line too short");
387
388 // NUL is not a valid tchar and would silently truncate
389 // C-string-based parsers rather than being rejected as malformed.
390 // tchar: https://www.rfc-editor.org/info/rfc7230/#section-3.2.6
391 if (request_line.find('\0') != std::string_view::npos) throw std::runtime_error("Invalid request line contains NUL");
392
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");
395
396 if (parts[0] == "GET") {
398 } else if (parts[0] == "POST") {
400 } else if (parts[0] == "HEAD") {
402 } else if (parts[0] == "PUT") {
404 } else {
406 }
407
408 m_target = parts[1];
409
410 if (parts[2].rfind("HTTP/") != 0) throw std::runtime_error("HTTP request line malformed");
411
412 // Version is exactly two decimal digits separated by a decimal point
413 // https://httpwg.org/specs/rfc9110.html#rfc.section.2.5
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");
420 m_version.major = major.value();
421 m_version.minor = minor.value();
422
423 return true;
424}
425
427{
428 return m_headers.Read(reader);
429}
430
432{
433 // https://httpwg.org/specs/rfc9112.html#message.body
434 auto transfer_encoding_header = m_headers.FindFirst("Transfer-Encoding");
435 if (transfer_encoding_header && ToLower(transfer_encoding_header.value()) == "chunked") {
436 // Transfer-Encoding: https://datatracker.ietf.org/doc/html/rfc7230.html#section-3.3.1
437 // Chunked Transfer Coding: https://datatracker.ietf.org/doc/html/rfc7230.html#section-4.1
438 // see evhttp_handle_chunked_read() in libevent http.c
439 while (reader.Remaining() > 0) {
440 if (!m_chunk_size) {
441 auto maybe_chunk_size = reader.ReadLine();
442 if (!maybe_chunk_size) return false;
443
444 // Allow (but ignore) Chunk Extensions
445 // See https://www.rfc-editor.org/rfc/rfc9112.html#name-chunk-extensions
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);
450 }
451
452 m_chunk_size = ToIntegral<uint64_t>(util::TrimStringView(chunk_size_noext), /*base=*/16);
453 if (!m_chunk_size) throw std::runtime_error("Cannot parse chunk length value");
454
455 if ((m_body.size() > MAX_BODY_SIZE) ||
456 (*m_chunk_size > MAX_BODY_SIZE - m_body.size()))
457 throw ContentTooLargeError("Chunk will exceed max body size");
458 }
459
460 // We either just read the chunk size, or we have it saved
461 // from a prior I/O loop iteration
463
464 // Last chunk has size 0
465 if (*m_chunk_size == 0) {
466 // Validate Chunked Trailer section, which is used for
467 // additional headers sent at the end of the message.
468 // Data consumed here is counted towards MAX_HEADERS_SIZE
469 // along with the headers we read in the beginning of the request.
470 // At this time we ignore and drop these data after validating.
471 // See https://httpwg.org/specs/rfc9112.html#rfc.section.7.1.2
472 return m_headers.Read(reader, /*write=*/false);
473 }
474
475 // We have not read the entire chunk from the buffer yet
476 if (m_chunk_read < *m_chunk_size) {
477 // Get what we can from the buffer
478 const uint64_t chunk_need{*m_chunk_size - m_chunk_read};
479 const uint64_t buffer_has{std::min(chunk_need, static_cast<uint64_t>(reader.Remaining()))};
480
481 // Pack [partial] chunk onto body and update state
482 m_body += reader.ReadLength(buffer_has);
483 m_chunk_read += buffer_has;
484 }
485
486 // Even though every chunk size is explicitly declared,
487 // they are still terminated by a CRLF we don't need,
488 // just consume it here.
489 if (m_chunk_read == *m_chunk_size) {
490 auto crlf = reader.ReadLine();
491 if (!crlf) {
492 // CRLF not found before end of buffer: it has not been received by our socket yet.
493 return false;
494 }
495 // CRLF was found but there was unexpected data after the chunk_sized chunk
496 if (!crlf.value().empty()) throw std::runtime_error("Improperly terminated chunk");
497
498 // Clear state for next chunk
499 m_chunk_size.reset();
500 m_chunk_read = 0;
501 }
502 }
503
504 // We read all the chunks but never got the last chunk, wait for client to send more
505 return false;
506 } else {
507 // No Content-length or Transfer-Encoding header means no body, see libevent evhttp_get_body()
508 auto content_length_values{m_headers.FindAll("Content-Length")};
509 if (content_length_values.empty()) return true;
510
511 // Duplicate Content-Length headers are allowed only if they all have the same value
512 // https://www.rfc-editor.org/rfc/rfc7230#section-3.3.3
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");
516 }
517
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");
520
521 if (*content_length > MAX_BODY_SIZE) throw ContentTooLargeError("Max body size exceeded");
522
523 // A large body may arrive over multiple I/O loop iterations. Copy
524 // whatever the buffer has now; m_body's size tracks our progress.
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()))};
527
528 // Pack [partial] body on and update state
529 m_body += reader.ReadLength(buffer_has);
530
531 return m_body.size() == *content_length;
532 }
533}
534
535void HTTPRequest::WriteReply(HTTPStatusCode status, std::span<const std::byte> reply_body)
536{
537 HTTPResponse res;
538
539 // Some response headers are determined in advance and stored in the request
540 res.headers = std::move(m_response_headers);
541
542 // Response version matches request version
543 res.version = m_version;
544
545 // Add response code
546 res.status = status;
547
548 // See libevent evhttp_response_needs_body()
549 // Response headers are different if no body is needed
550 bool needs_body{status != HTTP_NO_CONTENT && (status < 100 || status >= 200)};
551 bool needs_content_length{false};
552
553 bool keep_alive{false};
554
555 // See libevent evhttp_make_header_response()
556 // Expected response headers depend on protocol version
557 if (m_version.major == 1) {
558 // HTTP/1.0
559 if (m_version.minor == 0) {
560 auto connection_header{m_headers.FindFirst("Connection")};
561 if (connection_header && ToLower(connection_header.value()) == "keep-alive") {
562 res.headers.Write("Connection", "keep-alive");
563 keep_alive = true;
564 // HTTP/1.0 connections are closed by default so EOF is sufficient
565 // to indicate end of the body. Adding Content-Length a special case.
566 if (needs_body) needs_content_length = true;
567 }
568 }
569
570 // HTTP/1.1
571 if (m_version.minor >= 1) {
572 const int64_t now_seconds{TicksSinceEpoch<std::chrono::seconds>(NodeClock::now())};
573 res.headers.Write("Date", FormatRFC1123DateTime(now_seconds));
574
575 // HTTP/1.1 connections are kept alive by default and always require Content-Length.
576 if (needs_body) needs_content_length = true;
577
578 // Default for HTTP/1.1
579 keep_alive = true;
580 }
581 }
582
583 if (needs_content_length) {
584 res.headers.Write("Content-Length", util::ToString(reply_body.size()));
585 }
586
587 if (needs_body && !res.headers.FindFirst("Content-Type")) {
588 // Default type from libevent evhttp_new_object()
589 res.headers.Write("Content-Type", "text/html; charset=ISO-8859-1");
590 }
591
592 auto connection_header{m_headers.FindFirst("Connection")};
593 if (connection_header && ToLower(connection_header.value()) == "close") {
594 // Might not exist already but we need to replace it, not append to it
595 res.headers.RemoveAll("Connection");
596
597 res.headers.Write("Connection", "close");
598 keep_alive = false;
599 }
600
601 if (std::shared_ptr client{m_client.lock()}) {
602 client->Send(res, reply_body, keep_alive);
603 }
604}
605
606void HTTPRemoteClient::Send(const HTTPResponse& res, std::span<const std::byte> reply_body, bool keep_alive)
607{
608 m_keep_alive = keep_alive;
609
610 // Serialize the response headers
611 const std::string headers{res.StringifyHeaders()};
612 const auto headers_bytes{std::as_bytes(std::span{headers})};
613
614 bool send_buffer_was_empty{false};
615 // Fill the send buffer with the complete serialized response headers + body
616 {
618 send_buffer_was_empty = m_send_buffer.empty();
619 m_send_buffer.insert(m_send_buffer.end(), headers_bytes.begin(), headers_bytes.end());
620
621 // We've been using std::span up until now but it is finally time to copy
622 // data. The original data will go out of scope when WriteReply() returns.
623 // This is analogous to the memcpy() in libevent's evbuffer_add()
624 m_send_buffer.insert(m_send_buffer.end(), reply_body.begin(), reply_body.end());
625
626 // If the buffer already held data, the I/O thread is (or soon will be)
627 // draining it, so flag that there is more data to send. This must happen
628 // while holding m_send_mutex and while the buffer is known non-empty:
629 // setting m_send_ready after releasing the lock would race with the I/O
630 // thread draining the buffer to empty and clearing m_send_ready in
631 // between, leaving m_send_ready set on an empty buffer. The I/O loop would
632 // then only ever poll the socket for writeability, never read the client's
633 // next request, and wedge the connection.
634 if (!send_buffer_was_empty) m_send_ready = true;
635 }
636
637 LogDebug(
639 "HTTPResponse (status code: %d size: %lld) added to send buffer for client %s (id=%llu)",
640 res.status,
641 headers_bytes.size() + reply_body.size(),
642 m_origin,
643 m_id);
644
645 // If the send buffer was empty before we wrote this reply, we can try an
646 // optimistic send akin to CConnman::PushMessage() in which we
647 // push the data directly out the socket to client right now, instead
648 // of waiting for the next iteration of the I/O loop.
649 if (send_buffer_was_empty) {
651 }
652
653 // Signal to the I/O loop that we are ready to handle the next request.
654 m_req_busy = false;
655}
656
658{
659 if (std::shared_ptr c{m_client.lock()}) {
660 return c->GetPeer();
661 } else {
662 return {};
663 }
664}
665
666std::optional<std::string> HTTPRequest::GetQueryParameter(const std::string_view key) const
667{
669}
670
671// See libevent http.c evhttp_parse_query_impl()
672// and https://www.rfc-editor.org/rfc/rfc3986#section-3.4
673std::optional<std::string> GetQueryParameterFromUri(const std::string_view uri, const std::string_view key)
674{
675 // find query in URI
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) {
680 end = uri.length();
681 }
682 const std::string_view query{uri.data() + start + 1, end - start - 1};
683 // find requested parameter in query
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) {
689 return "";
690 } else {
691 return std::string(UrlDecode(param.substr(delim + 1)));
692 }
693 }
694 }
695 return std::nullopt;
696}
697
698std::optional<std::string> HTTPRequest::GetHeader(const std::string_view hdr) const
699{
700 return m_headers.FindFirst(hdr);
701}
702
703void HTTPRequest::WriteHeader(std::string&& hdr, std::string&& value)
704{
705 m_response_headers.Write(std::move(hdr), std::move(value));
706}
707
709{
710 // Create socket for listening for incoming connections
711 sockaddr_storage storage;
712 auto sa = reinterpret_cast<sockaddr*>(&storage);
713 socklen_t len{sizeof(storage)};
714 if (!to.GetSockAddr(sa, &len)) {
715 return util::Unexpected{strprintf("Bind address family for %s not supported", to.ToStringAddrPort())};
716 }
717
718 std::unique_ptr<Sock> sock{CreateSock(to.GetSAFamily(), SOCK_STREAM, IPPROTO_TCP)};
719 if (!sock) {
720 return util::Unexpected{strprintf("Cannot create %s listen socket: %s",
721 to.ToStringAddrPort(),
723 }
724
725#ifdef WIN32
726 // Prevent another application from binding to the same address and port and
727 // intercepting RPC credentials.
728 // SO_REUSEADDR on Windows is non-exclusive so another process could bind to
729 // the same port.
730 if (sock->SetSockOpt(SOL_SOCKET, SO_EXCLUSIVEADDRUSE, &SOCKET_OPTION_TRUE, sizeof(SOCKET_OPTION_TRUE)) == SOCKET_ERROR) {
731 return util::Unexpected{strprintf("Cannot set SO_EXCLUSIVEADDRUSE on %s listen socket: %s",
732 to.ToStringAddrPort(),
734 }
735#else
736 // Allow binding if the port is still in TIME_WAIT state after
737 // the program was closed and restarted.
738 if (sock->SetSockOpt(SOL_SOCKET, SO_REUSEADDR, &SOCKET_OPTION_TRUE, sizeof(SOCKET_OPTION_TRUE)) == SOCKET_ERROR) {
740 "Cannot set SO_REUSEADDR on %s listen socket: %s, continuing anyway",
741 to.ToStringAddrPort(),
743 }
744#endif
745
746 // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
747 // and enable it by default or not. Try to enable it, if possible.
748 if (to.IsIPv6()) {
749#ifdef IPV6_V6ONLY
750 if (sock->SetSockOpt(IPPROTO_IPV6, IPV6_V6ONLY, &SOCKET_OPTION_TRUE, sizeof(SOCKET_OPTION_TRUE)) == SOCKET_ERROR) {
752 "Cannot set IPV6_V6ONLY on %s listen socket: %s, continuing anyway",
753 to.ToStringAddrPort(),
755 }
756#endif
757#ifdef WIN32
758 int prot_level{PROTECTION_LEVEL_UNRESTRICTED};
759 if (sock->SetSockOpt(IPPROTO_IPV6,
760 IPV6_PROTECTION_LEVEL,
761 &prot_level,
762 sizeof(prot_level)) == SOCKET_ERROR) {
764 "Cannot set IPV6_PROTECTION_LEVEL on %s listen socket: %s, continuing anyway",
765 to.ToStringAddrPort(),
767 }
768#endif
769 }
770
771 if (sock->Bind(sa, len) == SOCKET_ERROR) {
772 const int err{WSAGetLastError()};
773 if (err == WSAEADDRINUSE) {
774 return util::Unexpected{strprintf("Unable to bind to %s on this computer. %s is probably already running.",
775 to.ToStringAddrPort(),
776 CLIENT_NAME)};
777 } else {
778 return util::Unexpected{strprintf("Unable to bind to %s on this computer (bind returned error %s)",
779 to.ToStringAddrPort(),
780 NetworkErrorString(err))};
781 }
782 }
783
784 // Listen for incoming connections
785 if (sock->Listen(SOMAXCONN) == SOCKET_ERROR) {
786 return util::Unexpected{strprintf("Cannot listen on %s: %s",
787 to.ToStringAddrPort(),
789 }
790
791 m_listen.emplace_back(std::move(sock));
792
793 return {};
794}
795
797{
798 m_listen.clear();
799}
800
802{
803 // The socket handler reads m_allow_subnets in ClientAllowed(). InitHTTPAllowList()
804 // must have populated it first; localhost entries are always added, so an empty
805 // list means it was never called and every connection is rejected.
806 Assume(!m_allow_subnets.empty());
807
809 "http",
810 [this] { ThreadSocketHandler(); });
811}
812
814{
815 if (m_thread_socket_handler.joinable()) {
817 }
818}
819
820std::unique_ptr<Sock> HTTPServer::AcceptConnection(const Sock& listen_sock, CService& addr)
821{
822 // Make sure we only operate on our own listening sockets
823 Assume(std::ranges::any_of(m_listen, [&](const auto& sock) { return sock.get() == &listen_sock; }));
824
825 sockaddr_storage storage;
826 socklen_t len{sizeof(storage)};
827 auto sa = reinterpret_cast<sockaddr*>(&storage);
828
829 auto sock{listen_sock.Accept(sa, &len)};
830
831 if (!sock) {
832 const int err{WSAGetLastError()};
833 if (err != WSAEWOULDBLOCK) {
835 "Cannot accept new connection: %s",
836 NetworkErrorString(err));
837 }
838 return {};
839 }
840
841 // The OS handed us a valid socket but we can't determine its source address.
842 if (!addr.SetSockAddr(sa, len)) {
844 "Unknown socket family");
845 }
846
847 // Early address-based allow check
848 if (!ClientAllowed(addr)) {
849 LogDebug(BCLog::HTTP, "Connection from %s rejected: Client network is not allowed HTTP access\n",
850 addr.ToStringAddrPort());
851 // Socket destroyed, connection aborted
852 return {};
853 }
854
855 return sock;
856}
857
859{
860 return m_next_id.fetch_add(1, std::memory_order_relaxed);
861}
862
863void HTTPServer::NewSockAccepted(std::unique_ptr<Sock>&& sock, const CService& addr)
864{
865 if (!sock->IsSelectable()) {
867 "connection from %s dropped: non-selectable socket",
868 addr.ToStringAddrPort());
869 return;
870 }
871
872 // According to the internet TCP_NODELAY is not carried into accepted sockets
873 // on all platforms. Set it again here just to be sure.
874 if (sock->SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &SOCKET_OPTION_TRUE, sizeof(SOCKET_OPTION_TRUE)) == SOCKET_ERROR) {
875 LogDebug(BCLog::HTTP, "connection from %s: unable to set TCP_NODELAY, continuing anyway",
876 addr.ToStringAddrPort());
877 }
878
879 const Id id{GetNewId()};
880
881 m_connected.push_back(std::make_shared<HTTPRemoteClient>(id, addr, std::move(sock)));
882 // Report back to the main thread
883 m_connected_size.fetch_add(1, std::memory_order_relaxed);
884
886 "HTTP Connection accepted from %s (id=%llu)",
887 addr.ToStringAddrPort(), id);
888}
889
890void HTTPServer::SocketHandlerConnected(const IOReadiness& io_readiness) const
891{
892 for (const auto& [sock, events] : io_readiness.events_per_sock) {
893 if (m_interrupt_net) {
894 return;
895 }
896
897 auto it{io_readiness.httpclients_per_sock.find(sock)};
898 if (it == io_readiness.httpclients_per_sock.end()) {
899 continue;
900 }
901 const std::shared_ptr<HTTPRemoteClient>& client{it->second};
902
903 bool send_ready = events.occurred & Sock::SendEvent;
904 bool recv_ready = events.occurred & Sock::RecvEvent;
905 bool err_ready = events.occurred & Sock::ErrorEvent;
906
907 if (send_ready) {
908 // Try to send as much data as is ready for this client.
909 // If there's an error we can skip the receive phase for this client
910 // because we need to disconnect.
911 if (!client->MaybeSendBytesFromBuffer()) {
912 recv_ready = false;
913 }
914 }
915
916 if (recv_ready || err_ready) {
917 client->Receive();
918 }
919 // Process as much received data as we can.
920 // This executes for every client whether or not reading or writing
921 // took place because it also (might) parse a request we have already
922 // received and pass it to a worker thread.
923 if (std::unique_ptr<HTTPRequest> request{HTTPRemoteClient::TryReadRequest(client)})
924 {
926 m_request_dispatcher(std::move(request));
927 }
928 }
929}
930
932{
933 char buf[0x10000]; // typical socket buffer is 8K-64K
934
935 const ssize_t nrecv{WITH_LOCK(
937 return m_sock->Recv(buf, sizeof(buf), MSG_DONTWAIT);)};
938
939 if (nrecv < 0) {
940 const int err = WSAGetLastError();
941 if (IOErrorIsPermanent(err)) {
942 LogDebug(
944 "Permanent read error from %s (id=%llu): %s",
945 m_origin,
946 m_id,
947 NetworkErrorString(err));
948 m_disconnect = true;
949 }
950 } else if (nrecv == 0) {
951 LogDebug(
953 "Received EOF from %s (id=%llu)",
954 m_origin,
955 m_id);
956 m_disconnect = true;
957 } else {
958 // Reset idle timeout
959 m_idle_since = Now<SteadySeconds>();
960
961 // Prevent disconnect until all requests are completely handled.
962 m_connection_busy = true;
963
964 // Copy data from socket buffer to client receive buffer
965 m_recv_buffer.insert(
966 m_recv_buffer.end(),
967 buf,
968 buf + nrecv);
969 }
970}
971
973{
974 if (m_stop_accepting) return;
975 for (const auto& sock : m_listen) {
976 if (m_interrupt_net) {
977 return;
978 }
979 const auto it = events_per_sock.find(sock);
980 if (it != events_per_sock.end() && it->second.occurred & Sock::RecvEvent) {
981 // Drain all pending connections from this socket up to the limit.
982 // Stop early if the kernel queue is empty (AcceptConnection returns null)
983 // or if accepting the last connection brought us to the limit.
984 while (GetConnectionsCount() < static_cast<size_t>(m_rpcmaxconnections)) {
985 CService addr_accepted;
986 auto sock_accepted{AcceptConnection(*sock, addr_accepted)};
987 if (!sock_accepted) break;
988 NewSockAccepted(std::move(sock_accepted), addr_accepted);
989 }
990 }
991 }
992}
993
995{
996 IOReadiness io_readiness;
997
998 // If the server is already handling its max connected clients count,
999 // don't bother checking the listening sockets for new inbound connections.
1000 // Leave them in the kernel's queue until space in the application opens
1001 // up (or the client times out on its own).
1002 if (GetConnectionsCount() < static_cast<size_t>(m_rpcmaxconnections)) {
1003 for (const auto& sock : m_listen) {
1004 io_readiness.events_per_sock.emplace(sock, Sock::Events{Sock::RecvEvent});
1005 }
1006 }
1007
1008 for (const auto& http_client : m_connected) {
1009 // Safely copy the shared pointer to the socket
1010 std::shared_ptr<Sock> sock{http_client->GetSock()};
1011
1012 // Event choice:
1013 // 1. ReadyToSend() (m_send_ready set) -> Send
1014 // m_send_ready stays set while the send buffer still has data to
1015 // drain, so we keep sending and do not Recv. This is also how the
1016 // send-throttle applies backpressure: while the send buffer is
1017 // full, TryReadRequest() holds a completed request back from a
1018 // worker, so nothing new is read until send has drained.
1019 // 2. Else, m_req is incomplete and needs more data, or there is no
1020 // m_req at all and the recv buffer is empty -> Recv
1021 // 3. Else (no parse in progress, leftover bytes in m_recv_buffer) -> 0
1022 // Stay in the I/O map so TryReadRequest() drains the buffer first.
1023 // Extra pipelined data waits in the kernel socket buffer
1024 // (TCP backpressure), not in m_recv_buffer.
1025 //
1026 // Lock-order safety: the convention established by
1027 // MaybeSendBytesFromBuffer() is to take m_send_mutex before m_sock_mutex.
1028 // In this loop GetSock() (above) takes m_sock_mutex and ReadyToSend()
1029 // (below) takes m_send_mutex; both are scoped, so each lock is released
1030 // before the next is taken and they stay separate critical sections.
1031 // Holding m_sock_mutex while acquiring m_send_mutex would invert that
1032 // order and risk a lock-order-inversion deadlock.
1033 Sock::Event event{0};
1034 if (http_client->ReadyToSend()) {
1035 event = Sock::SendEvent;
1036 } else if (http_client->GetRequest() != nullptr || http_client->ReceiveBufferEmpty()) {
1037 // Mid-parse (need more bytes) or buffer empty.
1038 event = Sock::RecvEvent;
1039 }
1040
1041 io_readiness.events_per_sock.emplace(sock, Sock::Events{event});
1042 io_readiness.httpclients_per_sock.emplace(sock, http_client);
1043 }
1044
1045 return io_readiness;
1046}
1047
1050{
1051 while (!m_interrupt_net) {
1052 // Check for the readiness of the already connected sockets and the
1053 // listening sockets in one call ("readiness" as in poll(2) or
1054 // select(2)). If none are ready, wait for a short while and return
1055 // empty sets.
1056 auto io_readiness{GenerateWaitSockets()};
1057 if (io_readiness.events_per_sock.empty() ||
1058 // WaitMany() may as well be a static method, the context of the first Sock in the vector is not relevant.
1059 !io_readiness.events_per_sock.begin()->first->WaitMany(SELECT_TIMEOUT,
1060 io_readiness.events_per_sock)) {
1062 }
1063
1064 // Service (send/receive) each of the already connected sockets.
1065 SocketHandlerConnected(io_readiness);
1066
1067 // Accept new connections from listening sockets.
1068 SocketHandlerListening(io_readiness.events_per_sock);
1069
1070 // Disconnect any clients that have been flagged.
1072 }
1073}
1074
1075std::unique_ptr<HTTPRequest> HTTPRemoteClient::TryReadRequest(const std::shared_ptr<HTTPRemoteClient>& client)
1076{
1077 // If we are already handling a request from
1078 // this client, do nothing. We'll check again on the next I/O
1079 // loop iteration.
1080 if (client->m_req_busy) return nullptr;
1081
1082 if (!client->m_req) {
1083 client->m_req = std::make_unique<HTTPRequest>(client);
1084 }
1085
1086 try {
1087 // Read data from the buffer into the current request
1088 client->ReadRequest(*client->m_req);
1089 } catch (const ContentTooLargeError& e) {
1090 LogDebug(
1092 "HTTP request body too large from client %s (id=%llu): %s",
1093 client->m_origin,
1094 client->m_id,
1095 e.what());
1096
1098 client->m_disconnect = true;
1099 return nullptr;
1100 } catch (const std::runtime_error& e) {
1101 LogDebug(
1103 "Error reading HTTP request from client %s (id=%llu): %s",
1104 client->m_origin,
1105 client->m_id,
1106 e.what());
1107
1108 // We failed to read a complete request from the buffer
1110 client->m_disconnect = true;
1111 return nullptr;
1112 }
1113
1114 // If the request is ready, hand it to a worker.
1115 if (client->m_req->GetState() == HTTPRequest::State::Complete) {
1116 // Unless this client's send buffer is full: in that case hold the
1117 // parsed request here instead of moving it to a worker. This prevents
1118 // the server from reading any more data from this client until they
1119 // drain their end of the socket, and prevents the server from packing
1120 // more responses into the send buffer.
1121 const size_t buffer_used{WITH_LOCK(
1122 client->m_send_mutex,
1123 return client->m_send_buffer.size();)};
1124 if (buffer_used > MAX_BODY_SIZE) return nullptr;
1125 LogDebug(
1127 "Received a %s request for %s from %s (id=%llu)",
1128 RequestMethodString(client->m_req->GetRequestMethod()),
1129 client->m_req->GetURI(),
1130 client->m_origin,
1131 client->m_id);
1132
1133 client->m_req_busy = true;
1134 return std::move(client->m_req);
1135 }
1136
1137 return nullptr;
1138}
1139
1141{
1142 const auto now{Now<SteadySeconds>()};
1143 size_t erased = std::erase_if(m_connected,
1144 [&](auto& client) {
1145 return client->MaybeDisconnect(now,
1147 /*disconnect_all=*/m_disconnect_all_clients);
1148 });
1149 if (erased > 0) {
1150 // Report back to the main thread
1151 m_connected_size.fetch_sub(erased, std::memory_order_relaxed);
1152 }
1153}
1154
1155bool HTTPRemoteClient::MaybeDisconnect(std::chrono::time_point<SteadyClock> now, std::chrono::seconds rpcservertimeout, bool disconnect_all)
1156{
1157 // First check for idle timeout. We reset the timer when we send and receive data,
1158 // but if the server is busy handling a request we should ignore the timeout until
1159 // the reply is sent. If we did erase the shared_ptr<HTTPRemoteClient> reference in m_connected
1160 // while the server is busy with a request, it might be prematurely dropped before
1161 // the response has been sent, or if the HTTPRequest was holding a temporary shared_ptr
1162 // client on a worker thread - it would keep the socket open even after "disconnecting".
1163 const bool is_idle{rpcservertimeout.count() > 0 &&
1164 now - m_idle_since.load() > rpcservertimeout &&
1165 !m_req_busy};
1166
1167 // Disconnect this client due to error, end of communication, or idle timeout.
1168 // May drop unsent data if we are closing due to error.
1169 if (m_disconnect || is_idle) {
1170 if (is_idle) {
1172 "HTTP client idle timeout %s (id=%llu)",
1173 m_origin,
1174 m_id);
1175 }
1176 } else {
1177 // Disconnect this client because the server is shutting
1178 // down and we need to disconnect all clients...
1179 if (disconnect_all) {
1180 // ...unless we still have data for this client.
1181 if (m_connection_busy) {
1182 // There is still data for this healthy-connected client.
1183 // Continue the I/O loop until all data is sent or an error is encountered.
1184 return false;
1185 } else {
1186 // This is a healthy persistent connection (e.g. keep-alive)
1187 // but it's time to say goodbye.
1188 ;
1189 }
1190 } else {
1191 // No reason to disconnect.
1192 return false;
1193 }
1194 }
1195 // No reason NOT to disconnect, log and remove.
1197 "Disconnecting HTTP client %s (id=%llu)",
1198 m_origin,
1199 m_id);
1200 return true;
1201}
1202
1204{
1205 Assume(!m_thread_socket_handler.joinable()); // must be called after JoinSocketsThreads()
1206 if (m_connected.empty()) return;
1207 LogWarning("Force-disconnecting %d HTTP client(s) that did not disconnect gracefully", m_connected.size());
1208 m_connected_size.fetch_sub(m_connected.size(), std::memory_order_relaxed);
1209 m_connected.clear();
1210}
1211
1213{
1214 if (m_recv_buffer.empty()) return;
1215
1217
1218 try {
1219 switch (req.GetState()) {
1221 if (!req.LoadControlData(reader)) break;
1223 [[fallthrough]];
1224
1226 if (!req.LoadHeaders(reader)) break;
1228 [[fallthrough]];
1229
1231 if (!req.LoadBody(reader)) break;
1233 [[fallthrough]];
1234
1236 break;
1237
1239 break;
1240 }
1241 } catch (...) {
1242 // Don't try to read any more data for this request
1244 // Clear the memory allocated to this client, caller must disconnect
1245 m_recv_buffer.clear();
1246 throw;
1247 }
1248
1249 // Remove the bytes read out of the buffer.
1250 m_recv_buffer.erase(
1251 m_recv_buffer.begin(),
1252 m_recv_buffer.begin() + reader.Consumed());
1253}
1254
1256{
1257 // Send as much data from this client's buffer as we can
1259 if (!m_send_buffer.empty()) {
1260 // Socket flags (See kernel docs for send(2) and tcp(7) for more details).
1261 // MSG_NOSIGNAL: If the remote end of the connection is closed,
1262 // fail with EPIPE (an error) as opposed to triggering
1263 // SIGPIPE which terminates the process.
1264 // MSG_DONTWAIT: Makes the send operation non-blocking regardless of socket blocking mode.
1265 // MSG_MORE: We do not set this flag here because http responses are usually
1266 // small and we want the kernel to send them right away. Setting MSG_MORE
1267 // would "cork" the socket to prevent sending out partial frames.
1269
1270 // Try to send bytes through socket
1271 ssize_t bytes_sent;
1272 {
1274 bytes_sent = m_sock->Send(m_send_buffer.data(),
1275 m_send_buffer.size(),
1276 flags);
1277 }
1278
1279 if (bytes_sent < 0) {
1280 // Something went wrong
1281 const int err{WSAGetLastError()};
1282 if (!IOErrorIsPermanent(err)) {
1283 // The error can be safely ignored, try the send again on the next I/O loop.
1284 m_send_ready = true;
1285 m_connection_busy = true;
1286 return true;
1287 } else {
1288 // Unrecoverable error, log and disconnect client.
1289 LogDebug(
1291 "Error sending HTTP response data to client %s (id=%llu): %s",
1292 m_origin,
1293 m_id,
1294 NetworkErrorString(err));
1295 m_send_ready = false;
1296 m_disconnect = true;
1297
1298 // Do not attempt to read from this client.
1299 return false;
1300 }
1301 }
1302
1303 // Successful send, remove sent bytes from our local buffer.
1304 Assume(static_cast<size_t>(bytes_sent) <= m_send_buffer.size());
1305 m_send_buffer.erase(m_send_buffer.begin(),
1306 m_send_buffer.begin() + bytes_sent);
1307
1308 LogDebug(
1310 "Sent %d bytes to client %s (id=%llu)",
1311 bytes_sent,
1312 m_origin,
1313 m_id);
1314
1315 // This check is inside the if(!empty) block meaning "there was data but now its gone".
1316 // We wouldn't want to change the flags if MaybeSendBytesFromBuffer() was called
1317 // on an already-empty m_send_buffer because the connection might have just been opened.
1318 if (m_send_buffer.empty()) {
1319 m_send_ready = false;
1320 m_connection_busy = false;
1321
1322 // Our work is done here
1323 if (!m_keep_alive) {
1324 m_disconnect = true;
1325 // Do not attempt to read from this client.
1326 return false;
1327 }
1328 } else {
1329 // The send buffer isn't flushed yet, try to push more on the next loop.
1330 m_send_ready = true;
1331 m_connection_busy = true;
1332 }
1333
1334 // Finally, reset idle timeout
1335 m_idle_since = Now<SteadySeconds>();
1336 }
1337
1338 return true;
1339}
1340
1342{
1343 // Create HTTPServer
1344 g_http_server = std::make_unique<HTTPServer>(MaybeDispatchRequestToWorker);
1345
1346 if (!g_http_server->InitHTTPAllowList()) {
1347 return false;
1348 }
1349
1350 g_http_server->SetServerTimeout(std::chrono::seconds(gArgs.GetIntArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT)));
1351 g_http_server->SetMaxConnections(std::max(gArgs.GetArg<int>("-rpcmaxconnections", DEFAULT_MAX_HTTP_CONNECTIONS), 1));
1352
1353 // Bind HTTP server to specified addresses
1354 std::vector<std::pair<std::string, uint16_t>> endpoints{GetBindAddresses()};
1355 bool bind_success{false};
1356 for (const auto& [address_string, port] : endpoints) {
1357 LogInfo("Binding RPC on address %s port %i", address_string, port);
1358 const std::optional<CService> addr{Lookup(address_string, port, false)};
1359 if (addr) {
1360 if (addr->IsBindAny()) {
1361 LogWarning("The RPC server is not safe to expose to untrusted networks such as the public internet");
1362 }
1363 auto result{g_http_server->BindAndStartListening(addr.value())};
1364 if (!result) {
1365 LogWarning("Binding RPC on address %s failed: %s", addr->ToStringAddrPort(), result.error());
1366 } else {
1367 bind_success = true;
1368 }
1369 } else {
1370 LogWarning("Could not bind RPC on address %s port %i: Address lookup failed.", address_string, port);
1371 }
1372 }
1373
1374 if (!bind_success) {
1375 LogError("Unable to bind any endpoint for RPC server");
1376 return false;
1377 }
1378
1379 LogDebug(BCLog::HTTP, "Initialized HTTP server");
1380
1381 g_max_queue_depth = std::max(gArgs.GetArg<int>("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1);
1382 LogDebug(BCLog::HTTP, "set work queue of depth %d\n", g_max_queue_depth);
1383
1384 return true;
1385}
1386
1388{
1389 auto rpcThreads{std::max(gArgs.GetArg<int>("-rpcthreads", DEFAULT_HTTP_THREADS), 1)};
1390 LogInfo("Starting HTTP server with %d worker threads", rpcThreads);
1391 g_threadpool_http.Start(rpcThreads);
1392 g_http_server->StartSocketsThreads();
1393}
1394
1396{
1397 LogDebug(BCLog::HTTP, "Interrupting HTTP server");
1398 if (g_http_server) {
1399 // Reject all new requests
1400 g_http_server->SetRequestHandler(RejectRequest);
1401 }
1402
1403 // Interrupt pool after disabling requests
1405}
1406
1408{
1409 LogDebug(BCLog::HTTP, "Stopping HTTP server");
1410
1411 LogDebug(BCLog::HTTP, "Waiting for HTTP worker threads to exit\n");
1413
1414 if (g_http_server) {
1415 // Must precede DisconnectAllClients(): a connection accepted after
1416 // GetConnectionsCount() returns 0 would survive into the destructor.
1417 g_http_server->StopAccepting();
1418 // Disconnect clients as their remaining responses are flushed
1419 g_http_server->DisconnectAllClients();
1420 // Wait 30 seconds for all disconnections
1421 LogDebug(BCLog::HTTP, "Waiting for HTTP clients to disconnect gracefully");
1422 const auto deadline{NodeClock::now() + 30s};
1423 while (g_http_server->GetConnectionsCount() != 0) {
1424 if (NodeClock::now() > deadline) {
1425 LogWarning("Timeout waiting for HTTP clients to disconnect gracefully, continuing shutdown");
1426 break;
1427 }
1428 std::this_thread::sleep_for(50ms);
1429 }
1430 // Break HTTPServer I/O loop: stop accepting connections, sending and receiving data
1431 g_http_server->InterruptNet();
1432 // Wait for HTTPServer I/O thread to exit
1433 g_http_server->JoinSocketsThreads();
1434 // Force-remove any clients that survived the graceful wait
1435 g_http_server->ClearConnectedClients();
1436 // Close all listening sockets
1437 g_http_server->StopListening();
1438 }
1439 LogDebug(BCLog::HTTP, "Stopped HTTP server");
1440}
ArgsManager gArgs
Definition: args.cpp:38
int ret
int flags
Definition: bitcoin-tx.cpp:530
const CBaseChainParams & BaseParams()
Return the currently selected parameters.
#define Assume(val)
Assume is the identity function.
Definition: check.h:128
std::vector< std::string > GetArgs(const std::string &strArg) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return a vector of strings of the given argument.
Definition: args.cpp:422
std::string GetArg(const std::string &strArg, const std::string &strDefault) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return string argument or default value.
Definition: args.cpp:517
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Definition: args.h:323
btcsignals::signal< void(const bilingual_str &message, unsigned int style)> ThreadSafeMessageBox
Show message box.
Definition: interface_ui.h:68
Network address.
Definition: netaddress.h:113
bool IsValid() const
Definition: netaddress.cpp:430
bool IsIPv6() const
Definition: netaddress.h:159
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:531
bool SetSockAddr(const struct sockaddr *paddr, socklen_t addrlen)
Set CService from a network sockaddr.
Definition: netaddress.cpp:812
sa_family_t GetSAFamily() const
Get the address family.
Definition: netaddress.cpp:828
bool GetSockAddr(struct sockaddr *paddr, socklen_t *addrlen) const
Obtain the IPv4/6 socket address this represents.
Definition: netaddress.cpp:868
std::string ToStringAddrPort() const
Definition: netaddress.cpp:909
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.
Definition: sync.h:142
std::optional< std::string > FindFirst(std::string_view key) const
Definition: httpserver.cpp:265
size_t m_consumed
Track total bytes consumed in Read() for limit checks.
Definition: httpserver.h:130
void RemoveAll(std::string_view key)
Definition: httpserver.cpp:291
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:127
bool Read(util::LineReader &reader, bool write=true)
Definition: httpserver.cpp:299
std::string Stringify() const
Definition: httpserver.cpp:355
void Write(std::string &&key, std::string &&value)
Definition: httpserver.cpp:286
std::vector< std::string_view > FindAll(std::string_view key) const LIFETIMEBOUND
Definition: httpserver.cpp:275
std::atomic_bool m_disconnect
Flag this client for disconnection on next loop.
Definition: httpserver.h:629
Mutex m_send_mutex
Response data destined for this client.
Definition: httpserver.h:581
void Send(const HTTPResponse &res, std::span< const std::byte > reply_body, bool keep_alive) EXCLUSIVE_LOCKS_REQUIRED(!m_send_mutex
Definition: httpserver.cpp:606
const std::string m_origin
IP:port of connected client, cached for logging purposes.
Definition: httpserver.h:557
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.
Definition: httpserver.h:551
std::string m_recv_buffer
In lieu of an intermediate transport class like p2p uses, we copy data from the socket buffer to the ...
Definition: httpserver.h:564
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.
Definition: httpserver.h:634
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.
Definition: httpserver.h:600
std::atomic_bool m_connection_busy
Initialized to true while server waits for first request from client.
Definition: httpserver.h:617
void Receive() EXCLUSIVE_LOCKS_REQUIRED(!m_sock_mutex)
Definition: httpserver.cpp:931
std::atomic_bool m_keep_alive
Client has requested to keep the connection open after all requests have been responded to.
Definition: httpserver.h:622
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,...
Definition: httpserver.h:574
void WriteHeader(std::string &&hdr, std::string &&value)
Definition: httpserver.cpp:703
std::optional< uint64_t > m_chunk_size
Definition: httpserver.h:222
std::optional< std::string > GetQueryParameter(std::string_view key) const
Definition: httpserver.cpp:666
std::string GetURI() const
Definition: httpserver.h:186
std::string m_target
Definition: httpserver.h:208
bool LoadHeaders(util::LineReader &reader)
Definition: httpserver.cpp:426
HTTPHeaders m_headers
Definition: httpserver.h:210
bool LoadControlData(util::LineReader &reader)
Methods that attempt to parse HTTP request fields line-by-line from a receive buffer.
Definition: httpserver.cpp:378
HTTPVersion m_version
Definition: httpserver.h:209
uint64_t m_chunk_read
Definition: httpserver.h:225
std::weak_ptr< HTTPRemoteClient > m_client
Pointer to the client that made the request so we know who to respond to.
Definition: httpserver.h:214
std::optional< std::string > GetHeader(std::string_view hdr) const
Definition: httpserver.cpp:698
HTTPRequestMethod m_method
Definition: httpserver.h:207
std::string m_body
Definition: httpserver.h:211
bool LoadBody(util::LineReader &reader)
Definition: httpserver.cpp:431
void SetState(State state)
Definition: httpserver.h:204
void WriteReply(HTTPStatusCode status, std::span< const std::byte > reply_body={})
Definition: httpserver.cpp:535
State GetState() const
Definition: httpserver.h:203
CService GetPeer() const
Definition: httpserver.cpp:657
HTTPHeaders m_response_headers
Response headers may be set in advance before response body is known.
Definition: httpserver.h:217
std::atomic< Id > m_next_id
The id to assign to the next created connection.
Definition: httpserver.h:339
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.
Definition: httpserver.cpp:813
std::vector< std::shared_ptr< HTTPRemoteClient > > m_connected
List of HTTPRemoteClients with connected sockets.
Definition: httpserver.h:347
int m_rpcmaxconnections
Maximum amount of concurrent connections.
Definition: httpserver.h:432
CThreadInterrupt m_interrupt_net
This is signaled when network activity should cease.
Definition: httpserver.h:396
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:890
std::atomic_bool m_disconnect_all_clients
Flag used during shutdown.
Definition: httpserver.h:360
Id GetNewId()
Generate an id for a newly created connection.
Definition: httpserver.cpp:858
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.
Definition: httpserver.cpp:708
std::vector< CSubNet > m_allow_subnets
List of subnets to allow HTTP connections from.
Definition: httpserver.h:422
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:367
std::vector< std::shared_ptr< Sock > > m_listen
List of listening sockets.
Definition: httpserver.h:334
std::atomic_bool m_stop_accepting
Flag used during shutdown to stop accepting new connections.
Definition: httpserver.h:353
void SocketHandlerListening(const Sock::EventsPerSock &events_per_sock)
Accept incoming connections, one from each read-ready listening socket.
Definition: httpserver.cpp:972
IOReadiness GenerateWaitSockets() const
Generate a collection of sockets to check for IO readiness.
Definition: httpserver.cpp:994
std::thread m_thread_socket_handler
Thread that sends to and receives from sockets and accepts connections.
Definition: httpserver.h:402
uint64_t Id
Each connection is assigned an unique id of this type.
Definition: httpserver.h:236
std::chrono::seconds m_rpcservertimeout
Idle timeout after which clients are disconnected.
Definition: httpserver.h:417
void StopListening()
Stop listening by closing all listening sockets.
Definition: httpserver.cpp:796
size_t GetConnectionsCount() const
Get the number of HTTPRemoteClients we are connected to.
Definition: httpserver.h:273
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:863
bool ClientAllowed(const CNetAddr &netaddr) const
Check an incoming connection's source IP against the allow list.
Definition: httpserver.cpp:79
bool InitHTTPAllowList()
Parse the user's -rpcallowip settings and populate m_allow_subnets.
Definition: httpserver.cpp:90
Mutex m_request_dispatcher_mutex
Definition: httpserver.h:410
std::unique_ptr< Sock > AcceptConnection(const Sock &listen_sock, CService &addr)
Accept a connection.
Definition: httpserver.cpp:820
void StartSocketsThreads()
Start the necessary threads for sockets IO.
Definition: httpserver.cpp:801
RAII helper class that manages a socket and closes it automatically when it goes out of scope.
Definition: sock.h:35
static constexpr Event RecvEvent
If passed to Wait(), then it will wait for readiness to read from the socket.
Definition: sock.h:151
virtual std::unique_ptr< Sock > Accept(sockaddr *addr, socklen_t *addr_len) const
accept(2) wrapper.
Definition: sock.cpp:72
uint8_t Event
Definition: sock.h:146
static constexpr Event SendEvent
If passed to Wait(), then it will wait for readiness to send to the socket.
Definition: sock.h:156
static constexpr Event ErrorEvent
Ignored if passed to Wait(), but could be set in the occurred events if an exceptional condition has ...
Definition: sock.h:162
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
Fixed-size thread pool for running arbitrary tasks concurrently.
Definition: threadpool.h:48
void Start(int num_workers) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Start worker threads.
Definition: threadpool.h:105
util::Expected< Future< F >, SubmitError > Submit(F &&fn) noexcept EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Enqueues a new task for asynchronous execution.
Definition: threadpool.h:184
void Stop() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Stop all worker threads and wait for them to exit.
Definition: threadpool.h:128
void Interrupt() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Stop accepting new tasks and begin asynchronous shutdown.
Definition: threadpool.h:268
size_t WorkQueueSize() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Definition: threadpool.h:274
The util::Expected class provides a standard way for low-level functions to return either error value...
Definition: expected.h:44
size_t Consumed() const
Returns number of bytes already read from buffer.
Definition: string.cpp:85
std::optional< std::string_view > ReadLine() LIFETIMEBOUND
Returns a string from current iterator position up to (but not including) next and advances iterator...
Definition: string.cpp:35
size_t Remaining() const
Returns remaining size of bytes in buffer.
Definition: string.cpp:80
std::string_view ReadLength(size_t len) LIFETIMEBOUND
Returns string from current iterator position of specified length if possible and advances iterator o...
Definition: string.cpp:71
The util::Unexpected class represents an unexpected value stored in util::Expected.
Definition: expected.h:21
#define WSAEWOULDBLOCK
Definition: compat.h:61
#define SOCKET_ERROR
Definition: compat.h:68
#define WSAGetLastError()
Definition: compat.h:59
#define MSG_NOSIGNAL
Definition: compat.h:110
#define MSG_DONTWAIT
Definition: compat.h:115
#define WSAEADDRINUSE
Definition: compat.h:66
static std::vector< std::pair< std::string, uint16_t > > GetBindAddresses()
Definition: httpserver.cpp:208
static void WriteNoStoreErrorReply(HTTPRequest &req, HTTPStatusCode status, std::string_view reply={})
Definition: httpserver.cpp:130
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.
Definition: httpserver.cpp:248
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
Register handler for prefix.
Definition: httpserver.cpp:241
void StartHTTPServer()
Start HTTP server.
static void RejectRequest(std::unique_ptr< HTTPRequest > hreq)
Definition: httpserver.cpp:202
std::string_view RequestMethodString(HTTPRequestMethod m)
HTTP request method as string - use for logging only.
Definition: httpserver.cpp:117
bool InitHTTPServer()
Initialize HTTP server.
static void MaybeDispatchRequestToWorker(std::shared_ptr< HTTPRequest > hreq)
Definition: httpserver.cpp:136
std::optional< std::string > GetQueryParameterFromUri(const std::string_view uri, const std::string_view key)
Definition: httpserver.cpp:673
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...
Definition: httpserver.cpp:47
static std::unique_ptr< HTTPServer > g_http_server
HTTP module state.
Definition: httpserver.cpp:69
static constexpr int SOCKET_OPTION_TRUE
Explicit alias for setting socket option methods.
Definition: httpserver.cpp:50
static int g_max_queue_depth
Definition: httpserver.cpp:76
void StopHTTPServer()
Stop HTTP server.
static std::vector< HTTPPathHandler > pathHandlers GUARDED_BY(g_httppathhandlers_mutex)
static GlobalMutex g_httppathhandlers_mutex
Handlers for (sub)paths.
Definition: httpserver.cpp:71
constexpr int DEFAULT_MAX_HTTP_CONNECTIONS
Maximum number of connected HTTP clients.
Definition: httpserver.h:47
std::function< void(HTTPRequest *req, const std::string &)> HTTPRequestHandler
Handler for requests to a certain HTTP path.
Definition: httpserver.h:60
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
HTTPRequestMethod
Definition: httpserver.h:49
util::LineReader reader
HTTPHeaders headers
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 LogWarning(...)
Definition: log.h:126
#define LogInfo(...)
Definition: log.h:125
#define LogError(...)
Definition: log.h:127
#define LogDebug(category,...)
Definition: log.h:143
is a home for simple string functions returning descriptive messages that are used in RPC and GUI int...
@ HTTP
Definition: categories.h:19
constexpr uint64_t MAX_BODY_SIZE
Maximum size of an HTTP request body received from a client.
Definition: httpserver.h:82
constexpr size_t MIN_REQUEST_LINE_LENGTH
Shortest valid request line, used by libevent in evhttp_parse_request_line()
Definition: httpserver.h:72
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:78
bilingual_str InvalidPortErrMsg(const std::string &optname, const std::string &invalid_value)
Definition: messages.cpp:148
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.
Definition: string.h:120
void TraceThread(std::string_view thread_name, std::function< void()> thread_func)
A wrapper for do-something-once thread functions.
Definition: thread.cpp:15
std::string_view TrimStringView(std::string_view str LIFETIMEBOUND, std::string_view pattern=" \f\n\r\t\v")
Definition: string.h:163
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition: string.h:250
std::string TrimString(std::string_view str, std::string_view pattern=" \f\n\r\t\v")
Definition: string.h:173
CSubNet LookupSubNet(const std::string &subnet_str)
Parse and resolve a specified subnet string into the appropriate internal representation.
Definition: netbase.cpp:831
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.
Definition: netbase.cpp:173
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.
Definition: netbase.cpp:191
std::function< std::unique_ptr< Sock >(int, int, int)> CreateSock
Socket factory.
Definition: netbase.cpp:577
const char * prefix
Definition: rest.cpp:1197
bool(* handler)(const std::any &context, HTTPRequest *req, const std::string &strReq)
Definition: rest.cpp:1198
std::string_view HTTPStatusReasonString(HTTPStatusCode code)
Mapping of HTTP status codes to short string explanation.
Definition: protocol.h:28
HTTPStatusCode
HTTP status codes.
Definition: protocol.h:13
@ HTTP_BAD_REQUEST
Definition: protocol.h:16
@ HTTP_BAD_METHOD
Definition: protocol.h:20
@ HTTP_CONTENT_TOO_LARGE
Definition: protocol.h:21
@ HTTP_SERVICE_UNAVAILABLE
Definition: protocol.h:23
@ HTTP_NOT_FOUND
Definition: protocol.h:19
@ HTTP_NO_CONTENT
Definition: protocol.h:15
@ HTTP_INTERNAL_SERVER_ERROR
Definition: protocol.h:22
std::string NetworkErrorString(int err)
Return readable error string for a network error code.
Definition: sock.cpp:426
bool IOErrorIsPermanent(int err)
Definition: sock.h:26
std::string prefix
Definition: httpserver.cpp:62
HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler)
Definition: httpserver.cpp:58
HTTPRequestHandler handler
Definition: httpserver.cpp:64
HTTPVersion version
Definition: httpserver.h:145
std::string StringifyHeaders() const
Definition: httpserver.cpp:368
HTTPHeaders headers
Definition: httpserver.h:147
Info about which socket has which event ready and a reverse map back to the HTTPRemoteClient that own...
Definition: httpserver.h:373
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:390
Sock::EventsPerSock events_per_sock
Map of socket -> socket events.
Definition: httpserver.h:379
uint8_t minor
Definition: httpserver.h:140
uint8_t major
Default HTTP protocol version 1.1 is used by error responses when a request is unreadable.
Definition: httpserver.h:139
static time_point now() noexcept
Return current system time or mocked time, if set.
Definition: time.cpp:38
Auxiliary requested/occurred events to wait for in WaitMany().
Definition: sock.h:181
Thrown when a request body exceeds MAX_BODY_SIZE (or will exceed, in chunked transfer) so the server ...
Definition: httpserver.h:86
#define LOCK(cs)
Definition: sync.h:268
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:299
constexpr std::string_view SubmitErrorString(const ThreadPool::SubmitError err) noexcept
Definition: threadpool.h:285
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:82
std::string UrlDecode(std::string_view url_encoded)
Definition: url.cpp:13
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....
Definition: time.cpp:131
assert(!tx.IsCoinBase())