Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
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
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
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
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) {
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
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
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
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
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
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
530
531 return m_body.size() == *content_length;
532 }
533}
534
535void HTTPRequest::WriteReply(HTTPStatusCode status, std::span<const std::byte> reply_body)
536{
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.
567 }
568 }
569
570 // HTTP/1.1
571 if (m_version.minor >= 1) {
573 res.headers.Write("Date", FormatRFC1123DateTime(now_seconds));
574
575 // HTTP/1.1 connections are kept alive by default and always require Content-Length.
577
578 // Default for HTTP/1.1
579 keep_alive = true;
580 }
581 }
582
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()}) {
603 }
604}
605
606void HTTPRemoteClient::Send(const HTTPResponse& res, std::span<const std::byte> reply_body, bool keep_alive)
607{
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 {
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.
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.
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
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.
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
759 if (sock->SetSockOpt(IPPROTO_IPV6,
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
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
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
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 m_total_bytes_received += static_cast<uint64_t>(nrecv);
971 LogDebug(
973 "Received %d bytes from %s (id=%llu): total=%llu buffered=%zu",
974 nrecv,
975 m_origin,
976 m_id,
978 m_recv_buffer.size());
979 }
980}
981
983{
984 if (m_stop_accepting) return;
985 for (const auto& sock : m_listen) {
986 if (m_interrupt_net) {
987 return;
988 }
989 const auto it = events_per_sock.find(sock);
990 if (it != events_per_sock.end() && it->second.occurred & Sock::RecvEvent) {
991 // Drain all pending connections from this socket up to the limit.
992 // Stop early if the kernel queue is empty (AcceptConnection returns null)
993 // or if accepting the last connection brought us to the limit.
994 while (GetConnectionsCount() < static_cast<size_t>(m_rpcmaxconnections)) {
997 if (!sock_accepted) break;
999 }
1000 }
1001 }
1002}
1003
1005{
1007
1008 // If the server is already handling its max connected clients count,
1009 // don't bother checking the listening sockets for new inbound connections.
1010 // Leave them in the kernel's queue until space in the application opens
1011 // up (or the client times out on its own).
1012 if (GetConnectionsCount() < static_cast<size_t>(m_rpcmaxconnections)) {
1013 for (const auto& sock : m_listen) {
1015 }
1016 }
1017
1018 for (const auto& http_client : m_connected) {
1019 // Safely copy the shared pointer to the socket
1020 std::shared_ptr<Sock> sock{http_client->GetSock()};
1021
1022 // Event choice:
1023 // 1. ReadyToSend() (m_send_ready set) -> Send
1024 // m_send_ready stays set while the send buffer still has data to
1025 // drain, so we keep sending and do not Recv. This is also how the
1026 // send-throttle applies backpressure: while the send buffer is
1027 // full, TryReadRequest() holds a completed request back from a
1028 // worker, so nothing new is read until send has drained.
1029 // 2. Else, m_req is incomplete and needs more data, or there is no
1030 // m_req at all and the recv buffer is empty -> Recv
1031 // 3. Else (no parse in progress, leftover bytes in m_recv_buffer) -> 0
1032 // Stay in the I/O map so TryReadRequest() drains the buffer first.
1033 // Extra pipelined data waits in the kernel socket buffer
1034 // (TCP backpressure), not in m_recv_buffer.
1035 //
1036 // Lock-order safety: the convention established by
1037 // MaybeSendBytesFromBuffer() is to take m_send_mutex before m_sock_mutex.
1038 // In this loop GetSock() (above) takes m_sock_mutex and ReadyToSend()
1039 // (below) takes m_send_mutex; both are scoped, so each lock is released
1040 // before the next is taken and they stay separate critical sections.
1041 // Holding m_sock_mutex while acquiring m_send_mutex would invert that
1042 // order and risk a lock-order-inversion deadlock.
1043 Sock::Event event{0};
1044 if (http_client->ReadyToSend()) {
1045 event = Sock::SendEvent;
1046 } else if (http_client->GetRequest() != nullptr || http_client->ReceiveBufferEmpty()) {
1047 // Mid-parse (need more bytes) or buffer empty.
1048 event = Sock::RecvEvent;
1049 }
1050
1051 io_readiness.events_per_sock.emplace(sock, Sock::Events{event});
1052 io_readiness.httpclients_per_sock.emplace(sock, http_client);
1053 }
1054
1055 return io_readiness;
1056}
1057
1060{
1061 while (!m_interrupt_net) {
1062 // Check for the readiness of the already connected sockets and the
1063 // listening sockets in one call ("readiness" as in poll(2) or
1064 // select(2)). If none are ready, wait for a short while and return
1065 // empty sets.
1067 if (io_readiness.events_per_sock.empty() ||
1068 // WaitMany() may as well be a static method, the context of the first Sock in the vector is not relevant.
1069 !io_readiness.events_per_sock.begin()->first->WaitMany(SELECT_TIMEOUT,
1070 io_readiness.events_per_sock)) {
1072 }
1073
1074 // Service (send/receive) each of the already connected sockets.
1076
1077 // Accept new connections from listening sockets.
1078 SocketHandlerListening(io_readiness.events_per_sock);
1079
1080 // Disconnect any clients that have been flagged.
1082 }
1083}
1084
1085std::unique_ptr<HTTPRequest> HTTPRemoteClient::TryReadRequest(const std::shared_ptr<HTTPRemoteClient>& client)
1086{
1087 // If we are already handling a request from
1088 // this client, do nothing. We'll check again on the next I/O
1089 // loop iteration.
1090 if (client->m_req_busy) return nullptr;
1091
1092 if (!client->m_req) {
1093 client->m_req = std::make_unique<HTTPRequest>(client);
1094 }
1095
1096 try {
1097 // Read data from the buffer into the current request
1098 client->ReadRequest(*client->m_req);
1099 } catch (const ContentTooLargeError& e) {
1100 LogDebug(
1102 "HTTP request body too large from client %s (id=%llu): %s",
1103 client->m_origin,
1104 client->m_id,
1105 e.what());
1106
1108 client->m_disconnect = true;
1109 return nullptr;
1110 } catch (const std::runtime_error& e) {
1111 LogDebug(
1113 "Error reading HTTP request from client %s (id=%llu): %s",
1114 client->m_origin,
1115 client->m_id,
1116 e.what());
1117
1118 // We failed to read a complete request from the buffer
1120 client->m_disconnect = true;
1121 return nullptr;
1122 }
1123
1124 // If the request is ready, hand it to a worker.
1125 if (client->m_req->GetState() == HTTPRequest::State::Complete) {
1126 // Unless this client's send buffer is full: in that case hold the
1127 // parsed request here instead of moving it to a worker. This prevents
1128 // the server from reading any more data from this client until they
1129 // drain their end of the socket, and prevents the server from packing
1130 // more responses into the send buffer.
1131 const size_t buffer_used{WITH_LOCK(
1132 client->m_send_mutex,
1133 return client->m_send_buffer.size();)};
1134 if (buffer_used > MAX_BODY_SIZE) return nullptr;
1135 LogDebug(
1137 "Received a %s request for %s from %s (id=%llu)",
1138 RequestMethodString(client->m_req->GetRequestMethod()),
1139 client->m_req->GetURI(),
1140 client->m_origin,
1141 client->m_id);
1142
1143 client->m_req_busy = true;
1144 return std::move(client->m_req);
1145 }
1146
1147 return nullptr;
1148}
1149
1151{
1152 const auto now{MockableSteadyClock::now()};
1153 size_t erased = std::erase_if(m_connected, [&](auto& client) {
1154 bool disconnect{client->ShouldDisconnect(now,
1156 /*disconnect_all=*/m_disconnect_all_clients)};
1157 if (disconnect) {
1159 "Disconnecting HTTP client %s (id=%llu)",
1160 client->GetOrigin(),
1161 client->GetId());
1162 }
1163 return disconnect;
1164 });
1165 if (erased > 0) {
1166 // Report back to the main thread
1167 m_connected_size.fetch_sub(erased, std::memory_order_relaxed);
1168 }
1169}
1170
1172{
1173 // Disconnect this client due to error or end of communication
1174 // May drop unsent data if we are closing due to error.
1175 if (m_disconnect) {
1176 // We should already have logged the reason when we set m_disconnect.
1177 return true;
1178 // Check for idle timeout. We reset the timer when we send and receive data,
1179 // but if the server is busy handling a request we should ignore the timeout until
1180 // the reply is sent. If we did erase the shared_ptr<HTTPRemoteClient> reference in m_connected
1181 // while the server is busy with a request, it might be prematurely dropped before
1182 // the response has been sent, or if the HTTPRequest was holding a temporary shared_ptr
1183 // client on a worker thread - it would keep the socket open even after "disconnecting".
1184 } else if (rpcservertimeout.count() > 0 &&
1185 now - m_idle_since.load() > rpcservertimeout &&
1186 !m_req_busy) {
1188 "HTTP client idle timeout %s (id=%llu)",
1189 m_origin,
1190 m_id);
1191 return true;
1192 // Disconnect this client because the server is shutting down and we need to
1193 // disconnect all clients... Unless the client is still being handled by a
1194 // worker thread, in which case we'd rather continue the I/O loop (but might
1195 // not complete sending back the full response).
1196 } else if (disconnect_all && !m_connection_busy) {
1197 return true;
1198 } else {
1199 // No reason to disconnect.
1200 return false;
1201 }
1202}
1203
1205{
1206 Assume(!m_thread_socket_handler.joinable()); // must be called after JoinSocketsThreads()
1207 if (m_connected.empty()) return;
1208 LogWarning("Force-disconnecting %d HTTP client(s) that did not disconnect gracefully", m_connected.size());
1209 m_connected_size.fetch_sub(m_connected.size(), std::memory_order_relaxed);
1210 m_connected.clear();
1211}
1212
1214{
1215 if (m_recv_buffer.empty()) return;
1216
1218
1219 try {
1220 switch (req.GetState()) {
1221 case HTTPRequest::State::Init:
1222 if (!req.LoadControlData(reader)) break;
1223 req.SetState(HTTPRequest::State::NeedsHeaders);
1224 [[fallthrough]];
1225
1226 case HTTPRequest::State::NeedsHeaders:
1227 if (!req.LoadHeaders(reader)) break;
1228 req.SetState(HTTPRequest::State::NeedsBody);
1229 [[fallthrough]];
1230
1231 case HTTPRequest::State::NeedsBody:
1232 if (!req.LoadBody(reader)) break;
1233 req.SetState(HTTPRequest::State::Complete);
1234 [[fallthrough]];
1235
1236 case HTTPRequest::State::Complete:
1237 break;
1238
1239 case HTTPRequest::State::Error:
1240 break;
1241 }
1242 } catch (...) {
1243 // Don't try to read any more data for this request
1244 req.SetState(HTTPRequest::State::Error);
1245 // Clear the memory allocated to this client, caller must disconnect
1246 m_recv_buffer.clear();
1247 throw;
1248 }
1249
1250 // Remove the bytes read out of the buffer.
1251 m_recv_buffer.erase(
1252 m_recv_buffer.begin(),
1253 m_recv_buffer.begin() + reader.Consumed());
1254}
1255
1257{
1258 // Send as much data from this client's buffer as we can
1260 if (!m_send_buffer.empty()) {
1261 // Socket flags (See kernel docs for send(2) and tcp(7) for more details).
1262 // MSG_NOSIGNAL: If the remote end of the connection is closed,
1263 // fail with EPIPE (an error) as opposed to triggering
1264 // SIGPIPE which terminates the process.
1265 // MSG_DONTWAIT: Makes the send operation non-blocking regardless of socket blocking mode.
1266 // MSG_MORE: We do not set this flag here because http responses are usually
1267 // small and we want the kernel to send them right away. Setting MSG_MORE
1268 // would "cork" the socket to prevent sending out partial frames.
1270
1271 // Try to send bytes through socket
1273 {
1275 bytes_sent = m_sock->Send(m_send_buffer.data(),
1276 m_send_buffer.size(),
1277 flags);
1278 }
1279
1280 if (bytes_sent < 0) {
1281 // Something went wrong
1282 const int err{WSAGetLastError()};
1283 if (!IOErrorIsPermanent(err)) {
1284 // The error can be safely ignored, try the send again on the next I/O loop.
1285 m_send_ready = true;
1286 m_connection_busy = true;
1287 return true;
1288 } else {
1289 // Unrecoverable error, log and disconnect client.
1290 LogDebug(
1292 "Error sending HTTP response data to client %s (id=%llu): %s",
1293 m_origin,
1294 m_id,
1295 NetworkErrorString(err));
1296 m_send_ready = false;
1297 m_disconnect = true;
1298
1299 // Do not attempt to read from this client.
1300 return false;
1301 }
1302 }
1303
1304 // Successful send, remove sent bytes from our local buffer.
1305 Assume(static_cast<size_t>(bytes_sent) <= m_send_buffer.size());
1306 m_send_buffer.erase(m_send_buffer.begin(),
1307 m_send_buffer.begin() + bytes_sent);
1308
1309 LogDebug(
1311 "Sent %d bytes to client %s (id=%llu)",
1312 bytes_sent,
1313 m_origin,
1314 m_id);
1315
1316 // This check is inside the if(!empty) block meaning "there was data but now its gone".
1317 // We wouldn't want to change the flags if MaybeSendBytesFromBuffer() was called
1318 // on an already-empty m_send_buffer because the connection might have just been opened.
1319 if (m_send_buffer.empty()) {
1320 m_send_ready = false;
1321 m_connection_busy = false;
1322
1323 // Our work is done here
1324 if (!m_keep_alive) {
1325 LogDebug(
1327 "Done sending to client without keep-alive %s (id=%llu)",
1328 m_origin,
1329 m_id);
1330 m_disconnect = true;
1331 // Do not attempt to read from this client.
1332 return false;
1333 }
1334 } else {
1335 // The send buffer isn't flushed yet, try to push more on the next loop.
1336 m_send_ready = true;
1337 m_connection_busy = true;
1338 }
1339
1340 // Finally, reset idle timeout
1342 }
1343
1344 return true;
1345}
1346
1348{
1349 // Create HTTPServer
1350 g_http_server = std::make_unique<HTTPServer>(MaybeDispatchRequestToWorker);
1351
1352 if (!g_http_server->InitHTTPAllowList()) {
1353 return false;
1354 }
1355
1356 g_http_server->SetServerTimeout(std::chrono::seconds(gArgs.GetIntArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT)));
1357 g_http_server->SetMaxConnections(std::max(gArgs.GetArg<int>("-rpcmaxconnections", DEFAULT_MAX_HTTP_CONNECTIONS), 1));
1358
1359 // Bind HTTP server to specified addresses
1360 std::vector<std::pair<std::string, uint16_t>> endpoints{GetBindAddresses()};
1361 bool bind_success{false};
1362 for (const auto& [address_string, port] : endpoints) {
1363 LogInfo("Binding RPC on address %s port %i", address_string, port);
1364 const std::optional<CService> addr{Lookup(address_string, port, false)};
1365 if (addr) {
1366 if (addr->IsBindAny()) {
1367 LogWarning("The RPC server is not safe to expose to untrusted networks such as the public internet");
1368 }
1369 auto result{g_http_server->BindAndStartListening(addr.value())};
1370 if (!result) {
1371 LogWarning("Binding RPC on address %s failed: %s", addr->ToStringAddrPort(), result.error());
1372 } else {
1373 bind_success = true;
1374 }
1375 } else {
1376 LogWarning("Could not bind RPC on address %s port %i: Address lookup failed.", address_string, port);
1377 }
1378 }
1379
1380 if (!bind_success) {
1381 LogError("Unable to bind any endpoint for RPC server");
1382 return false;
1383 }
1384
1385 LogDebug(BCLog::HTTP, "Initialized HTTP server");
1386
1387 g_max_queue_depth = std::max(gArgs.GetArg<int>("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1);
1388 LogDebug(BCLog::HTTP, "set work queue of depth %d\n", g_max_queue_depth);
1389
1390 return true;
1391}
1392
1394{
1395 auto rpcThreads{std::max(gArgs.GetArg<int>("-rpcthreads", DEFAULT_HTTP_THREADS), 1)};
1396 LogInfo("Starting HTTP server with %d worker threads", rpcThreads);
1398 g_http_server->StartSocketsThreads();
1399}
1400
1402{
1403 LogDebug(BCLog::HTTP, "Interrupting HTTP server");
1404 if (g_http_server) {
1405 // Reject all new requests
1406 g_http_server->SetRequestHandler(RejectRequest);
1407 }
1408
1409 // Interrupt pool after disabling requests
1411}
1412
1414{
1415 LogDebug(BCLog::HTTP, "Stopping HTTP server");
1416
1417 LogDebug(BCLog::HTTP, "Waiting for HTTP worker threads to exit\n");
1419
1420 if (g_http_server) {
1421 // Must precede DisconnectAllClients(): a connection accepted after
1422 // GetConnectionsCount() returns 0 would survive into the destructor.
1423 g_http_server->StopAccepting();
1424 // Disconnect clients as their remaining responses are flushed
1425 g_http_server->DisconnectAllClients();
1426 // Wait 30 seconds for all disconnections
1427 LogDebug(BCLog::HTTP, "Waiting for HTTP clients to disconnect gracefully");
1428 const auto deadline{NodeClock::now() + 30s};
1429 while (g_http_server->GetConnectionsCount() != 0) {
1430 if (NodeClock::now() > deadline) {
1431 LogWarning("Timeout waiting for HTTP clients to disconnect gracefully, continuing shutdown");
1432 break;
1433 }
1434 std::this_thread::sleep_for(50ms);
1435 }
1436 // Break HTTPServer I/O loop: stop accepting connections, sending and receiving data
1437 g_http_server->InterruptNet();
1438 // Wait for HTTPServer I/O thread to exit
1439 g_http_server->JoinSocketsThreads();
1440 // Force-remove any clients that survived the graceful wait
1441 g_http_server->ClearConnectedClients();
1442 // Close all listening sockets
1443 g_http_server->StopListening();
1444 }
1445 LogDebug(BCLog::HTTP, "Stopped HTTP server");
1446}
ArgsManager gArgs
Definition args.cpp:38
int ret
int flags
const CBaseChainParams & BaseParams()
Return the currently selected parameters.
#define Assume(val)
Assume is the identity function.
Definition check.h:131
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:318
btcsignals::signal< void(const bilingual_str &message, unsigned int style)> ThreadSafeMessageBox
Show message box.
Network address.
Definition netaddress.h:113
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.
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.
Definition sync.h:142
std::optional< std::string > FindFirst(std::string_view key) const
size_t m_consumed
Track total bytes consumed in Read() for limit checks.
Definition httpserver.h:130
void RemoveAll(std::string_view key)
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)
std::string Stringify() const
void Write(std::string &&key, std::string &&value)
std::vector< std::string_view > FindAll(std::string_view key) const LIFETIMEBOUND
std::atomic_bool m_disconnect
Flag this client for disconnection on next loop.
Definition httpserver.h:633
uint64_t m_total_bytes_received
Running total of bytes read from this client's socket.
Definition httpserver.h:568
Mutex m_send_mutex
Response data destined for this client.
Definition httpserver.h:585
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.
Definition httpserver.h:558
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.
const HTTPServer::Id m_id
ID provided by HTTPServer upon connection and instantiation.
Definition httpserver.h:552
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:565
void ReadRequest(HTTPRequest &req)
Try to read an HTTP request from the receive buffer.
bool ShouldDisconnect(std::chrono::time_point< MockableSteadyClock > now, std::chrono::seconds rpcservertimeout, bool disconnect_all) const
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:604
std::atomic_bool m_connection_busy
Initialized to true while server waits for first request from client.
Definition httpserver.h:621
void Receive() EXCLUSIVE_LOCKS_REQUIRED(!m_sock_mutex)
std::atomic_bool m_keep_alive
Client has requested to keep the connection open after all requests have been responded to.
Definition httpserver.h:626
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:578
std::atomic< MockableSteadyClock::time_point > m_idle_since
Timestamp of last send or receive activity, used for -rpcservertimeout.
Definition httpserver.h:638
void WriteHeader(std::string &&hdr, std::string &&value)
std::optional< uint64_t > m_chunk_size
Definition httpserver.h:222
std::optional< std::string > GetQueryParameter(std::string_view key) const
std::string GetURI() const
Definition httpserver.h:186
std::string m_target
Definition httpserver.h:208
bool LoadHeaders(util::LineReader &reader)
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.
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
HTTPRequestMethod m_method
Definition httpserver.h:207
std::string m_body
Definition httpserver.h:211
bool LoadBody(util::LineReader &reader)
void SetState(State state)
Definition httpserver.h:204
void WriteReply(HTTPStatusCode status, std::span< const std::byte > reply_body={})
State GetState() const
Definition httpserver.h:203
CService GetPeer() const
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.
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.
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.
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.
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.
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.
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.
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...
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
Definition httpserver.h:410
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.
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
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:225
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()
static void WriteNoStoreErrorReply(HTTPRequest &req, HTTPStatusCode status, std::string_view reply={})
void InterruptHTTPServer()
Interrupt HTTP server threads.
static ThreadPool g_threadpool_http("http")
Http thread pool - future: encapsulate in HttpContext
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
Unregister handler for prefix.
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
Register handler for prefix.
void StartHTTPServer()
Start HTTP server.
static void RejectRequest(std::unique_ptr< HTTPRequest > hreq)
std::string_view RequestMethodString(HTTPRequestMethod m)
HTTP request method as string - use for logging only.
bool InitHTTPServer()
Initialize HTTP server.
static void MaybeDispatchRequestToWorker(std::shared_ptr< HTTPRequest > hreq)
std::optional< std::string > GetQueryParameterFromUri(const std::string_view uri, const std::string_view key)
static constexpr auto SELECT_TIMEOUT
The set of sockets cannot be modified while waiting, so the sleep time needs to be small to avoid new...
static std::unique_ptr< HTTPServer > g_http_server
HTTP module state.
static constexpr int SOCKET_OPTION_TRUE
Explicit alias for setting socket option methods.
static int g_max_queue_depth
void StopHTTPServer()
Stop HTTP server.
static GlobalMutex g_httppathhandlers_mutex
Handlers for (sub)paths.
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
std::optional< std::string > GetQueryParameterFromUri(std::string_view uri, std::string_view key)
util::LineReader reader
HTTPHeaders headers
CClientUIInterface uiInterface
std::unique_ptr< ProxyClient< messages::FooInterface > > client
#define LogWarning(...)
Definition log.h:137
#define LogInfo(...)
Definition log.h:136
#define LogError(...)
Definition log.h:138
#define LogDebug(category,...)
Definition log.h:154
is a home for simple string functions returning descriptive messages that are used in RPC and GUI int...
constexpr uint64_t MAX_BODY_SIZE
Maximum size of an HTTP request body 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:161
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:428
bool IOErrorIsPermanent(int err)
Definition sock.h:26
std::string prefix
HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler)
HTTPRequestHandler handler
HTTPVersion version
Definition httpserver.h:145
std::string StringifyHeaders() const
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
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:64
std::chrono::time_point< MockableSteadyClock > time_point
Definition time.h:48
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:190
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 GUARDED_BY(x)
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
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
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82
assert(!tx.IsCoinBase())