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 <deque>
34#include <memory>
35#include <optional>
36#include <span>
37#include <string>
38#include <string_view>
39#include <thread>
40#include <unordered_map>
41#include <vector>
42
43#include <sys/types.h>
44#include <sys/stat.h>
45
48static constexpr auto SELECT_TIMEOUT{50ms};
49
51static constexpr int SOCKET_OPTION_TRUE{1};
52
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<http_bitcoin::HTTPServer> g_http_server{nullptr};
71static std::vector<CSubNet> rpc_allow_subnets;
74static std::vector<HTTPPathHandler> pathHandlers GUARDED_BY(g_httppathhandlers_mutex);
78static int g_max_queue_depth{100};
79
81static bool ClientAllowed(const CNetAddr& netaddr)
82{
83 if (!netaddr.IsValid())
84 return false;
85 for(const CSubNet& subnet : rpc_allow_subnets)
86 if (subnet.Match(netaddr))
87 return true;
88 return false;
89}
90
92static bool InitHTTPAllowList()
93{
94 rpc_allow_subnets.clear();
95 rpc_allow_subnets.emplace_back(LookupHost("127.0.0.1", false).value(), 8); // always allow IPv4 local subnet
96 rpc_allow_subnets.emplace_back(LookupHost("::1", false).value()); // always allow IPv6 localhost
97 for (const std::string& strAllow : gArgs.GetArgs("-rpcallowip")) {
98 const CSubNet subnet{LookupSubNet(strAllow)};
99 if (!subnet.IsValid()) {
101 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)),
103 return false;
104 }
105 rpc_allow_subnets.push_back(subnet);
106 }
107 std::string strAllowed;
108 for (const CSubNet& subnet : rpc_allow_subnets)
109 strAllowed += subnet.ToString() + " ";
110 LogDebug(BCLog::HTTP, "Allowing HTTP connections from: %s\n", strAllowed);
111 return true;
112}
113
116{
117 switch (m) {
118 using enum HTTPRequestMethod;
119 case GET: return "GET";
120 case POST: return "POST";
121 case HEAD: return "HEAD";
122 case PUT: return "PUT";
123 case UNKNOWN: return "unknown";
124 } // no default case, so the compiler can warn about missing cases
125 assert(false);
126}
127
128static void MaybeDispatchRequestToWorker(std::shared_ptr<HTTPRequest> hreq)
129{
130 // Early address-based allow check
131 if (!ClientAllowed(hreq->GetPeer())) {
132 LogDebug(BCLog::HTTP, "HTTP request from %s rejected: Client network is not allowed RPC access\n",
133 hreq->GetPeer().ToStringAddrPort());
134 hreq->WriteReply(HTTP_FORBIDDEN);
135 return;
136 }
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());
142 hreq->WriteReply(HTTP_BAD_METHOD);
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 hreq->WriteReply(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.
187 req->WriteReply(HTTP_INTERNAL_SERVER_ERROR, err_msg);
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 hreq->WriteReply(HTTP_SERVICE_UNAVAILABLE, "Request rejected during server shutdown");
195 return;
196 }
197 } else {
198 hreq->WriteReply(HTTP_NOT_FOUND);
199 }
200}
201
202static void RejectRequest(std::unique_ptr<http_bitcoin::HTTPRequest> hreq)
203{
204 LogDebug(BCLog::HTTP, "Rejecting request while shutting down");
205 hreq->WriteReply(HTTP_SERVICE_UNAVAILABLE);
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
263namespace http_bitcoin {
264using util::Split;
265
266std::optional<std::string> HTTPHeaders::FindFirst(const std::string_view key) const
267{
268 for (const auto& item : m_headers) {
269 if (CaseInsensitiveEqual(key, item.first)) {
270 return item.second;
271 }
272 }
273 return std::nullopt;
274}
275
276std::vector<std::string_view> HTTPHeaders::FindAll(const std::string_view key) const
277{
278 std::vector<std::string_view> ret;
279 for (const auto& item : m_headers) {
280 if (CaseInsensitiveEqual(key, item.first)) {
281 ret.push_back(item.second);
282 }
283 }
284 return ret;
285}
286
287void HTTPHeaders::Write(std::string&& key, std::string&& value)
288{
289 m_headers.emplace_back(std::move(key), std::move(value));
290}
291
292void HTTPHeaders::RemoveAll(std::string_view key)
293{
294 auto moved = std::ranges::remove_if(m_headers, [key] (auto& pair) {
295 return CaseInsensitiveEqual(key, pair.first);
296 });
297 m_headers.erase(moved.begin(), moved.end());
298}
299
301{
302 // Headers https://httpwg.org/specs/rfc9110.html#rfc.section.6.3
303 // A sequence of Field Lines https://httpwg.org/specs/rfc9110.html#rfc.section.5.2
304 while (auto maybe_line = reader.ReadLine()) {
305 if (reader.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()) return true;
311
312 // "Field values containing CR, LF, or NUL characters are invalid and dangerous"
313 // https://httpwg.org/specs/rfc9110.html#rfc.section.5.5
314 // A sender MUST NOT generate a bare CR (a CR character not immediately followed by LF)
315 // within any protocol elements other than the content.
316 // A recipient of such a bare CR MUST consider that element to be invalid...
317 // https://httpwg.org/specs/rfc9112.html#rfc.section.2.2
318 if (line.find_first_of("\r\n\0", 0, 3) != std::string_view::npos) throw std::runtime_error("Header contains invalid character");
319
320 // Header line must have at least one ":"
321 // keys are not allowed to have delimiters like ":" but values are
322 // https://httpwg.org/specs/rfc9110.html#rfc.section.5.6.2
323 const size_t pos{line.find(':')};
324 if (pos == std::string_view::npos) throw std::runtime_error("HTTP header missing colon (:)");
325
326 // Whitespace is strictly not allowed in the field-name (key)
327 // https://www.rfc-editor.org/rfc/rfc9110.html#section-5.6.2
328 std::string_view key = line.substr(0, pos);
329 if (key.find_first_of(" \t\n\r\f\v") != std::string_view::npos) throw std::runtime_error("Invalid header field-name contains whitespace");
330 // Whitespace is optional in the value and can be trimmed
331 std::string value = util::TrimString(std::string_view(line).substr(pos + 1));
332
333 // Header keys are Field Names: https://httpwg.org/specs/rfc9110.html#fields.names
334 // which consist of "tokens": https://httpwg.org/specs/rfc9110.html#rfc.section.5.6.2
335 // that can not be empty.
336 if (key.empty()) throw std::runtime_error("Empty HTTP header name");
337
338 Write(std::string(key), std::move(value));
339 }
340
341 return false;
342}
343
344std::string HTTPHeaders::Stringify() const
345{
346 std::string out;
347 for (const auto& [key, value] : m_headers) {
348 out += key + ": " + value + "\r\n";
349 }
350
351 // Headers are terminated by an empty line
352 out += "\r\n";
353
354 return out;
355}
356
358{
359 return strprintf("HTTP/%d.%d %d %s\r\n%s",
362 m_status,
365}
366
368{
369 auto maybe_line = reader.ReadLine();
370 if (!maybe_line) return false;
371 const std::string_view& request_line = *maybe_line;
372
373 // Request Line aka Control Data https://httpwg.org/specs/rfc9110.html#rfc.section.6.2
374 // Three words separated by spaces, terminated by \n or \r\n
375 if (request_line.length() < MIN_REQUEST_LINE_LENGTH) throw std::runtime_error("HTTP request line too short");
376
377 // NUL is not a valid tchar and would silently truncate
378 // C-string-based parsers rather than being rejected as malformed.
379 // tchar: https://www.rfc-editor.org/info/rfc7230/#section-3.2.6
380 if (request_line.find('\0') != std::string_view::npos) throw std::runtime_error("Invalid request line contains NUL");
381
382 const std::vector<std::string_view> parts{Split<std::string_view>(request_line, " ")};
383 if (parts.size() != 3) throw std::runtime_error("HTTP request line malformed");
384
385 if (parts[0] == "GET") {
387 } else if (parts[0] == "POST") {
389 } else if (parts[0] == "HEAD") {
391 } else if (parts[0] == "PUT") {
393 } else {
395 }
396
397 m_target = parts[1];
398
399 if (parts[2].rfind("HTTP/") != 0) throw std::runtime_error("HTTP request line malformed");
400
401 // Version is exactly two decimal digits separated by a decimal point
402 // https://httpwg.org/specs/rfc9110.html#rfc.section.2.5
403 const std::vector<std::string_view> version_parts{Split<std::string_view>(parts[2].substr(5), ".")};
404 if (version_parts.size() != 2) throw std::runtime_error("HTTP request line malformed");
405 if (version_parts[0].size() != 1 || version_parts[1].size() != 1) throw std::runtime_error("HTTP bad version");
406 auto major = ToIntegral<uint8_t>(version_parts[0]);
407 auto minor = ToIntegral<uint8_t>(version_parts[1]);
408 if (!major || !minor || major != 1 || minor > 9) throw std::runtime_error("HTTP bad version");
409 m_version.major = major.value();
410 m_version.minor = minor.value();
411
412 return true;
413}
414
416{
417 return m_headers.Read(reader);
418}
419
421{
422 // https://httpwg.org/specs/rfc9112.html#message.body
423 auto transfer_encoding_header = m_headers.FindFirst("Transfer-Encoding");
424 if (transfer_encoding_header && ToLower(transfer_encoding_header.value()) == "chunked") {
425 // Transfer-Encoding: https://datatracker.ietf.org/doc/html/rfc7230.html#section-3.3.1
426 // Chunked Transfer Coding: https://datatracker.ietf.org/doc/html/rfc7230.html#section-4.1
427 // see evhttp_handle_chunked_read() in libevent http.c
428 while (reader.Remaining() > 0) {
429 auto maybe_chunk_size = reader.ReadLine();
430 if (!maybe_chunk_size) return false;
431
432 // Allow (but ignore) Chunk Extensions
433 // See https://www.rfc-editor.org/rfc/rfc9112.html#name-chunk-extensions
434 std::string_view chunk_size_noext{maybe_chunk_size.value()};
435 const auto semicolon_pos = chunk_size_noext.find(';');
436 if (semicolon_pos != chunk_size_noext.npos) {
437 chunk_size_noext.remove_suffix(chunk_size_noext.size() - semicolon_pos);
438 }
439
440 const auto chunk_size{ToIntegral<uint64_t>(util::TrimStringView(chunk_size_noext), /*base=*/16)};
441 if (!chunk_size) throw std::runtime_error("Cannot parse chunk length value");
442
443 if ((m_body.size() > MAX_BODY_SIZE) ||
444 (*chunk_size > MAX_BODY_SIZE - m_body.size()))
445 throw ContentTooLargeError("Chunk will exceed max body size");
446
447 // Last chunk has size 0
448 if (*chunk_size == 0) {
449 // Allow (but ignore) Chunked Trailer section, by
450 // reading CRLF-terminated lines until we read an empty line,
451 // which indicates the end of this request.
452 // See https://httpwg.org/specs/rfc9112.html#rfc.section.7.1.2
453 const size_t trailer_start{reader.Consumed()};
454 while (true) {
455 auto maybe_trailer = reader.ReadLine();
456 if (reader.Consumed() - trailer_start > MAX_HEADERS_SIZE) {
457 throw std::runtime_error("HTTP chunked trailer exceeds size limit");
458 }
459 if (!maybe_trailer) return false;
460 if (maybe_trailer->empty()) break;
461 }
462 // Complete request has been parsed, reader is now pointing
463 // to beginning of next request or end of the buffer.
464 return true;
465 }
466
467 // We are still expecting more data for this chunk
468 if (reader.Remaining() < *chunk_size) {
469 return false;
470 }
471
472 // Pack chunk onto body
473 m_body += reader.ReadLength(*chunk_size);
474
475 // Even though every chunk size is explicitly declared,
476 // they are still terminated by a CRLF we don't need,
477 // just consume it here.
478 auto crlf = reader.ReadLine();
479 if (!crlf) {
480 // CRLF not found before end of buffer: it has not been received by our socket yet.
481 return false;
482 }
483 // CRLF was found but there was unexpected data after the chunk_sized chunk
484 if (!crlf.value().empty()) throw std::runtime_error("Improperly terminated chunk");
485 }
486
487 // We read all the chunks but never got the last chunk, wait for client to send more
488 return false;
489 } else {
490 // No Content-length or Transfer-Encoding header means no body, see libevent evhttp_get_body()
491 auto content_length_values{m_headers.FindAll("Content-Length")};
492 if (content_length_values.empty()) return true;
493
494 // Duplicate Content-Length headers are allowed only if they all have the same value
495 // https://www.rfc-editor.org/rfc/rfc7230#section-3.3.3
496 const auto& first_content_length_value{content_length_values[0]};
497 for (size_t i = 1; i < content_length_values.size(); ++i) {
498 if (content_length_values[i] != first_content_length_value) throw std::runtime_error("Differing Content-Length values");
499 }
500
501 const auto content_length{ToIntegral<uint64_t>(first_content_length_value)};
502 if (!content_length) throw std::runtime_error("Cannot parse Content-Length value");
503
504 if (*content_length > MAX_BODY_SIZE) throw ContentTooLargeError("Max body size exceeded");
505
506 // Not enough data in buffer for expected body
507 if (reader.Remaining() < *content_length) return false;
508
509 m_body = reader.ReadLength(*content_length);
510
511 return true;
512 }
513}
514
515void HTTPRequest::WriteReply(HTTPStatusCode status, std::span<const std::byte> reply_body)
516{
517 HTTPResponse res;
518
519 // Some response headers are determined in advance and stored in the request
520 res.m_headers = std::move(m_response_headers);
521
522 // Response version matches request version
523 res.m_version = m_version;
524
525 // Add response code
526 res.m_status = status;
527
528 // See libevent evhttp_response_needs_body()
529 // Response headers are different if no body is needed
530 bool needs_body{status != HTTP_NO_CONTENT && (status < 100 || status >= 200)};
531 bool needs_content_length{false};
532
533 bool keep_alive{false};
534
535 // See libevent evhttp_make_header_response()
536 // Expected response headers depend on protocol version
537 if (m_version.major == 1) {
538 // HTTP/1.0
539 if (m_version.minor == 0) {
540 auto connection_header{m_headers.FindFirst("Connection")};
541 if (connection_header && ToLower(connection_header.value()) == "keep-alive") {
542 res.m_headers.Write("Connection", "keep-alive");
543 keep_alive = true;
544 // HTTP/1.0 connections are closed by default so EOF is sufficient
545 // to indicate end of the body. Adding Content-Length a special case.
546 if (needs_body) needs_content_length = true;
547 }
548 }
549
550 // HTTP/1.1
551 if (m_version.minor >= 1) {
552 const int64_t now_seconds{TicksSinceEpoch<std::chrono::seconds>(NodeClock::now())};
553 res.m_headers.Write("Date", FormatRFC1123DateTime(now_seconds));
554
555 // HTTP/1.1 connections are kept alive by default and always require Content-Length.
556 if (needs_body) needs_content_length = true;
557
558 // Default for HTTP/1.1
559 keep_alive = true;
560 }
561 }
562
563 if (needs_content_length) {
564 res.m_headers.Write("Content-Length", util::ToString(reply_body.size()));
565 }
566
567 if (needs_body && !res.m_headers.FindFirst("Content-Type")) {
568 // Default type from libevent evhttp_new_object()
569 res.m_headers.Write("Content-Type", "text/html; charset=ISO-8859-1");
570 }
571
572 auto connection_header{m_headers.FindFirst("Connection")};
573 if (connection_header && ToLower(connection_header.value()) == "close") {
574 // Might not exist already but we need to replace it, not append to it
575 res.m_headers.RemoveAll("Connection");
576
577 res.m_headers.Write("Connection", "close");
578 keep_alive = false;
579 }
580
581 m_client->m_keep_alive = keep_alive;
582
583 // Serialize the response headers
584 const std::string headers{res.StringifyHeaders()};
585 const auto headers_bytes{std::as_bytes(std::span{headers})};
586
587 bool send_buffer_was_empty{false};
588 // Fill the send buffer with the complete serialized response headers + body
589 {
590 LOCK(m_client->m_send_mutex);
591 send_buffer_was_empty = m_client->m_send_buffer.empty();
592 m_client->m_send_buffer.insert(m_client->m_send_buffer.end(), headers_bytes.begin(), headers_bytes.end());
593
594 // We've been using std::span up until now but it is finally time to copy
595 // data. The original data will go out of scope when WriteReply() returns.
596 // This is analogous to the memcpy() in libevent's evbuffer_add()
597 m_client->m_send_buffer.insert(m_client->m_send_buffer.end(), reply_body.begin(), reply_body.end());
598 }
599
600 LogDebug(
602 "HTTPResponse (status code: %d size: %lld) added to send buffer for client %s (id=%llu)",
603 status,
604 headers_bytes.size() + reply_body.size(),
605 m_client->m_origin,
606 m_client->m_id);
607
608 // If the send buffer was empty before we wrote this reply, we can try an
609 // optimistic send akin to CConnman::PushMessage() in which we
610 // push the data directly out the socket to client right now, instead
611 // of waiting for the next iteration of the I/O loop.
612 if (send_buffer_was_empty) {
613 m_client->MaybeSendBytesFromBuffer();
614 } else {
615 // Inform HTTPServer I/O that data is ready to be sent to this client
616 // in the next loop iteration.
617 m_client->m_send_ready = true;
618 }
619
620 // Signal to the I/O loop that we are ready to handle the next request.
621 m_client->m_req_busy = false;
622}
623
625{
626 return m_client->m_addr;
627}
628
629std::optional<std::string> HTTPRequest::GetQueryParameter(const std::string_view key) const
630{
632}
633
634// See libevent http.c evhttp_parse_query_impl()
635// and https://www.rfc-editor.org/rfc/rfc3986#section-3.4
636std::optional<std::string> GetQueryParameterFromUri(const std::string_view uri, const std::string_view key)
637{
638 // find query in URI
639 size_t start = uri.find('?');
640 if (start == std::string::npos) return std::nullopt;
641 size_t end = uri.find('#', start);
642 if (end == std::string::npos) {
643 end = uri.length();
644 }
645 const std::string_view query{uri.data() + start + 1, end - start - 1};
646 // find requested parameter in query
647 const std::vector<std::string_view> params{Split<std::string_view>(query, "&")};
648 for (const std::string_view& param : params) {
649 size_t delim = param.find('=');
650 if (key == UrlDecode(param.substr(0, delim))) {
651 if (delim == std::string::npos) {
652 return "";
653 } else {
654 return std::string(UrlDecode(param.substr(delim + 1)));
655 }
656 }
657 }
658 return std::nullopt;
659}
660
661std::pair<bool, std::string> HTTPRequest::GetHeader(const std::string_view hdr) const
662{
663 std::optional<std::string> found{m_headers.FindFirst(hdr)};
664 return std::pair{found.has_value(), std::move(found).value_or("")};
665}
666
667void HTTPRequest::WriteHeader(std::string&& hdr, std::string&& value)
668{
669 m_response_headers.Write(std::move(hdr), std::move(value));
670}
671
673{
674 // Create socket for listening for incoming connections
675 sockaddr_storage storage;
676 auto sa = reinterpret_cast<sockaddr*>(&storage);
677 socklen_t len{sizeof(storage)};
678 if (!to.GetSockAddr(sa, &len)) {
679 return util::Unexpected{strprintf("Bind address family for %s not supported", to.ToStringAddrPort())};
680 }
681
682 std::unique_ptr<Sock> sock{CreateSock(to.GetSAFamily(), SOCK_STREAM, IPPROTO_TCP)};
683 if (!sock) {
684 return util::Unexpected{strprintf("Cannot create %s listen socket: %s",
685 to.ToStringAddrPort(),
687 }
688
689 // Allow binding if the port is still in TIME_WAIT state after
690 // the program was closed and restarted.
691 if (sock->SetSockOpt(SOL_SOCKET, SO_REUSEADDR, &SOCKET_OPTION_TRUE, sizeof(SOCKET_OPTION_TRUE)) == SOCKET_ERROR) {
693 "Cannot set SO_REUSEADDR on %s listen socket: %s, continuing anyway",
694 to.ToStringAddrPort(),
696 }
697
698 // some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
699 // and enable it by default or not. Try to enable it, if possible.
700 if (to.IsIPv6()) {
701#ifdef IPV6_V6ONLY
702 if (sock->SetSockOpt(IPPROTO_IPV6, IPV6_V6ONLY, &SOCKET_OPTION_TRUE, sizeof(SOCKET_OPTION_TRUE)) == SOCKET_ERROR) {
704 "Cannot set IPV6_V6ONLY on %s listen socket: %s, continuing anyway",
705 to.ToStringAddrPort(),
707 }
708#endif
709#ifdef WIN32
710 int prot_level{PROTECTION_LEVEL_UNRESTRICTED};
711 if (sock->SetSockOpt(IPPROTO_IPV6,
712 IPV6_PROTECTION_LEVEL,
713 &prot_level,
714 sizeof(prot_level)) == SOCKET_ERROR) {
716 "Cannot set IPV6_PROTECTION_LEVEL on %s listen socket: %s, continuing anyway",
717 to.ToStringAddrPort(),
719 }
720#endif
721 }
722
723 if (sock->Bind(sa, len) == SOCKET_ERROR) {
724 const int err{WSAGetLastError()};
725 if (err == WSAEADDRINUSE) {
726 return util::Unexpected{strprintf("Unable to bind to %s on this computer. %s is probably already running.",
727 to.ToStringAddrPort(),
728 CLIENT_NAME)};
729 } else {
730 return util::Unexpected{strprintf("Unable to bind to %s on this computer (bind returned error %s)",
731 to.ToStringAddrPort(),
732 NetworkErrorString(err))};
733 }
734 }
735
736 // Listen for incoming connections
737 if (sock->Listen(SOMAXCONN) == SOCKET_ERROR) {
738 return util::Unexpected{strprintf("Cannot listen on %s: %s",
739 to.ToStringAddrPort(),
741 }
742
743 m_listen.emplace_back(std::move(sock));
744
745 return {};
746}
747
749{
750 m_listen.clear();
751}
752
754{
756 "http",
757 [this] { ThreadSocketHandler(); });
758}
759
761{
762 if (m_thread_socket_handler.joinable()) {
764 }
765}
766
767std::unique_ptr<Sock> HTTPServer::AcceptConnection(const Sock& listen_sock, CService& addr)
768{
769 // Make sure we only operate on our own listening sockets
770 Assume(std::ranges::any_of(m_listen, [&](const auto& sock) { return sock.get() == &listen_sock; }));
771
772 sockaddr_storage storage;
773 socklen_t len{sizeof(storage)};
774 auto sa = reinterpret_cast<sockaddr*>(&storage);
775
776 auto sock{listen_sock.Accept(sa, &len)};
777
778 if (!sock) {
779 const int err{WSAGetLastError()};
780 if (err != WSAEWOULDBLOCK) {
782 "Cannot accept new connection: %s",
783 NetworkErrorString(err));
784 }
785 return {};
786 }
787
788 // The OS handed us a valid socket but we can't determine its source address.
789 // In the unlikely event this occurs, the invalid address will be rejected
790 // by the downstream ClientAllowed() check.
791 if (!addr.SetSockAddr(sa, len)) {
793 "Unknown socket family");
794 }
795
796 return sock;
797}
798
800{
801 return m_next_id.fetch_add(1, std::memory_order_relaxed);
802}
803
804void HTTPServer::NewSockAccepted(std::unique_ptr<Sock>&& sock, const CService& addr)
805{
806 if (!sock->IsSelectable()) {
808 "connection from %s dropped: non-selectable socket",
809 addr.ToStringAddrPort());
810 return;
811 }
812
813 // According to the internet TCP_NODELAY is not carried into accepted sockets
814 // on all platforms. Set it again here just to be sure.
815 if (sock->SetSockOpt(IPPROTO_TCP, TCP_NODELAY, &SOCKET_OPTION_TRUE, sizeof(SOCKET_OPTION_TRUE)) == SOCKET_ERROR) {
816 LogDebug(BCLog::HTTP, "connection from %s: unable to set TCP_NODELAY, continuing anyway",
817 addr.ToStringAddrPort());
818 }
819
820 const Id id{GetNewId()};
821
822 m_connected.push_back(std::make_shared<HTTPRemoteClient>(id, addr, std::move(sock)));
823 // Report back to the main thread
824 m_connected_size.fetch_add(1, std::memory_order_relaxed);
825
827 "HTTP Connection accepted from %s (id=%llu)",
828 addr.ToStringAddrPort(), id);
829}
830
831void HTTPServer::SocketHandlerConnected(const IOReadiness& io_readiness) const
832{
833 for (const auto& [sock, events] : io_readiness.events_per_sock) {
834 if (m_interrupt_net) {
835 return;
836 }
837
838 auto it{io_readiness.httpclients_per_sock.find(sock)};
839 if (it == io_readiness.httpclients_per_sock.end()) {
840 continue;
841 }
842 const std::shared_ptr<HTTPRemoteClient>& client{it->second};
843
844 bool send_ready = events.occurred & Sock::SendEvent;
845 bool recv_ready = events.occurred & Sock::RecvEvent;
846 bool err_ready = events.occurred & Sock::ErrorEvent;
847
848 if (send_ready) {
849 // Try to send as much data as is ready for this client.
850 // If there's an error we can skip the receive phase for this client
851 // because we need to disconnect.
852 if (!client->MaybeSendBytesFromBuffer()) {
853 recv_ready = false;
854 }
855 }
856
857 if (recv_ready || err_ready) {
858 std::byte buf[0x10000]; // typical socket buffer is 8K-64K
859
860 const ssize_t nrecv{WITH_LOCK(
861 client->m_sock_mutex,
862 return client->m_sock->Recv(buf, sizeof(buf), MSG_DONTWAIT);)};
863
864 if (nrecv < 0) {
865 const int err = WSAGetLastError();
866 if (IOErrorIsPermanent(err)) {
867 LogDebug(
869 "Permanent read error from %s (id=%llu): %s",
870 client->m_origin,
871 client->m_id,
872 NetworkErrorString(err));
873 client->m_disconnect = true;
874 }
875 } else if (nrecv == 0) {
876 LogDebug(
878 "Received EOF from %s (id=%llu)",
879 client->m_origin,
880 client->m_id);
881 client->m_disconnect = true;
882 } else {
883 // Reset idle timeout
884 client->m_idle_since = Now<SteadySeconds>();
885
886 // Prevent disconnect until all requests are completely handled.
887 client->m_connection_busy = true;
888
889 // Copy data from socket buffer to client receive buffer
890 client->m_recv_buffer.insert(
891 client->m_recv_buffer.end(),
892 buf,
893 buf + nrecv);
894 }
895 }
896 // Process as much received data as we can.
897 // This executes for every client whether or not reading or writing
898 // took place because it also (might) parse a request we have already
899 // received and pass it to a worker thread.
901 }
902}
903
905{
906 if (m_stop_accepting) return;
907 for (const auto& sock : m_listen) {
908 if (m_interrupt_net) {
909 return;
910 }
911 const auto it = events_per_sock.find(sock);
912 if (it != events_per_sock.end() && it->second.occurred & Sock::RecvEvent) {
913 CService addr_accepted;
914
915 auto sock_accepted{AcceptConnection(*sock, addr_accepted)};
916
917 if (sock_accepted) {
918 NewSockAccepted(std::move(sock_accepted), addr_accepted);
919 }
920 }
921 }
922}
923
925{
926 IOReadiness io_readiness;
927
928 for (const auto& sock : m_listen) {
929 io_readiness.events_per_sock.emplace(sock, Sock::Events{Sock::RecvEvent});
930 }
931
932 for (const auto& http_client : m_connected) {
933 // Safely copy the shared pointer to the socket
934 std::shared_ptr<Sock> sock{WITH_LOCK(http_client->m_sock_mutex, return http_client->m_sock;)};
935
936 // Check if client is ready to send data. Don't try to receive again
937 // until the send buffer is cleared (all data sent to client).
938 Sock::Event event = (http_client->m_send_ready ? Sock::SendEvent : Sock::RecvEvent);
939 io_readiness.events_per_sock.emplace(sock, Sock::Events{event});
940 io_readiness.httpclients_per_sock.emplace(sock, http_client);
941 }
942
943 return io_readiness;
944}
945
948{
949 while (!m_interrupt_net) {
950 // Check for the readiness of the already connected sockets and the
951 // listening sockets in one call ("readiness" as in poll(2) or
952 // select(2)). If none are ready, wait for a short while and return
953 // empty sets.
954 auto io_readiness{GenerateWaitSockets()};
955 if (io_readiness.events_per_sock.empty() ||
956 // WaitMany() may as well be a static method, the context of the first Sock in the vector is not relevant.
957 !io_readiness.events_per_sock.begin()->first->WaitMany(SELECT_TIMEOUT,
958 io_readiness.events_per_sock)) {
960 }
961
962 // Service (send/receive) each of the already connected sockets.
963 SocketHandlerConnected(io_readiness);
964
965 // Accept new connections from listening sockets.
966 SocketHandlerListening(io_readiness.events_per_sock);
967
968 // Disconnect any clients that have been flagged.
970 }
971}
972
973void HTTPServer::MaybeDispatchRequestsFromClient(const std::shared_ptr<HTTPRemoteClient>& client) const
974{
975 // Try reading (potentially multiple) HTTP requests from the buffer
976 while (!client->m_recv_buffer.empty()) {
977 // Create a new request object and try to fill it with data from the receive buffer
978 auto req = std::make_unique<HTTPRequest>(client);
979 try {
980 // Stop reading if we need more data from the client to parse a complete request
981 if (!client->ReadRequest(*req)) break;
982 } catch (const ContentTooLargeError& e) {
983 LogDebug(
985 "HTTP request body too large from client %s (id=%llu): %s",
986 client->m_origin,
987 client->m_id,
988 e.what());
989
990 req->WriteReply(HTTP_CONTENT_TOO_LARGE);
991 client->m_disconnect = true;
992 return;
993 } catch (const std::runtime_error& e) {
994 LogDebug(
996 "Error reading HTTP request from client %s (id=%llu): %s",
997 client->m_origin,
998 client->m_id,
999 e.what());
1000
1001 // We failed to read a complete request from the buffer
1002 req->WriteReply(HTTP_BAD_REQUEST);
1003 client->m_disconnect = true;
1004 return;
1005 }
1006
1007 // We read a complete request from the buffer into the queue
1008 LogDebug(
1010 "Received a %s request for %s from %s (id=%llu)",
1011 RequestMethodString(req->m_method),
1012 req->m_target,
1013 client->m_origin,
1014 client->m_id);
1015
1016 // add request to client queue
1017 client->m_req_queue.push_back(std::move(req));
1018 }
1019
1020 // If we are already handling a request from
1021 // this client, do nothing. We'll check again on the next I/O
1022 // loop iteration.
1023 if (client->m_req_busy) return;
1024
1025 // Otherwise, if there is a pending request in the queue, handle it.
1026 if (!client->m_req_queue.empty()) {
1028 client->m_req_busy = true;
1029 m_request_dispatcher(std::move(client->m_req_queue.front()));
1030 client->m_req_queue.pop_front();
1031 }
1032}
1033
1035{
1036 const auto now{Now<SteadySeconds>()};
1037 size_t erased = std::erase_if(m_connected,
1038 [&](auto& client) {
1039 // First check for idle timeout. We reset the timer when we send and receive data,
1040 // but if the server is busy handling a request we should ignore the timeout until
1041 // the reply is sent. If we did erase the shared_ptr<HTTPRemoteClient> reference in m_connected
1042 // while the server is busy with a request, there would still be a reference in a worker
1043 // thread keeping the socket open even after "disconnecting".
1044 const bool is_idle{m_rpcservertimeout.count() > 0 &&
1045 now - client->m_idle_since.load() > m_rpcservertimeout &&
1046 !client->m_req_busy};
1047
1048 // Disconnect this client due to error, end of communication, or idle timeout.
1049 // May drop unsent data if we are closing due to error.
1050 if (client->m_disconnect || is_idle) {
1051 if (is_idle) {
1052 LogDebug(BCLog::HTTP,
1053 "HTTP client idle timeout %s (id=%llu)",
1054 client->m_origin,
1055 client->m_id);
1056 }
1057 } else {
1058 // Disconnect this client because the server is shutting
1059 // down and we need to disconnect all clients...
1061 // ...unless we still have data for this client.
1062 if (client->m_connection_busy) {
1063 // There is still data for this healthy-connected client.
1064 // Continue the I/O loop until all data is sent or an error is encountered.
1065 return false;
1066 } else {
1067 // This is a healthy persistent connection (e.g. keep-alive)
1068 // but it's time to say goodbye.
1069 ;
1070 }
1071 } else {
1072 // No reason to disconnect.
1073 return false;
1074 }
1075 }
1076 // No reason NOT to disconnect, log and remove.
1078 "Disconnecting HTTP client %s (id=%llu)",
1079 client->m_origin,
1080 client->m_id);
1081 return true;
1082 });
1083 if (erased > 0) {
1084 // Report back to the main thread
1085 m_connected_size.fetch_sub(erased, std::memory_order_relaxed);
1086 }
1087}
1088
1089void HTTPServer::ClearConnectedClients()
1090{
1091 Assume(!m_thread_socket_handler.joinable()); // must be called after JoinSocketsThreads()
1092 if (m_connected.empty()) return;
1093 LogWarning("Force-disconnecting %d HTTP client(s) that did not disconnect gracefully", m_connected.size());
1094 m_connected_size.fetch_sub(m_connected.size(), std::memory_order_relaxed);
1095 m_connected.clear();
1096}
1097
1098bool HTTPRemoteClient::ReadRequest(HTTPRequest& req)
1099{
1100 LineReader reader(m_recv_buffer, MAX_HEADERS_SIZE);
1101
1102 if (!req.LoadControlData(reader)) return false;
1103 if (!req.LoadHeaders(reader)) return false;
1104 if (!req.LoadBody(reader)) return false;
1105
1106 // Remove the bytes read out of the buffer.
1107 // If one of the above calls throws an error, the caller must
1108 // catch it and disconnect the client.
1109 m_recv_buffer.erase(
1110 m_recv_buffer.begin(),
1111 m_recv_buffer.begin() + reader.Consumed());
1112
1113 return true;
1114}
1115
1116bool HTTPRemoteClient::MaybeSendBytesFromBuffer()
1117{
1118 // Send as much data from this client's buffer as we can
1119 LOCK(m_send_mutex);
1120 if (!m_send_buffer.empty()) {
1121 // Socket flags (See kernel docs for send(2) and tcp(7) for more details).
1122 // MSG_NOSIGNAL: If the remote end of the connection is closed,
1123 // fail with EPIPE (an error) as opposed to triggering
1124 // SIGPIPE which terminates the process.
1125 // MSG_DONTWAIT: Makes the send operation non-blocking regardless of socket blocking mode.
1126 // MSG_MORE: We do not set this flag here because http responses are usually
1127 // small and we want the kernel to send them right away. Setting MSG_MORE
1128 // would "cork" the socket to prevent sending out partial frames.
1130
1131 // Try to send bytes through socket
1132 ssize_t bytes_sent;
1133 {
1134 LOCK(m_sock_mutex);
1135 bytes_sent = m_sock->Send(m_send_buffer.data(),
1136 m_send_buffer.size(),
1137 flags);
1138 }
1139
1140 if (bytes_sent < 0) {
1141 // Something went wrong
1142 const int err{WSAGetLastError()};
1143 if (!IOErrorIsPermanent(err)) {
1144 // The error can be safely ignored, try the send again on the next I/O loop.
1145 m_send_ready = true;
1146 m_connection_busy = true;
1147 return true;
1148 } else {
1149 // Unrecoverable error, log and disconnect client.
1150 LogDebug(
1152 "Error sending HTTP response data to client %s (id=%llu): %s",
1153 m_origin,
1154 m_id,
1155 NetworkErrorString(err));
1156 m_send_ready = false;
1157 m_disconnect = true;
1158
1159 // Do not attempt to read from this client.
1160 return false;
1161 }
1162 }
1163
1164 // Successful send, remove sent bytes from our local buffer.
1165 Assume(static_cast<size_t>(bytes_sent) <= m_send_buffer.size());
1166 m_send_buffer.erase(m_send_buffer.begin(),
1167 m_send_buffer.begin() + bytes_sent);
1168
1169 LogDebug(
1171 "Sent %d bytes to client %s (id=%llu)",
1172 bytes_sent,
1173 m_origin,
1174 m_id);
1175
1176 // This check is inside the if(!empty) block meaning "there was data but now its gone".
1177 // We wouldn't want to change the flags if MaybeSendBytesFromBuffer() was called
1178 // on an already-empty m_send_buffer because the connection might have just been opened.
1179 if (m_send_buffer.empty()) {
1180 m_send_ready = false;
1181 m_connection_busy = false;
1182
1183 // Our work is done here
1184 if (!m_keep_alive) {
1185 m_disconnect = true;
1186 // Do not attempt to read from this client.
1187 return false;
1188 }
1189 } else {
1190 // The send buffer isn't flushed yet, try to push more on the next loop.
1191 m_send_ready = true;
1192 m_connection_busy = true;
1193 }
1194
1195 // Finally, reset idle timeout
1196 m_idle_since = Now<SteadySeconds>();
1197 }
1198
1199 return true;
1200}
1201
1203{
1204 if (!InitHTTPAllowList()) {
1205 return false;
1206 }
1207
1208 // Create HTTPServer
1209 g_http_server = std::make_unique<HTTPServer>(MaybeDispatchRequestToWorker);
1210
1211 g_http_server->SetServerTimeout(std::chrono::seconds(gArgs.GetIntArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT)));
1212
1213 // Bind HTTP server to specified addresses
1214 std::vector<std::pair<std::string, uint16_t>> endpoints{GetBindAddresses()};
1215 bool bind_success{false};
1216 for (const auto& [address_string, port] : endpoints) {
1217 LogInfo("Binding RPC on address %s port %i", address_string, port);
1218 const std::optional<CService> addr{Lookup(address_string, port, false)};
1219 if (addr) {
1220 if (addr->IsBindAny()) {
1221 LogWarning("The RPC server is not safe to expose to untrusted networks such as the public internet");
1222 }
1223 auto result{g_http_server->BindAndStartListening(addr.value())};
1224 if (!result) {
1225 LogWarning("Binding RPC on address %s failed: %s", addr->ToStringAddrPort(), result.error());
1226 } else {
1227 bind_success = true;
1228 }
1229 } else {
1230 LogWarning("Could not bind RPC on address %s port %i: Address lookup failed.", address_string, port);
1231 }
1232 }
1233
1234 if (!bind_success) {
1235 LogError("Unable to bind any endpoint for RPC server");
1236 return false;
1237 }
1238
1239 LogDebug(BCLog::HTTP, "Initialized HTTP server");
1240
1241 g_max_queue_depth = std::max(gArgs.GetArg<int>("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1);
1242 LogDebug(BCLog::HTTP, "set work queue of depth %d\n", g_max_queue_depth);
1243
1244 return true;
1245}
1246
1248{
1249 auto rpcThreads{std::max(gArgs.GetArg<int>("-rpcthreads", DEFAULT_HTTP_THREADS), 1)};
1250 LogInfo("Starting HTTP server with %d worker threads", rpcThreads);
1251 g_threadpool_http.Start(rpcThreads);
1252 g_http_server->StartSocketsThreads();
1253}
1254
1256{
1257 LogDebug(BCLog::HTTP, "Interrupting HTTP server");
1258 if (g_http_server) {
1259 // Reject all new requests
1260 g_http_server->SetRequestHandler(RejectRequest);
1261 }
1262
1263 // Interrupt pool after disabling requests
1265}
1266
1268{
1269 LogDebug(BCLog::HTTP, "Stopping HTTP server");
1270
1271 LogDebug(BCLog::HTTP, "Waiting for HTTP worker threads to exit\n");
1273
1274 if (g_http_server) {
1275 // Must precede DisconnectAllClients(): a connection accepted after
1276 // GetConnectionsCount() returns 0 would survive into the destructor.
1277 g_http_server->StopAccepting();
1278 // Disconnect clients as their remaining responses are flushed
1279 g_http_server->DisconnectAllClients();
1280 // Wait 30 seconds for all disconnections
1281 LogDebug(BCLog::HTTP, "Waiting for HTTP clients to disconnect gracefully");
1282 const auto deadline{NodeClock::now() + 30s};
1283 while (g_http_server->GetConnectionsCount() != 0) {
1284 if (NodeClock::now() > deadline) {
1285 LogWarning("Timeout waiting for HTTP clients to disconnect gracefully, continuing shutdown");
1286 break;
1287 }
1288 std::this_thread::sleep_for(50ms);
1289 }
1290 // Break HTTPServer I/O loop: stop accepting connections, sending and receiving data
1291 g_http_server->InterruptNet();
1292 // Wait for HTTPServer I/O thread to exit
1293 g_http_server->JoinSocketsThreads();
1294 // Force-remove any clients that survived the graceful wait
1295 g_http_server->ClearConnectedClients();
1296 // Close all listening sockets
1297 g_http_server->StopListening();
1298 }
1299 LogDebug(BCLog::HTTP, "Stopped HTTP server");
1300}
1301} // namespace http_bitcoin
ArgsManager gArgs
Definition: args.cpp:40
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:424
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:519
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Definition: args.h:324
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
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
void RemoveAll(std::string_view key)
Definition: httpserver.cpp:292
bool Read(util::LineReader &reader)
Definition: httpserver.cpp:300
std::vector< std::string_view > FindAll(std::string_view key) const
Definition: httpserver.cpp:276
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:122
std::string Stringify() const
Definition: httpserver.cpp:344
void Write(std::string &&key, std::string &&value)
Definition: httpserver.cpp:287
std::optional< std::string > FindFirst(std::string_view key) const
Definition: httpserver.cpp:266
HTTPHeaders m_response_headers
Response headers may be set in advance before response body is known.
Definition: httpserver.h:163
HTTPRequestMethod m_method
Definition: httpserver.h:153
std::optional< std::string > GetQueryParameter(std::string_view key) const
Definition: httpserver.cpp:629
bool LoadHeaders(LineReader &reader)
Definition: httpserver.cpp:415
std::pair< bool, std::string > GetHeader(std::string_view hdr) const
Definition: httpserver.cpp:661
void WriteHeader(std::string &&hdr, std::string &&value)
Definition: httpserver.cpp:667
std::shared_ptr< HTTPRemoteClient > m_client
Pointer to the client that made the request so we know who to respond to.
Definition: httpserver.h:160
CService GetPeer() const
Definition: httpserver.cpp:624
bool LoadControlData(LineReader &reader)
Methods that attempt to parse HTTP request fields line-by-line from a receive buffer.
Definition: httpserver.cpp:367
void WriteReply(HTTPStatusCode status, std::span< const std::byte > reply_body={})
Definition: httpserver.cpp:515
bool LoadBody(LineReader &reader)
Definition: httpserver.cpp:420
HTTPStatusCode m_status
Definition: httpserver.h:142
std::string StringifyHeaders() const
Definition: httpserver.cpp:357
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:804
void ThreadSocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_request_dispatcher_mutex)
Check connected and listening sockets for IO readiness and process them accordingly.
Definition: httpserver.cpp:947
std::vector< std::shared_ptr< Sock > > m_listen
List of listening sockets.
Definition: httpserver.h:294
CThreadInterrupt m_interrupt_net
This is signaled when network activity should cease.
Definition: httpserver.h:356
std::atomic_bool m_disconnect_all_clients
Flag used during shutdown.
Definition: httpserver.h:320
void DisconnectClients()
Close underlying socket connections for flagged clients by removing their shared pointer from m_conne...
void StopListening()
Stop listening by closing all listening sockets.
Definition: httpserver.cpp:748
void SocketHandlerListening(const Sock::EventsPerSock &events_per_sock)
Accept incoming connections, one from each read-ready listening socket.
Definition: httpserver.cpp:904
std::vector< std::shared_ptr< HTTPRemoteClient > > m_connected
List of HTTPRemoteClients with connected sockets.
Definition: httpserver.h:307
IOReadiness GenerateWaitSockets() const
Generate a collection of sockets to check for IO readiness.
Definition: httpserver.cpp:924
std::atomic< Id > m_next_id
The id to assign to the next created connection.
Definition: httpserver.h:299
void StartSocketsThreads()
Start the necessary threads for sockets IO.
Definition: httpserver.cpp:753
void MaybeDispatchRequestsFromClient(const std::shared_ptr< HTTPRemoteClient > &client) const EXCLUSIVE_LOCKS_REQUIRED(!m_request_dispatcher_mutex)
Try to read HTTPRequests from a client's receive buffer.
Definition: httpserver.cpp:973
void JoinSocketsThreads()
Join (wait for) the threads started by StartSocketsThreads() to exit.
Definition: httpserver.cpp:760
std::chrono::seconds m_rpcservertimeout
Idle timeout after which clients are disconnected.
Definition: httpserver.h:377
std::thread m_thread_socket_handler
Thread that sends to and receives from sockets and accepts connections.
Definition: httpserver.h:362
std::unique_ptr< Sock > AcceptConnection(const Sock &listen_sock, CService &addr)
Accept a connection.
Definition: httpserver.cpp:767
std::atomic< size_t > m_connected_size
The number of connected sockets.
Definition: httpserver.h:327
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:672
Id GetNewId()
Generate an id for a newly created connection.
Definition: httpserver.cpp:799
std::atomic_bool m_stop_accepting
Flag used during shutdown to stop accepting new connections.
Definition: httpserver.h:313
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:831
uint64_t Id
Each connection is assigned an unique id of this type.
Definition: httpserver.h:206
The util::Expected class provides a standard way for low-level functions to return either error value...
Definition: expected.h:44
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 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
std::string_view RequestMethodString(HTTPRequestMethod m)
HTTP request method as string - use for logging only.
Definition: httpserver.cpp:115
static void MaybeDispatchRequestToWorker(std::shared_ptr< HTTPRequest > hreq)
Definition: httpserver.cpp:128
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:48
static constexpr int SOCKET_OPTION_TRUE
Explicit alias for setting socket option methods.
Definition: httpserver.cpp:51
static bool InitHTTPAllowList()
Initialize ACL list for HTTP server.
Definition: httpserver.cpp:92
static int g_max_queue_depth
Definition: httpserver.cpp:78
static std::unique_ptr< http_bitcoin::HTTPServer > g_http_server
HTTP module state.
Definition: httpserver.cpp:69
static void RejectRequest(std::unique_ptr< http_bitcoin::HTTPRequest > hreq)
Definition: httpserver.cpp:202
static std::vector< CSubNet > rpc_allow_subnets
List of subnets to allow RPC connections from.
Definition: httpserver.cpp:71
static bool ClientAllowed(const CNetAddr &netaddr)
Check if a network address is allowed to access the HTTP server.
Definition: httpserver.cpp:81
static std::vector< HTTPPathHandler > pathHandlers GUARDED_BY(g_httppathhandlers_mutex)
static GlobalMutex g_httppathhandlers_mutex
Handlers for (sub)paths.
Definition: httpserver.cpp:73
static const int DEFAULT_HTTP_SERVER_TIMEOUT
Definition: httpserver.h:43
static const int DEFAULT_HTTP_WORKQUEUE
The default value for -rpcworkqueue.
Definition: httpserver.h:41
static const int DEFAULT_HTTP_THREADS
The default value for -rpcthreads.
Definition: httpserver.h:35
std::function< void(http_bitcoin::HTTPRequest *req, const std::string &)> HTTPRequestHandler
Handler for requests to a certain HTTP path.
Definition: httpserver.h:57
HTTPRequestMethod
Definition: httpserver.h:45
util::LineReader reader
HTTPHeaders headers
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
is a home for simple string functions returning descriptive messages that are used in RPC and GUI int...
@ HTTP
Definition: categories.h:19
bilingual_str InvalidPortErrMsg(const std::string &optname, const std::string &invalid_value)
Definition: messages.cpp:155
constexpr size_t MIN_REQUEST_LINE_LENGTH
Shortest valid request line, used by libevent in evhttp_parse_request_line()
Definition: httpserver.h:71
void StartHTTPServer()
Start HTTP server.
std::optional< std::string > GetQueryParameterFromUri(const std::string_view uri, const std::string_view key)
Definition: httpserver.cpp:636
constexpr uint64_t MAX_BODY_SIZE
Maximum size of an HTTP request body.
Definition: httpserver.h:80
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:77
void StopHTTPServer()
Stop HTTP server.
void InterruptHTTPServer()
Interrupt HTTP server threads.
bool InitHTTPServer()
Initialize HTTP server.
std::string_view TrimStringView(std::string_view str, std::string_view pattern=" \f\n\r\t\v")
Definition: string.h:162
void TraceThread(std::string_view thread_name, std::function< void()> thread_func)
A wrapper for do-something-once thread functions.
Definition: thread.cpp:15
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition: string.h:249
std::string TrimString(std::string_view str, std::string_view pattern=" \f\n\r\t\v")
Definition: string.h:172
std::vector< T > Split(const std::span< const char > &sp, std::string_view separators, bool include_sep=false)
Split a string on any char found in separators, returning a vector.
Definition: string.h:119
CSubNet LookupSubNet(const std::string &subnet_str)
Parse and resolve a specified subnet string into the appropriate internal representation.
Definition: netbase.cpp:831
std::vector< CNetAddr > LookupHost(const std::string &name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
Resolve a host string to its corresponding network addresses.
Definition: netbase.cpp:173
std::vector< CService > Lookup(const std::string &name, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function)
Resolve a service string to its corresponding service.
Definition: netbase.cpp:191
std::function< std::unique_ptr< Sock >(int, int, int)> CreateSock
Socket factory.
Definition: netbase.cpp:577
const char * prefix
Definition: rest.cpp:1143
bool(* handler)(const std::any &context, HTTPRequest *req, const std::string &strReq)
Definition: rest.cpp:1144
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_FORBIDDEN
Definition: protocol.h:16
@ 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
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:84
Info about which socket has which event ready and a reverse map back to the HTTPRemoteClient that own...
Definition: httpserver.h:333
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:350
Sock::EventsPerSock events_per_sock
Map of socket -> socket events.
Definition: httpserver.h:339
uint8_t major
Default HTTP protocol version 1.1 is used by error responses when a request is unreadable.
Definition: httpserver.h:131
size_t Consumed() const
Returns number of bytes already read from buffer.
Definition: string.cpp:74
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:69
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:60
#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:12
bool CaseInsensitiveEqual(std::string_view s1, std::string_view s2)
Locale-independent, ASCII-only comparator.
bool SplitHostPort(std::string_view in, uint16_t &portOut, std::string &hostOut)
Splits socket address string into host string and port value.
std::string ToLower(std::string_view str)
Returns the lowercase equivalent of the given string.
std::string FormatRFC1123DateTime(int64_t time)
RFC1123 formatting https://www.rfc-editor.org/rfc/rfc1123#section-5.2.14 Used in HTTP/1....
Definition: time.cpp:132
assert(!tx.IsCoinBase())