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