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