Bitcoin Core 32.1.0
P2P Digital Currency
Loading...
Searching...
No Matches
httpserver.cpp
Go to the documentation of this file.
1// Copyright (c) 2015-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <bitcoin-build-config.h> // IWYU pragma: keep
6
7#include <httpserver.h>
8
9#include <chainparamsbase.h>
10#include <common/args.h>
11#include <common/messages.h>
12#include <common/url.h>
13#include <compat/compat.h>
14#include <logging.h>
15#include <netbase.h>
16#include <node/interface_ui.h>
17#include <rpc/protocol.h>
18#include <span.h>
19#include <sync.h>
20#include <util/check.h>
22#include <util/sock.h>
23#include <util/strencodings.h>
24#include <util/thread.h>
25#include <util/threadnames.h>
26#include <util/threadpool.h>
27#include <util/time.h>
28#include <util/translation.h>
29
30#include <condition_variable>
31#include <cstdio>
32#include <cstdlib>
33#include <memory>
34#include <optional>
35#include <span>
36#include <string>
37#include <string_view>
38#include <thread>
39#include <unordered_map>
40#include <vector>
41
42#include <sys/types.h>
43#include <sys/stat.h>
44
47static constexpr auto SELECT_TIMEOUT{50ms};
48
50static constexpr int SOCKET_OPTION_TRUE{1};
51
54using namespace bitcoin_http;
55
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
68
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
430
432{
433 // https://httpwg.org/specs/rfc9112.html#message.body
434 auto transfer_encoding_header = m_headers.FindFirst("Transfer-Encoding");
435 if (transfer_encoding_header && ToLower(transfer_encoding_header.value()) == "chunked") {
436 // Transfer-Encoding: https://datatracker.ietf.org/doc/html/rfc7230.html#section-3.3.1
437 // Chunked Transfer Coding: https://datatracker.ietf.org/doc/html/rfc7230.html#section-4.1
438 // see evhttp_handle_chunked_read() in libevent http.c
439 while (reader.Remaining() > 0) {
440 if (!m_chunk_size) {
441 auto maybe_chunk_size = reader.ReadLine();
442 if (!maybe_chunk_size) return false;
443
444 // Allow (but ignore) Chunk Extensions
445 // See https://www.rfc-editor.org/rfc/rfc9112.html#name-chunk-extensions
446 std::string_view chunk_size_noext{maybe_chunk_size.value()};
447 const auto semicolon_pos = chunk_size_noext.find(';');
448 if (semicolon_pos != chunk_size_noext.npos) {
449 chunk_size_noext.remove_suffix(chunk_size_noext.size() - semicolon_pos);
450 }
451
452 m_chunk_size = ToIntegral<uint64_t>(util::TrimStringView(chunk_size_noext), /*base=*/16);
453 if (!m_chunk_size) throw std::runtime_error("Cannot parse chunk length value");
454
455 if ((m_body.size() > MAX_BODY_SIZE) ||
456 (*m_chunk_size > MAX_BODY_SIZE - m_body.size()))
457 throw ContentTooLargeError("Chunk will exceed max body size");
458 }
459
460 // We either just read the chunk size, or we have it saved
461 // from a prior I/O loop iteration
463
464 // Last chunk has size 0
465 if (*m_chunk_size == 0) {
466 // Validate Chunked Trailer section, which is used for
467 // additional headers sent at the end of the message.
468 // Data consumed here is counted towards MAX_HEADERS_SIZE
469 // along with the headers we read in the beginning of the request.
470 // At this time we ignore and drop these data after validating.
471 // See https://httpwg.org/specs/rfc9112.html#rfc.section.7.1.2
472 return m_headers.Read(reader, /*write=*/false);
473 }
474
475 // We have not read the entire chunk from the buffer yet
476 if (m_chunk_read < *m_chunk_size) {
477 // Get what we can from the buffer
478 const uint64_t chunk_need{*m_chunk_size - m_chunk_read};
479 const uint64_t buffer_has{std::min(chunk_need, static_cast<uint64_t>(reader.Remaining()))};
480
481 // Pack [partial] chunk onto body and update state
482 m_body += reader.ReadLength(buffer_has);
483 m_chunk_read += buffer_has;
484 }
485
486 // Even though every chunk size is explicitly declared,
487 // they are still terminated by a CRLF we don't need,
488 // just consume it here.
489 if (m_chunk_read == *m_chunk_size) {
490 auto crlf = reader.ReadLine();
491 if (!crlf) {
492 // CRLF not found before end of buffer: it has not been received by our socket yet.
493 return false;
494 }
495 // CRLF was found but there was unexpected data after the chunk_sized chunk
496 if (!crlf.value().empty()) throw std::runtime_error("Improperly terminated chunk");
497
498 // Clear state for next chunk
499 m_chunk_size.reset();
500 m_chunk_read = 0;
501 }
502 }
503
504 // We read all the chunks but never got the last chunk, wait for client to send more
505 return false;
506 } else {
507 // No Content-length or Transfer-Encoding header means no body, see libevent evhttp_get_body()
508 auto content_length_values{m_headers.FindAll("Content-Length")};
509 if (content_length_values.empty()) return true;
510
511 // Duplicate Content-Length headers are allowed only if they all have the same value
512 // https://www.rfc-editor.org/rfc/rfc7230#section-3.3.3
513 const auto& first_content_length_value{content_length_values[0]};
514 for (size_t i = 1; i < content_length_values.size(); ++i) {
515 if (content_length_values[i] != first_content_length_value) throw std::runtime_error("Differing Content-Length values");
516 }
517
518 const auto content_length{ToIntegral<uint64_t>(first_content_length_value)};
519 if (!content_length) throw std::runtime_error("Cannot parse Content-Length value");
520
521 if (*content_length > MAX_BODY_SIZE) throw ContentTooLargeError("Max body size exceeded");
522
523 // A large body may arrive over multiple I/O loop iterations. Copy
524 // whatever the buffer has now; m_body's size tracks our progress.
525 const uint64_t body_need{*content_length - m_body.size()};
526 const uint64_t buffer_has{std::min(body_need, static_cast<uint64_t>(reader.Remaining()))};
527
528 // Pack [partial] body on and update state
529 m_body += reader.ReadLength(buffer_has);
530
531 return m_body.size() == *content_length;
532 }
533}
534
535void HTTPRequest::WriteReply(HTTPStatusCode status, std::span<const std::byte> reply_body)
536{
537 HTTPResponse res;
538
539 // Some response headers are determined in advance and stored in the request
540 res.headers = std::move(m_response_headers);
541
542 // Response version matches request version
543 res.version = m_version;
544
545 // Add response code
546 res.status = status;
547
548 // See libevent evhttp_response_needs_body()
549 // Response headers are different if no body is needed
550 bool needs_body{status != HTTP_NO_CONTENT && (status < 100 || status >= 200)};
551 bool needs_content_length{false};
552
553 bool keep_alive{false};
554
555 // See libevent evhttp_make_header_response()
556 // Expected response headers depend on protocol version
557 if (m_version.major == 1) {
558 // HTTP/1.0
559 if (m_version.minor == 0) {
560 auto connection_header{m_headers.FindFirst("Connection")};
561 if (connection_header && ToLower(connection_header.value()) == "keep-alive") {
562 res.headers.Write("Connection", "keep-alive");
563 keep_alive = true;
564 // HTTP/1.0 connections are closed by default so EOF is sufficient
565 // to indicate end of the body. Adding Content-Length a special case.
566 if (needs_body) needs_content_length = true;
567 }
568 }
569
570 // HTTP/1.1
571 if (m_version.minor >= 1) {
572 const int64_t now_seconds{TicksSinceEpoch<std::chrono::seconds>(NodeClock::now())};
573 res.headers.Write("Date", FormatRFC1123DateTime(now_seconds));
574
575 // HTTP/1.1 connections are kept alive by default and always require Content-Length.
576 if (needs_body) needs_content_length = true;
577
578 // Default for HTTP/1.1
579 keep_alive = true;
580 }
581 }
582
583 if (needs_content_length) {
584 res.headers.Write("Content-Length", util::ToString(reply_body.size()));
585 }
586
587 if (needs_body && !res.headers.FindFirst("Content-Type")) {
588 // Default type from libevent evhttp_new_object()
589 res.headers.Write("Content-Type", "text/html; charset=ISO-8859-1");
590 }
591
592 auto connection_header{m_headers.FindFirst("Connection")};
593 if (connection_header && ToLower(connection_header.value()) == "close") {
594 // Might not exist already but we need to replace it, not append to it
595 res.headers.RemoveAll("Connection");
596
597 res.headers.Write("Connection", "close");
598 keep_alive = false;
599 }
600
601 if (std::shared_ptr client{m_client.lock()}) {
602 client->Send(res, reply_body, keep_alive);
603 }
604}
605
606void HTTPRemoteClient::Send(const HTTPResponse& res, std::span<const std::byte> reply_body, bool keep_alive)
607{
608 m_keep_alive = keep_alive;
609
610 // Serialize the response headers
611 const std::string headers{res.StringifyHeaders()};
612 const auto headers_bytes{std::as_bytes(std::span{headers})};
613
614 bool send_buffer_was_empty{false};
615 // Fill the send buffer with the complete serialized response headers + body
616 {
618 send_buffer_was_empty = m_send_buffer.empty();
619 m_send_buffer.insert(m_send_buffer.end(), headers_bytes.begin(), headers_bytes.end());
620
621 // We've been using std::span up until now but it is finally time to copy
622 // data. The original data will go out of scope when WriteReply() returns.
623 // This is analogous to the memcpy() in libevent's evbuffer_add()
624 m_send_buffer.insert(m_send_buffer.end(), reply_body.begin(), reply_body.end());
625
626 // If the buffer already held data, the I/O thread is (or soon will be)
627 // draining it, so flag that there is more data to send. This must happen
628 // while holding m_send_mutex and while the buffer is known non-empty:
629 // setting m_send_ready after releasing the lock would race with the I/O
630 // thread draining the buffer to empty and clearing m_send_ready in
631 // between, leaving m_send_ready set on an empty buffer. The I/O loop would
632 // then only ever poll the socket for writeability, never read the client's
633 // next request, and wedge the connection.
634 if (!send_buffer_was_empty) m_send_ready = true;
635 }
636
637 LogDebug(
639 "HTTPResponse (status code: %d size: %lld) added to send buffer for client %s (id=%llu)",
640 res.status,
641 headers_bytes.size() + reply_body.size(),
642 m_origin,
643 m_id);
644
645 // If the send buffer was empty before we wrote this reply, we can try an
646 // optimistic send akin to CConnman::PushMessage() in which we
647 // push the data directly out the socket to client right now, instead
648 // of waiting for the next iteration of the I/O loop.
649 if (send_buffer_was_empty) {
651 }
652
653 // Signal to the I/O loop that we are ready to handle the next request.
654 m_req_busy = false;
655}
656
658{
659 if (std::shared_ptr c{m_client.lock()}) {
660 return c->GetPeer();
661 } else {
662 return {};
663 }
664}
665
666std::optional<std::string> HTTPRequest::GetQueryParameter(const std::string_view key) const
667{
669}
670
671// See libevent http.c evhttp_parse_query_impl()
672// and https://www.rfc-editor.org/rfc/rfc3986#section-3.4
673std::optional<std::string> GetQueryParameterFromUri(const std::string_view uri, const std::string_view key)
674{
675 // find query in URI
676 size_t start = uri.find('?');
677 if (start == std::string::npos) return std::nullopt;
678 size_t end = uri.find('#', start);
679 if (end == std::string::npos) {
680 end = uri.length();
681 }
682 const std::string_view query{uri.data() + start + 1, end - start - 1};
683 // find requested parameter in query
684 const std::vector<std::string_view> params{Split<std::string_view>(query, "&")};
685 for (const std::string_view& param : params) {
686 size_t delim = param.find('=');
687 if (key == UrlDecode(param.substr(0, delim))) {
688 if (delim == std::string::npos) {
689 return "";
690 } else {
691 return std::string(UrlDecode(param.substr(delim + 1)));
692 }
693 }
694 }
695 return std::nullopt;
696}
697
698std::optional<std::string> HTTPRequest::GetHeader(const std::string_view hdr) const
699{
700 return m_headers.FindFirst(hdr);
701}
702
703void HTTPRequest::WriteHeader(std::string&& hdr, std::string&& value)
704{
705 m_response_headers.Write(std::move(hdr), std::move(value));
706}
707
709{
710 // Create socket for listening for incoming connections
711 sockaddr_storage storage;
712 auto sa = reinterpret_cast<sockaddr*>(&storage);
713 socklen_t len{sizeof(storage)};
714 if (!to.GetSockAddr(sa, &len)) {
715 return util::Unexpected{strprintf("Bind address family for %s not supported", to.ToStringAddrPort())};
716 }
717
718 std::unique_ptr<Sock> sock{CreateSock(to.GetSAFamily(), SOCK_STREAM, IPPROTO_TCP)};
719 if (!sock) {
720 return util::Unexpected{strprintf("Cannot create %s listen socket: %s",
721 to.ToStringAddrPort(),
723 }
724
725#ifdef WIN32
726 // Prevent another application from binding to the same address and port and
727 // intercepting RPC credentials.
728 // SO_REUSEADDR on Windows is non-exclusive so another process could bind to
729 // the same port.
730 if (sock->SetSockOpt(SOL_SOCKET, SO_EXCLUSIVEADDRUSE, &SOCKET_OPTION_TRUE, sizeof(SOCKET_OPTION_TRUE)) == SOCKET_ERROR) {
731 return util::Unexpected{strprintf("Cannot set SO_EXCLUSIVEADDRUSE on %s listen socket: %s",
732 to.ToStringAddrPort(),
734 }
735#else
736 // Allow binding if the port is still in TIME_WAIT state after
737 // the program was closed and restarted.
738 if (sock->SetSockOpt(SOL_SOCKET, SO_REUSEADDR, &SOCKET_OPTION_TRUE, sizeof(SOCKET_OPTION_TRUE)) == SOCKET_ERROR) {
740 "Cannot set SO_REUSEADDR on %s listen socket: %s, continuing anyway",
741 to.ToStringAddrPort(),
743 }
744#endif
745
746 // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
747 // and enable it by default or not. Try to enable it, if possible.
748 if (to.IsIPv6()) {
749#ifdef IPV6_V6ONLY
750 if (sock->SetSockOpt(IPPROTO_IPV6, IPV6_V6ONLY, &SOCKET_OPTION_TRUE, sizeof(SOCKET_OPTION_TRUE)) == SOCKET_ERROR) {
752 "Cannot set IPV6_V6ONLY on %s listen socket: %s, continuing anyway",
753 to.ToStringAddrPort(),
755 }
756#endif
757#ifdef WIN32
758 int prot_level{PROTECTION_LEVEL_UNRESTRICTED};
759 if (sock->SetSockOpt(IPPROTO_IPV6,
760 IPV6_PROTECTION_LEVEL,
761 &prot_level,
762 sizeof(prot_level)) == SOCKET_ERROR) {
764 "Cannot set IPV6_PROTECTION_LEVEL on %s listen socket: %s, continuing anyway",
765 to.ToStringAddrPort(),
767 }
768#endif
769 }
770
771 if (sock->Bind(sa, len) == SOCKET_ERROR) {
772 const int err{WSAGetLastError()};
773 if (err == WSAEADDRINUSE) {
774 return util::Unexpected{strprintf("Unable to bind to %s on this computer. %s is probably already running.",
775 to.ToStringAddrPort(),
776 CLIENT_NAME)};
777 } else {
778 return util::Unexpected{strprintf("Unable to bind to %s on this computer (bind returned error %s)",
779 to.ToStringAddrPort(),
780 NetworkErrorString(err))};
781 }
782 }
783
784 // Listen for incoming connections
785 if (sock->Listen(SOMAXCONN) == SOCKET_ERROR) {
786 return util::Unexpected{strprintf("Cannot listen on %s: %s",
787 to.ToStringAddrPort(),
789 }
790
791 m_listen.emplace_back(std::move(sock));
792
793 return {};
794}
795
797{
798 m_listen.clear();
799}
800
802{
803 // The socket handler reads m_allow_subnets in ClientAllowed(). InitHTTPAllowList()
804 // must have populated it first; localhost entries are always added, so an empty
805 // list means it was never called and every connection is rejected.
806 Assume(!m_allow_subnets.empty());
807
809 "http",
810 [this] { ThreadSocketHandler(); });
811}
812
814{
815 if (m_thread_socket_handler.joinable()) {
817 }
818}
819
820std::unique_ptr<Sock> HTTPServer::AcceptConnection(const Sock& listen_sock, CService& addr)
821{
822 // Make sure we only operate on our own listening sockets
823 Assume(std::ranges::any_of(m_listen, [&](const auto& sock) { return sock.get() == &listen_sock; }));
824
825 sockaddr_storage storage;
826 socklen_t len{sizeof(storage)};
827 auto sa = reinterpret_cast<sockaddr*>(&storage);
828
829 auto sock{listen_sock.Accept(sa, &len)};
830
831 if (!sock) {
832 const int err{WSAGetLastError()};
833 if (err != WSAEWOULDBLOCK) {
835 "Cannot accept new connection: %s",
836 NetworkErrorString(err));
837 }
838 return {};
839 }
840
841 // The OS handed us a valid socket but we can't determine its source address.
842 if (!addr.SetSockAddr(sa, len)) {
844 "Unknown socket family");
845 }
846
847 // Early address-based allow check
848 if (!ClientAllowed(addr)) {
849 LogDebug(BCLog::HTTP, "Connection from %s rejected: Client network is not allowed HTTP access\n",
850 addr.ToStringAddrPort());
851 // Socket destroyed, connection aborted
852 return {};
853 }
854
855 return sock;
856}
857
859{
860 return m_next_id.fetch_add(1, std::memory_order_relaxed);
861}
862
863void HTTPServer::NewSockAccepted(std::unique_ptr<Sock>&& sock, const CService& addr)
864{
865 if (!sock->IsSelectable()) {
867 "connection from %s dropped: non-selectable socket",
868 addr.ToStringAddrPort());
869 return;
870 }
871
872 // According to the internet TCP_NODELAY is not carried into accepted sockets
873 // on all platforms. Set it again here just to be sure.
874 if (sock->SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &SOCKET_OPTION_TRUE, sizeof(SOCKET_OPTION_TRUE)) == SOCKET_ERROR) {
875 LogDebug(BCLog::HTTP, "connection from %s: unable to set TCP_NODELAY, continuing anyway",
876 addr.ToStringAddrPort());
877 }
878
879 const Id id{GetNewId()};
880
881 m_connected.push_back(std::make_shared<HTTPRemoteClient>(id, addr, std::move(sock)));
882 // Report back to the main thread
883 m_connected_size.fetch_add(1, std::memory_order_relaxed);
884
886 "HTTP Connection accepted from %s (id=%llu)",
887 addr.ToStringAddrPort(), id);
888}
889
890void HTTPServer::SocketHandlerConnected(const IOReadiness& io_readiness) const
891{
892 for (const auto& [sock, events] : io_readiness.events_per_sock) {
893 if (m_interrupt_net) {
894 return;
895 }
896
897 auto it{io_readiness.httpclients_per_sock.find(sock)};
898 if (it == io_readiness.httpclients_per_sock.end()) {
899 continue;
900 }
901 const std::shared_ptr<HTTPRemoteClient>& client{it->second};
902
903 bool send_ready = events.occurred & Sock::SendEvent;
904 bool recv_ready = events.occurred & Sock::RecvEvent;
905 bool err_ready = events.occurred & Sock::ErrorEvent;
906
907 if (send_ready) {
908 // Try to send as much data as is ready for this client.
909 // If there's an error we can skip the receive phase for this client
910 // because we need to disconnect.
911 if (!client->MaybeSendBytesFromBuffer()) {
912 recv_ready = false;
913 }
914 }
915
916 if (recv_ready || err_ready) {
917 client->Receive();
918 }
919 // Process as much received data as we can.
920 // This executes for every client whether or not reading or writing
921 // took place because it also (might) parse a request we have already
922 // received and pass it to a worker thread.
923 if (std::unique_ptr<HTTPRequest> request{HTTPRemoteClient::TryReadRequest(client)})
924 {
926 m_request_dispatcher(std::move(request));
927 }
928 }
929}
930
932{
933 char buf[0x10000]; // typical socket buffer is 8K-64K
934
935 const ssize_t nrecv{WITH_LOCK(
937 return m_sock->Recv(buf, sizeof(buf), MSG_DONTWAIT);)};
938
939 if (nrecv < 0) {
940 const int err = WSAGetLastError();
941 if (IOErrorIsPermanent(err)) {
942 LogDebug(
944 "Permanent read error from %s (id=%llu): %s",
945 m_origin,
946 m_id,
947 NetworkErrorString(err));
948 m_disconnect = true;
949 }
950 } else if (nrecv == 0) {
951 LogDebug(
953 "Received EOF from %s (id=%llu)",
954 m_origin,
955 m_id);
956 m_disconnect = true;
957 } else {
958 // Reset idle timeout
960
961 // Prevent disconnect until all requests are completely handled.
962 m_connection_busy = true;
963
964 // Copy data from socket buffer to client receive buffer
965 m_recv_buffer.insert(
966 m_recv_buffer.end(),
967 buf,
968 buf + nrecv);
969
970 m_total_bytes_received += static_cast<uint64_t>(nrecv);
971 LogDebug(
973 "Received %d bytes from %s (id=%llu): total=%llu buffered=%zu",
974 nrecv,
975 m_origin,
976 m_id,
978 m_recv_buffer.size());
979 }
980}
981
983{
984 if (m_stop_accepting) return;
985 for (const auto& sock : m_listen) {
986 if (m_interrupt_net) {
987 return;
988 }
989 const auto it = events_per_sock.find(sock);
990 if (it != events_per_sock.end() && it->second.occurred & Sock::RecvEvent) {
991 // Drain all pending connections from this socket up to the limit.
992 // Stop early if the kernel queue is empty (AcceptConnection returns null)
993 // or if accepting the last connection brought us to the limit.
994 while (GetConnectionsCount() < static_cast<size_t>(m_rpcmaxconnections)) {
995 CService addr_accepted;
996 auto sock_accepted{AcceptConnection(*sock, addr_accepted)};
997 if (!sock_accepted) break;
998 NewSockAccepted(std::move(sock_accepted), addr_accepted);
999 }
1000 }
1001 }
1002}
1003
1005{
1006 IOReadiness io_readiness;
1007
1008 // If the server is already handling its max connected clients count,
1009 // don't bother checking the listening sockets for new inbound connections.
1010 // Leave them in the kernel's queue until space in the application opens
1011 // up (or the client times out on its own).
1012 if (GetConnectionsCount() < static_cast<size_t>(m_rpcmaxconnections)) {
1013 for (const auto& sock : m_listen) {
1014 io_readiness.events_per_sock.emplace(sock, Sock::Events{Sock::RecvEvent});
1015 }
1016 }
1017
1018 for (const auto& http_client : m_connected) {
1019 // Safely copy the shared pointer to the socket
1020 std::shared_ptr<Sock> sock{http_client->GetSock()};
1021
1022 // Event choice:
1023 // 1. ReadyToSend() (m_send_ready set) -> Send
1024 // m_send_ready stays set while the send buffer still has data to
1025 // drain, so we keep sending and do not Recv. This is also how the
1026 // send-throttle applies backpressure: while the send buffer is
1027 // full, TryReadRequest() holds a completed request back from a
1028 // worker, so nothing new is read until send has drained.
1029 // 2. Else, m_req is incomplete and needs more data, or there is no
1030 // m_req at all and the recv buffer is empty -> Recv
1031 // 3. Else (no parse in progress, leftover bytes in m_recv_buffer) -> 0
1032 // Stay in the I/O map so TryReadRequest() drains the buffer first.
1033 // Extra pipelined data waits in the kernel socket buffer
1034 // (TCP backpressure), not in m_recv_buffer.
1035 //
1036 // Lock-order safety: the convention established by
1037 // MaybeSendBytesFromBuffer() is to take m_send_mutex before m_sock_mutex.
1038 // In this loop GetSock() (above) takes m_sock_mutex and ReadyToSend()
1039 // (below) takes m_send_mutex; both are scoped, so each lock is released
1040 // before the next is taken and they stay separate critical sections.
1041 // Holding m_sock_mutex while acquiring m_send_mutex would invert that
1042 // order and risk a lock-order-inversion deadlock.
1043 Sock::Event event{0};
1044 if (http_client->ReadyToSend()) {
1045 event = Sock::SendEvent;
1046 } else if (http_client->GetRequest() != nullptr || http_client->ReceiveBufferEmpty()) {
1047 // Mid-parse (need more bytes) or buffer empty.
1048 event = Sock::RecvEvent;
1049 }
1050
1051 io_readiness.events_per_sock.emplace(sock, Sock::Events{event});
1052 io_readiness.httpclients_per_sock.emplace(sock, http_client);
1053 }
1054
1055 return io_readiness;
1056}
1057
1060{
1061 while (!m_interrupt_net) {
1062 // Check for the readiness of the already connected sockets and the
1063 // listening sockets in one call ("readiness" as in poll(2) or
1064 // select(2)). If none are ready, wait for a short while and return
1065 // empty sets.
1066 auto io_readiness{GenerateWaitSockets()};
1067 if (io_readiness.events_per_sock.empty() ||
1068 // WaitMany() may as well be a static method, the context of the first Sock in the vector is not relevant.
1069 !io_readiness.events_per_sock.begin()->first->WaitMany(SELECT_TIMEOUT,
1070 io_readiness.events_per_sock)) {
1072 }
1073
1074 // Service (send/receive) each of the already connected sockets.
1075 SocketHandlerConnected(io_readiness);
1076
1077 // Accept new connections from listening sockets.
1078 SocketHandlerListening(io_readiness.events_per_sock);
1079
1080 // Disconnect any clients that have been flagged.
1082 }
1083}
1084
1085std::unique_ptr<HTTPRequest> HTTPRemoteClient::TryReadRequest(const std::shared_ptr<HTTPRemoteClient>& client)
1086{
1087 // If we are already handling a request from
1088 // this client, do nothing. We'll check again on the next I/O
1089 // loop iteration.
1090 if (client->m_req_busy) return nullptr;
1091
1092 if (!client->m_req) {
1093 client->m_req = std::make_unique<HTTPRequest>(client);
1094 }
1095
1096 try {
1097 // Read data from the buffer into the current request
1098 client->ReadRequest(*client->m_req);
1099 } catch (const ContentTooLargeError& e) {
1100 LogDebug(
1102 "HTTP request body too large from client %s (id=%llu): %s",
1103 client->m_origin,
1104 client->m_id,
1105 e.what());
1106
1108 client->m_disconnect = true;
1109 return nullptr;
1110 } catch (const std::runtime_error& e) {
1111 LogDebug(
1113 "Error reading HTTP request from client %s (id=%llu): %s",
1114 client->m_origin,
1115 client->m_id,
1116 e.what());
1117
1118 // We failed to read a complete request from the buffer
1120 client->m_disconnect = true;
1121 return nullptr;
1122 }
1123
1124 // If the request is ready, hand it to a worker.
1125 if (client->m_req->GetState() == HTTPRequest::State::Complete) {
1126 // Unless this client's send buffer is full: in that case hold the
1127 // parsed request here instead of moving it to a worker. This prevents
1128 // the server from reading any more data from this client until they
1129 // drain their end of the socket, and prevents the server from packing
1130 // more responses into the send buffer.
1131 const size_t buffer_used{WITH_LOCK(
1132 client->m_send_mutex,
1133 return client->m_send_buffer.size();)};
1134 if (buffer_used > MAX_BODY_SIZE) return nullptr;
1135 LogDebug(
1137 "Received a %s request for %s from %s (id=%llu)",
1138 RequestMethodString(client->m_req->GetRequestMethod()),
1139 client->m_req->GetURI(),
1140 client->m_origin,
1141 client->m_id);
1142
1143 client->m_req_busy = true;
1144 return std::move(client->m_req);
1145 }
1146
1147 return nullptr;
1148}
1149
1151{
1152 const auto now{Now<SteadySeconds>()};
1153 size_t erased = std::erase_if(m_connected,
1154 [&](auto& client) {
1155 return client->MaybeDisconnect(now,
1157 /*disconnect_all=*/m_disconnect_all_clients);
1158 });
1159 if (erased > 0) {
1160 // Report back to the main thread
1161 m_connected_size.fetch_sub(erased, std::memory_order_relaxed);
1162 }
1163}
1164
1165bool HTTPRemoteClient::MaybeDisconnect(std::chrono::time_point<SteadyClock> now, std::chrono::seconds rpcservertimeout, bool disconnect_all)
1166{
1167 // First check for idle timeout. We reset the timer when we send and receive data,
1168 // but if the server is busy handling a request we should ignore the timeout until
1169 // the reply is sent. If we did erase the shared_ptr<HTTPRemoteClient> reference in m_connected
1170 // while the server is busy with a request, it might be prematurely dropped before
1171 // the response has been sent, or if the HTTPRequest was holding a temporary shared_ptr
1172 // client on a worker thread - it would keep the socket open even after "disconnecting".
1173 const bool is_idle{rpcservertimeout.count() > 0 &&
1174 now - m_idle_since.load() > rpcservertimeout &&
1175 !m_req_busy};
1176
1177 // Disconnect this client due to error, end of communication, or idle timeout.
1178 // May drop unsent data if we are closing due to error.
1179 if (m_disconnect || is_idle) {
1180 if (is_idle) {
1182 "HTTP client idle timeout %s (id=%llu)",
1183 m_origin,
1184 m_id);
1185 }
1186 } else {
1187 // Disconnect this client because the server is shutting
1188 // down and we need to disconnect all clients...
1189 if (disconnect_all) {
1190 // ...unless we still have data for this client.
1191 if (m_connection_busy) {
1192 // There is still data for this healthy-connected client.
1193 // Continue the I/O loop until all data is sent or an error is encountered.
1194 return false;
1195 } else {
1196 // This is a healthy persistent connection (e.g. keep-alive)
1197 // but it's time to say goodbye.
1198 ;
1199 }
1200 } else {
1201 // No reason to disconnect.
1202 return false;
1203 }
1204 }
1205 // No reason NOT to disconnect, log and remove.
1207 "Disconnecting HTTP client %s (id=%llu)",
1208 m_origin,
1209 m_id);
1210 return true;
1211}
1212
1214{
1215 Assume(!m_thread_socket_handler.joinable()); // must be called after JoinSocketsThreads()
1216 if (m_connected.empty()) return;
1217 LogWarning("Force-disconnecting %d HTTP client(s) that did not disconnect gracefully", m_connected.size());
1218 m_connected_size.fetch_sub(m_connected.size(), std::memory_order_relaxed);
1219 m_connected.clear();
1220}
1221
1223{
1224 if (m_recv_buffer.empty()) return;
1225
1227
1228 try {
1229 switch (req.GetState()) {
1230 case HTTPRequest::State::Init:
1231 if (!req.LoadControlData(reader)) break;
1232 req.SetState(HTTPRequest::State::NeedsHeaders);
1233 [[fallthrough]];
1234
1235 case HTTPRequest::State::NeedsHeaders:
1236 if (!req.LoadHeaders(reader)) break;
1237 req.SetState(HTTPRequest::State::NeedsBody);
1238 [[fallthrough]];
1239
1240 case HTTPRequest::State::NeedsBody:
1241 if (!req.LoadBody(reader)) break;
1242 req.SetState(HTTPRequest::State::Complete);
1243 [[fallthrough]];
1244
1245 case HTTPRequest::State::Complete:
1246 break;
1247
1248 case HTTPRequest::State::Error:
1249 break;
1250 }
1251 } catch (...) {
1252 // Don't try to read any more data for this request
1253 req.SetState(HTTPRequest::State::Error);
1254 // Clear the memory allocated to this client, caller must disconnect
1255 m_recv_buffer.clear();
1256 throw;
1257 }
1258
1259 // Remove the bytes read out of the buffer.
1260 m_recv_buffer.erase(
1261 m_recv_buffer.begin(),
1262 m_recv_buffer.begin() + reader.Consumed());
1263}
1264
1266{
1267 // Send as much data from this client's buffer as we can
1269 if (!m_send_buffer.empty()) {
1270 // Socket flags (See kernel docs for send(2) and tcp(7) for more details).
1271 // MSG_NOSIGNAL: If the remote end of the connection is closed,
1272 // fail with EPIPE (an error) as opposed to triggering
1273 // SIGPIPE which terminates the process.
1274 // MSG_DONTWAIT: Makes the send operation non-blocking regardless of socket blocking mode.
1275 // MSG_MORE: We do not set this flag here because http responses are usually
1276 // small and we want the kernel to send them right away. Setting MSG_MORE
1277 // would "cork" the socket to prevent sending out partial frames.
1278 int flags{MSG_NOSIGNAL | MSG_DONTWAIT};
1279
1280 // Try to send bytes through socket
1281 ssize_t bytes_sent;
1282 {
1284 bytes_sent = m_sock->Send(m_send_buffer.data(),
1285 m_send_buffer.size(),
1286 flags);
1287 }
1288
1289 if (bytes_sent < 0) {
1290 // Something went wrong
1291 const int err{WSAGetLastError()};
1292 if (!IOErrorIsPermanent(err)) {
1293 // The error can be safely ignored, try the send again on the next I/O loop.
1294 m_send_ready = true;
1295 m_connection_busy = true;
1296 return true;
1297 } else {
1298 // Unrecoverable error, log and disconnect client.
1299 LogDebug(
1301 "Error sending HTTP response data to client %s (id=%llu): %s",
1302 m_origin,
1303 m_id,
1304 NetworkErrorString(err));
1305 m_send_ready = false;
1306 m_disconnect = true;
1307
1308 // Do not attempt to read from this client.
1309 return false;
1310 }
1311 }
1312
1313 // Successful send, remove sent bytes from our local buffer.
1314 Assume(static_cast<size_t>(bytes_sent) <= m_send_buffer.size());
1315 m_send_buffer.erase(m_send_buffer.begin(),
1316 m_send_buffer.begin() + bytes_sent);
1317
1318 LogDebug(
1320 "Sent %d bytes to client %s (id=%llu)",
1321 bytes_sent,
1322 m_origin,
1323 m_id);
1324
1325 // This check is inside the if(!empty) block meaning "there was data but now its gone".
1326 // We wouldn't want to change the flags if MaybeSendBytesFromBuffer() was called
1327 // on an already-empty m_send_buffer because the connection might have just been opened.
1328 if (m_send_buffer.empty()) {
1329 m_send_ready = false;
1330 m_connection_busy = false;
1331
1332 // Our work is done here
1333 if (!m_keep_alive) {
1334 m_disconnect = true;
1335 // Do not attempt to read from this client.
1336 return false;
1337 }
1338 } else {
1339 // The send buffer isn't flushed yet, try to push more on the next loop.
1340 m_send_ready = true;
1341 m_connection_busy = true;
1342 }
1343
1344 // Finally, reset idle timeout
1346 }
1347
1348 return true;
1349}
1350
1352{
1353 // Create HTTPServer
1354 g_http_server = std::make_unique<HTTPServer>(MaybeDispatchRequestToWorker);
1355
1356 if (!g_http_server->InitHTTPAllowList()) {
1357 return false;
1358 }
1359
1360 g_http_server->SetServerTimeout(std::chrono::seconds(gArgs.GetIntArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT)));
1361 g_http_server->SetMaxConnections(std::max(gArgs.GetArg<int>("-rpcmaxconnections", DEFAULT_MAX_HTTP_CONNECTIONS), 1));
1362
1363 // Bind HTTP server to specified addresses
1364 std::vector<std::pair<std::string, uint16_t>> endpoints{GetBindAddresses()};
1365 bool bind_success{false};
1366 for (const auto& [address_string, port] : endpoints) {
1367 LogInfo("Binding RPC on address %s port %i", address_string, port);
1368 const std::optional<CService> addr{Lookup(address_string, port, false)};
1369 if (addr) {
1370 if (addr->IsBindAny()) {
1371 LogWarning("The RPC server is not safe to expose to untrusted networks such as the public internet");
1372 }
1373 auto result{g_http_server->BindAndStartListening(addr.value())};
1374 if (!result) {
1375 LogWarning("Binding RPC on address %s failed: %s", addr->ToStringAddrPort(), result.error());
1376 } else {
1377 bind_success = true;
1378 }
1379 } else {
1380 LogWarning("Could not bind RPC on address %s port %i: Address lookup failed.", address_string, port);
1381 }
1382 }
1383
1384 if (!bind_success) {
1385 LogError("Unable to bind any endpoint for RPC server");
1386 return false;
1387 }
1388
1389 LogDebug(BCLog::HTTP, "Initialized HTTP server");
1390
1391 g_max_queue_depth = std::max(gArgs.GetArg<int>("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1);
1392 LogDebug(BCLog::HTTP, "set work queue of depth %d\n", g_max_queue_depth);
1393
1394 return true;
1395}
1396
1398{
1399 auto rpcThreads{std::max(gArgs.GetArg<int>("-rpcthreads", DEFAULT_HTTP_THREADS), 1)};
1400 LogInfo("Starting HTTP server with %d worker threads", rpcThreads);
1401 g_threadpool_http.Start(rpcThreads);
1402 g_http_server->StartSocketsThreads();
1403}
1404
1406{
1407 LogDebug(BCLog::HTTP, "Interrupting HTTP server");
1408 if (g_http_server) {
1409 // Reject all new requests
1410 g_http_server->SetRequestHandler(RejectRequest);
1411 }
1412
1413 // Interrupt pool after disabling requests
1415}
1416
1418{
1419 LogDebug(BCLog::HTTP, "Stopping HTTP server");
1420
1421 LogDebug(BCLog::HTTP, "Waiting for HTTP worker threads to exit\n");
1423
1424 if (g_http_server) {
1425 // Must precede DisconnectAllClients(): a connection accepted after
1426 // GetConnectionsCount() returns 0 would survive into the destructor.
1427 g_http_server->StopAccepting();
1428 // Disconnect clients as their remaining responses are flushed
1429 g_http_server->DisconnectAllClients();
1430 // Wait 30 seconds for all disconnections
1431 LogDebug(BCLog::HTTP, "Waiting for HTTP clients to disconnect gracefully");
1432 const auto deadline{NodeClock::now() + 30s};
1433 while (g_http_server->GetConnectionsCount() != 0) {
1434 if (NodeClock::now() > deadline) {
1435 LogWarning("Timeout waiting for HTTP clients to disconnect gracefully, continuing shutdown");
1436 break;
1437 }
1438 std::this_thread::sleep_for(50ms);
1439 }
1440 // Break HTTPServer I/O loop: stop accepting connections, sending and receiving data
1441 g_http_server->InterruptNet();
1442 // Wait for HTTPServer I/O thread to exit
1443 g_http_server->JoinSocketsThreads();
1444 // Force-remove any clients that survived the graceful wait
1445 g_http_server->ClearConnectedClients();
1446 // Close all listening sockets
1447 g_http_server->StopListening();
1448 }
1449 LogDebug(BCLog::HTTP, "Stopped HTTP server");
1450}
ArgsManager gArgs
Definition args.cpp:38
int ret
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.
Network address.
Definition netaddress.h:113
bool IsValid() const
bool IsIPv6() const
Definition netaddress.h:159
A combination of a network address (CNetAddr) and a (TCP) port.
Definition netaddress.h:531
bool SetSockAddr(const struct sockaddr *paddr, socklen_t addrlen)
Set CService from a network sockaddr.
sa_family_t GetSAFamily() const
Get the address family.
bool GetSockAddr(struct sockaddr *paddr, socklen_t *addrlen) const
Obtain the IPv4/6 socket address this represents.
std::string ToStringAddrPort() const
bool IsValid() const
virtual bool sleep_for(Clock::duration rel_time) EXCLUSIVE_LOCKS_REQUIRED(!mut)
Sleep for the given duration.
Different type to mark Mutex at global scope.
Definition sync.h:142
std::optional< std::string > FindFirst(std::string_view key) const
size_t m_consumed
Track total bytes consumed in Read() for limit checks.
Definition httpserver.h:130
void RemoveAll(std::string_view key)
std::vector< std::pair< std::string, std::string > > m_headers
Headers can have duplicate field names, so we use a vector of key-value pairs instead of a map.
Definition httpserver.h:127
bool Read(util::LineReader &reader, bool write=true)
std::string Stringify() const
void Write(std::string &&key, std::string &&value)
std::vector< std::string_view > FindAll(std::string_view key) const
std::atomic_bool m_disconnect
Definition httpserver.h:632
uint64_t m_total_bytes_received
Running total of bytes read from this client's socket.
Definition httpserver.h:567
Mutex m_send_mutex
Response data destined for this client.
Definition httpserver.h:584
void Send(const HTTPResponse &res, std::span< const std::byte > reply_body, bool keep_alive) EXCLUSIVE_LOCKS_REQUIRED(!m_send_mutex
const std::string m_origin
IP:port of connected client, cached for logging purposes.
Definition httpserver.h:557
static std::unique_ptr< HTTPRequest > TryReadRequest(const std::shared_ptr< HTTPRemoteClient > &client) EXCLUSIVE_LOCKS_REQUIRED(!client -> m_send_mutex)
Try to read an HTTPRequest from a client's receive buffer.
bool MaybeDisconnect(std::chrono::time_point< SteadyClock > now, std::chrono::seconds rpcservertimeout, bool disconnect_all)
const HTTPServer::Id m_id
ID provided by HTTPServer upon connection and instantiation.
Definition httpserver.h:551
std::string m_recv_buffer
In lieu of an intermediate transport class like p2p uses, we copy data from the socket buffer to the ...
Definition httpserver.h:564
void ReadRequest(HTTPRequest &req)
Try to read an HTTP request from the receive buffer.
std::atomic< SteadySeconds > m_idle_since
Definition httpserver.h:637
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:603
std::atomic_bool m_connection_busy
Definition httpserver.h:620
void Receive() EXCLUSIVE_LOCKS_REQUIRED(!m_sock_mutex)
std::atomic_bool m_keep_alive
Definition httpserver.h:625
std::atomic_bool m_req_busy
Definition httpserver.h:577
void WriteHeader(std::string &&hdr, std::string &&value)
std::optional< uint64_t > m_chunk_size
Definition httpserver.h:222
std::optional< std::string > GetQueryParameter(std::string_view key) const
std::string GetURI() const
Definition httpserver.h:186
std::string m_target
Definition httpserver.h:208
bool LoadHeaders(util::LineReader &reader)
HTTPHeaders m_headers
Definition httpserver.h:210
bool LoadControlData(util::LineReader &reader)
Methods that attempt to parse HTTP request fields line-by-line from a receive buffer.
HTTPVersion m_version
Definition httpserver.h:209
uint64_t m_chunk_read
Definition httpserver.h:225
std::weak_ptr< HTTPRemoteClient > m_client
Pointer to the client that made the request so we know who to respond to.
Definition httpserver.h:214
std::optional< std::string > GetHeader(std::string_view hdr) const
HTTPRequestMethod m_method
Definition httpserver.h:207
std::string m_body
Definition httpserver.h:211
bool LoadBody(util::LineReader &reader)
void SetState(State state)
Definition httpserver.h:204
void WriteReply(HTTPStatusCode status, std::span< const std::byte > reply_body={})
State GetState() const
Definition httpserver.h:203
CService GetPeer() const
HTTPHeaders m_response_headers
Response headers may be set in advance before response body is known.
Definition httpserver.h:217
std::atomic< Id > m_next_id
The id to assign to the next created connection.
Definition httpserver.h:339
void ThreadSocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_request_dispatcher_mutex)
Check connected and listening sockets for IO readiness and process them accordingly.
void JoinSocketsThreads()
Join (wait for) the threads started by StartSocketsThreads() to exit.
std::vector< std::shared_ptr< HTTPRemoteClient > > m_connected
List of HTTPRemoteClients with connected sockets.
Definition httpserver.h:347
int m_rpcmaxconnections
Maximum amount of concurrent connections.
Definition httpserver.h:432
CThreadInterrupt m_interrupt_net
This is signaled when network activity should cease.
Definition httpserver.h:396
void SocketHandlerConnected(const IOReadiness &io_readiness) const EXCLUSIVE_LOCKS_REQUIRED(!m_request_dispatcher_mutex)
Do the read/write for connected sockets that are ready for IO.
std::atomic_bool m_disconnect_all_clients
Flag used during shutdown.
Definition httpserver.h:360
Id GetNewId()
Generate an id for a newly created connection.
void DisconnectClients()
Close underlying socket connections for flagged clients by removing their shared pointer from m_conne...
util::Expected< void, std::string > BindAndStartListening(const CService &to)
Bind to a new address:port, start listening and add the listen socket to m_listen.
std::vector< CSubNet > m_allow_subnets
List of subnets to allow HTTP connections from.
Definition httpserver.h:422
void ClearConnectedClients()
Force-remove all remaining clients from m_connected without waiting for graceful disconnection.
std::atomic< size_t > m_connected_size
The number of connected sockets.
Definition httpserver.h:367
std::vector< std::shared_ptr< Sock > > m_listen
List of listening sockets.
Definition httpserver.h:334
std::atomic_bool m_stop_accepting
Flag used during shutdown to stop accepting new connections.
Definition httpserver.h:353
void SocketHandlerListening(const Sock::EventsPerSock &events_per_sock)
Accept incoming connections, one from each read-ready listening socket.
IOReadiness GenerateWaitSockets() const
Generate a collection of sockets to check for IO readiness.
std::thread m_thread_socket_handler
Thread that sends to and receives from sockets and accepts connections.
Definition httpserver.h:402
uint64_t Id
Each connection is assigned an unique id of this type.
Definition httpserver.h:236
std::chrono::seconds m_rpcservertimeout
Idle timeout after which clients are disconnected.
Definition httpserver.h:417
void StopListening()
Stop listening by closing all listening sockets.
size_t GetConnectionsCount() const
Get the number of HTTPRemoteClients we are connected to.
Definition httpserver.h:273
void NewSockAccepted(std::unique_ptr< Sock > &&sock, const CService &addr)
After a new socket with a client has been created, configure its flags, make a new HTTPRemoteClient a...
bool ClientAllowed(const CNetAddr &netaddr) const
Check an incoming connection's source IP against the allow list.
bool InitHTTPAllowList()
Parse the user's -rpcallowip settings and populate m_allow_subnets.
Mutex m_request_dispatcher_mutex
Definition httpserver.h:410
std::unique_ptr< Sock > AcceptConnection(const Sock &listen_sock, CService &addr)
Accept a connection.
void StartSocketsThreads()
Start the necessary threads for sockets IO.
RAII helper class that manages a socket and closes it automatically when it goes out of scope.
Definition sock.h:35
static constexpr Event RecvEvent
If passed to Wait(), then it will wait for readiness to read from the socket.
Definition sock.h:151
virtual std::unique_ptr< Sock > Accept(sockaddr *addr, socklen_t *addr_len) const
accept(2) wrapper.
Definition sock.cpp:73
uint8_t Event
Definition sock.h:146
static constexpr Event SendEvent
If passed to Wait(), then it will wait for readiness to send to the socket.
Definition sock.h:156
static constexpr Event ErrorEvent
Ignored if passed to Wait(), but could be set in the occurred events if an exceptional condition has ...
Definition sock.h:162
std::unordered_map< std::shared_ptr< const Sock >, Events, HashSharedPtrSock, EqualSharedPtrSock > EventsPerSock
On which socket to wait for what events in WaitMany().
Definition sock.h:216
Fixed-size thread pool for running arbitrary tasks concurrently.
Definition threadpool.h:48
void Start(int num_workers) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Start worker threads.
Definition threadpool.h:105
util::Expected< Future< F >, SubmitError > Submit(F &&fn) noexcept EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Enqueues a new task for asynchronous execution.
Definition threadpool.h:184
void Stop() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Stop all worker threads and wait for them to exit.
Definition threadpool.h:128
void Interrupt() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Stop accepting new tasks and begin asynchronous shutdown.
Definition threadpool.h:268
size_t WorkQueueSize() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Definition threadpool.h:274
The util::Expected class provides a standard way for low-level functions to return either error value...
Definition expected.h:44
size_t Consumed() const
Returns number of bytes already read from buffer.
Definition string.cpp:85
std::optional< std::string_view > ReadLine() LIFETIMEBOUND
Returns a string from current iterator position up to (but not including) next and advances iterator...
Definition string.cpp:35
size_t Remaining() const
Returns remaining size of bytes in buffer.
Definition string.cpp:80
std::string_view ReadLength(size_t len) LIFETIMEBOUND
Returns string from current iterator position of specified length if possible and advances iterator o...
Definition string.cpp:71
The util::Unexpected class represents an unexpected value stored in util::Expected.
Definition expected.h:21
#define WSAEWOULDBLOCK
Definition compat.h:61
#define SOCKET_ERROR
Definition compat.h:68
#define WSAGetLastError()
Definition compat.h:59
#define MSG_NOSIGNAL
Definition compat.h:110
#define MSG_DONTWAIT
Definition compat.h:115
#define WSAEADDRINUSE
Definition compat.h:66
static std::vector< std::pair< std::string, uint16_t > > GetBindAddresses()
static void WriteNoStoreErrorReply(HTTPRequest &req, HTTPStatusCode status, std::string_view reply={})
void InterruptHTTPServer()
Interrupt HTTP server threads.
static ThreadPool g_threadpool_http("http")
Http thread pool - future: encapsulate in HttpContext
void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
Unregister handler for prefix.
void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
Register handler for prefix.
void StartHTTPServer()
Start HTTP server.
static void RejectRequest(std::unique_ptr< HTTPRequest > hreq)
std::string_view RequestMethodString(HTTPRequestMethod m)
HTTP request method as string - use for logging only.
bool InitHTTPServer()
Initialize HTTP server.
static void MaybeDispatchRequestToWorker(std::shared_ptr< HTTPRequest > hreq)
std::optional< std::string > GetQueryParameterFromUri(const std::string_view uri, const std::string_view key)
static constexpr auto SELECT_TIMEOUT
static std::unique_ptr< HTTPServer > g_http_server
HTTP module state.
static constexpr int SOCKET_OPTION_TRUE
Explicit alias for setting socket option methods.
static int g_max_queue_depth
void StopHTTPServer()
Stop HTTP server.
static GlobalMutex g_httppathhandlers_mutex
Handlers for (sub)paths.
bilingual_str InvalidPortErrMsg(const std::string &optname, const std::string &invalid_value)
Definition messages.cpp:148
constexpr int DEFAULT_MAX_HTTP_CONNECTIONS
Maximum number of connected HTTP clients.
Definition httpserver.h:47
std::function< void(HTTPRequest *req, const std::string &)> HTTPRequestHandler
Handler for requests to a certain HTTP path.
Definition httpserver.h:60
constexpr int DEFAULT_HTTP_SERVER_TIMEOUT
Definition httpserver.h:42
constexpr int DEFAULT_HTTP_THREADS
The default value for -rpcthreads.
Definition httpserver.h:34
constexpr int DEFAULT_HTTP_WORKQUEUE
The default value for -rpcworkqueue.
Definition httpserver.h:40
HTTPRequestMethod
Definition httpserver.h:49
std::optional< std::string > GetQueryParameterFromUri(std::string_view uri, std::string_view key)
HTTPRequest req
LineReader reader("GET / HTTP/1.0\r\nHost: ", MAX_HEADERS_SIZE)
const std::string request
CClientUIInterface uiInterface
#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
constexpr uint64_t MAX_BODY_SIZE
Definition httpserver.h:82
constexpr size_t MIN_REQUEST_LINE_LENGTH
Shortest valid request line, used by libevent in evhttp_parse_request_line().
Definition httpserver.h:72
constexpr size_t MAX_HEADERS_SIZE
Definition httpserver.h:78
bilingual_str InvalidPortErrMsg(const std::string &optname, const std::string &invalid_value)
Definition messages.cpp:148
std::vector< T > Split(std::span< const char > sp LIFETIMEBOUND, std::string_view separators, bool include_sep=false)
Split a string on any char found in separators, returning a vector.
Definition string.h:120
void TraceThread(std::string_view thread_name, std::function< void()> thread_func)
A wrapper for do-something-once thread functions.
Definition thread.cpp:15
std::string_view TrimStringView(std::string_view str LIFETIMEBOUND, std::string_view pattern=" \f\n\r\t\v")
Definition string.h:163
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition string.h:250
std::string TrimString(std::string_view str, std::string_view pattern=" \f\n\r\t\v")
Definition string.h:173
CSubNet LookupSubNet(const std::string &subnet_str)
Parse and resolve a specified subnet string into the appropriate internal representation.
Definition netbase.cpp:831
std::vector< CNetAddr > LookupHost(const std::string &name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
Resolve a host string to its corresponding network addresses.
Definition netbase.cpp:173
std::vector< CService > Lookup(const std::string &name, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function)
Resolve a service string to its corresponding service.
Definition netbase.cpp:191
std::function< std::unique_ptr< Sock >(int, int, int)> CreateSock
Socket factory.
Definition netbase.cpp:577
std::string_view HTTPStatusReasonString(HTTPStatusCode code)
Definition protocol.h:28
HTTPStatusCode
HTTP status codes.
Definition protocol.h:13
@ HTTP_BAD_REQUEST
Definition protocol.h:16
@ HTTP_BAD_METHOD
Definition protocol.h:20
@ HTTP_CONTENT_TOO_LARGE
Definition protocol.h:21
@ HTTP_SERVICE_UNAVAILABLE
Definition protocol.h:23
@ HTTP_NOT_FOUND
Definition protocol.h:19
@ HTTP_NO_CONTENT
Definition protocol.h:15
@ HTTP_INTERNAL_SERVER_ERROR
Definition protocol.h:22
std::string NetworkErrorString(int err)
Return readable error string for a network error code.
Definition sock.cpp:433
bool IOErrorIsPermanent(int err)
Definition sock.h:26
std::optional< T > ToIntegral(std::string_view str, size_t base=10)
Convert string to integral type T.
std::string prefix
HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler)
HTTPRequestHandler handler
HTTPVersion version
Definition httpserver.h:145
std::string StringifyHeaders() const
HTTPHeaders headers
Definition httpserver.h:147
Info about which socket has which event ready and a reverse map back to the HTTPRemoteClient that own...
Definition httpserver.h:373
std::unordered_map< Sock::EventsPerSock::key_type, std::shared_ptr< HTTPRemoteClient >, Sock::HashSharedPtrSock, Sock::EqualSharedPtrSock > httpclients_per_sock
Map of socket -> HTTPRemoteClient.
Definition httpserver.h:390
Sock::EventsPerSock events_per_sock
Map of socket -> socket events.
Definition httpserver.h:379
uint8_t minor
Definition httpserver.h:140
uint8_t major
Default HTTP protocol version 1.1 is used by error responses when a request is unreadable.
Definition httpserver.h:139
static time_point now() noexcept
Return current system time or mocked time, if set.
Definition time.cpp:38
Auxiliary requested/occurred events to wait for in WaitMany().
Definition sock.h:181
#define LOCK(cs)
Definition sync.h:268
#define WITH_LOCK(cs, code)
Definition sync.h:299
constexpr std::string_view SubmitErrorString(const ThreadPool::SubmitError err) noexcept
Definition threadpool.h:285
#define GUARDED_BY(x)
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition translation.h:82
std::string UrlDecode(std::string_view url_encoded)
Definition url.cpp:13
bool CaseInsensitiveEqual(std::string_view s1, std::string_view s2)
Locale-independent, ASCII-only comparator.
bool SplitHostPort(std::string_view in, uint16_t &portOut, std::string &hostOut)
Splits socket address string into host string and port value.
std::string ToLower(std::string_view str)
Returns the lowercase equivalent of the given string.
std::string FormatRFC1123DateTime(int64_t time)
RFC1123 formatting https://www.rfc-editor.org/rfc/rfc1123#section-5.2.14 Used in HTTP/1....
Definition time.cpp:131
constexpr auto TicksSinceEpoch(Timepoint t)
Definition time.h:93
T Now()
Return the current time point cast to the given precision.
Definition time.h:127
assert(!tx.IsCoinBase())