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