#include "rec-system-resolve.hh"
#include "root-dnssec.hh"
#include "ratelimitedlog.hh"
+#include "settings/rust/web.rs.h"
#ifdef NOD_ENABLED
#include "nod.hh"
g_packetCache = std::make_unique<RecursorPacketCache>(g_maxPacketCacheEntries, ::arg().asNum("packetcache-shards"));
}
+ extern void serveRustWeb();
+ serveRustWeb();
ret = serviceMain(startupLog);
}
catch (const PDNSException& ae) {
return 1;
}
}
+
+void pdns::rust::web::rec::serveStuff(const pdns::rust::web::rec::Request& /* unused */, pdns::rust::web::rec::Response& /* unused */)
+{
+}
+
+void pdns::rust::web::rec::prometheusMetrics(const pdns::rust::web::rec::Request& /* unused */, pdns::rust::web::rec::Response& /* unused */)
+{
+}
+
+void pdns::rust::web::rec::apiServerZonesGET(const pdns::rust::web::rec::Request& /* unused */, pdns::rust::web::rec::Response& /* unused */)
+{
+}
+
+void pdns::rust::web::rec::apiServerCacheFlush(const pdns::rust::web::rec::Request& /* unused */, pdns::rust::web::rec::Response& /* unused */)
+{
+}
+
+void pdns::rust::web::rec::apiServerZonesPOST(const pdns::rust::web::rec::Request& /* unused */, pdns::rust::web::rec::Response& /* unused */)
+{
+}
for (const auto& entry : oldAndNewDomains) {
wipeCaches(entry, true, 0xffff);
}
+ extern std::shared_ptr<SyncRes::domainmap_t> g_initialDomainMap; // XXX
+ g_initialDomainMap = newDomainMap;
return "ok\n";
}
catch (const std::exception& e) {
#include "dnsrecords.hh"
#include "base64.hh"
#include "validate-recursor.hh"
+#include "threadname.hh"
::rust::Vec<::rust::String> pdns::settings::rec::getStrings(const std::string& name)
{
return false;
}
}
+
mod bridge;
use bridge::*;
+mod web; // leaving this out causes link issues
+
// Suppresses "Deserialize unused" warning
#[derive(Deserialize, Serialize)]
struct UnusedStruct {}
# It is not intended for manual editing.
version = 3
+[[package]]
+name = "addr2line"
+version = "0.24.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+
[[package]]
name = "anyhow"
version = "1.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8"
+[[package]]
+name = "backtrace"
+version = "0.3.74"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
+dependencies = [
+ "addr2line",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+ "windows-targets",
+]
+
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+[[package]]
+name = "bytes"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da"
+
[[package]]
name = "cc"
version = "1.1.18"
"shlex",
]
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
[[package]]
name = "codespan-reporting"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
+
+[[package]]
+name = "futures-task"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
+
+[[package]]
+name = "futures-util"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "pin-project-lite",
+ "pin-utils",
+]
+
+[[package]]
+name = "gimli"
+version = "0.31.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
+
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+[[package]]
+name = "hermit-abi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+
+[[package]]
+name = "http"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
+dependencies = [
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
+
+[[package]]
+name = "httpdate"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
+
+[[package]]
+name = "hyper"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "smallvec",
+ "tokio",
+]
+
+[[package]]
+name = "hyper-util"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
+dependencies = [
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "hyper",
+ "pin-project-lite",
+ "tokio",
+]
+
[[package]]
name = "indexmap"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+[[package]]
+name = "libc"
+version = "0.2.162"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398"
+
[[package]]
name = "libyml"
version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+[[package]]
+name = "miniz_oxide"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
+dependencies = [
+ "adler2",
+]
+
+[[package]]
+name = "mio"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "wasi",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "object"
+version = "0.36.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
[[package]]
name = "proc-macro2"
version = "1.0.86"
"proc-macro2",
]
+[[package]]
+name = "rustc-demangle"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+
[[package]]
name = "ryu"
version = "1.0.18"
version = "5.2.0"
dependencies = [
"base64",
+ "bytes",
"cxx",
"cxx-build",
+ "form_urlencoded",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
"ipnet",
"once_cell",
"serde",
"serde_yml",
+ "tokio",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+[[package]]
+name = "smallvec"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+
+[[package]]
+name = "socket2"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
[[package]]
name = "syn"
version = "2.0.77"
"winapi-util",
]
+[[package]]
+name = "tokio"
+version = "1.41.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33"
+dependencies = [
+ "backtrace",
+ "libc",
+ "mio",
+ "pin-project-lite",
+ "socket2",
+ "windows-sys 0.52.0",
+]
+
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
[[package]]
name = "winapi-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
- "windows-sys",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
]
[[package]]
ipnet = "2.8"
once_cell = "1.18.0"
base64 = "0.22"
+hyper = { version = "1", features = ["server", "http1"]}
+tokio = { version = "1" , features = ["rt", "net"]}
+http-body-util = "0.1"
+hyper-util = { version = "0.1", features = ["tokio"]}
+bytes = "1.8"
+form_urlencoded = "1.2"
[build-dependencies]
cxx-build = "1.0"
src/helpers.rs
# should actually end up in a target specific dir...
-libsettings.a lib.rs.h: src/bridge.rs src/lib.rs src/helpers.rs Cargo.toml Cargo.lock build.rs
+libsettings.a lib.rs.h: src/web.rs src/bridge.rs src/lib.rs src/helpers.rs Cargo.toml Cargo.lock build.rs
SYSCONFDIR=$(sysconfdir) NODCACHEDIRNOD=$(localstatedir)/nod NODCACHEDIRUDR=$(localstatedir)/udr $(CARGO) build --release $(RUST_TARGET) --target-dir=$(builddir)/target --manifest-path ${srcdir}/Cargo.toml
cp target/$(RUSTC_TARGET_ARCH)/release/libsettings.a libsettings.a
cp target/$(RUSTC_TARGET_ARCH)/cxxbridge/settings/src/lib.rs.h lib.rs.h
+ cp target/$(RUSTC_TARGET_ARCH)/cxxbridge/settings/src/web.rs.h web.rs.h
cp target/$(RUSTC_TARGET_ARCH)/cxxbridge/rust/cxx.h cxx.h
clean-local:
- rm -rf libsettings.a src/lib.rs lib.rs.h cxx.h target
+ rm -rf libsettings.a src/lib.rs lib.rs.h web.rs.h cxx.h target
fn main() {
- cxx_build::bridge("src/lib.rs")
+ let sources = vec!["src/lib.rs", "src/web.rs"];
+ cxx_build::bridges(sources)
// .file("src/source.cc") Code callable from Rust is in ../cxxsupport.cc
.flag_if_supported("-std=c++17")
.flag("-Isrc")
{
uint16_t qTypeStringToCode(::rust::Str str);
bool isValidHostname(::rust::Str str);
+void setThreadName(::rust::Str str);
+}
+
+namespace pdns::rust::web::rec
+{
+struct KeyValue;
+struct Request;
+struct Response;
+void serveStuff(const Request& rustRequest, Response& rustResponse);
+void prometheusMetrics(const Request& rustRequest, Response& rustResponse);
+void apiServerCacheFlush(const Request& rustRequest, Response& rustResponse);
+void apiServerZonesGET(const Request& rustRequest,Response& rustResponse);
+void apiServerZonesPOST(const Request& rustRequest, Response& rustResponse);
}
--- /dev/null
+use std::net::SocketAddr;
+
+use bytes::Bytes;
+use http_body_util::{BodyExt, Full};
+use hyper::{body::Incoming as IncomingBody, header, Method, Request, Response, StatusCode};
+use hyper::server::conn::http1;
+use hyper::service::service_fn;
+use hyper_util::rt::TokioIo;
+use tokio::net::TcpListener;
+use tokio::runtime::Builder;
+use tokio::task::JoinSet;
+
+use std::io::ErrorKind;
+use std::str::FromStr;
+
+type GenericError = Box<dyn std::error::Error + Send + Sync>;
+type MyResult<T> = std::result::Result<T, GenericError>;
+type BoxBody = http_body_util::combinators::BoxBody<Bytes, hyper::Error>;
+
+static NOTFOUND: &[u8] = b"Not Found";
+
+fn full<T: Into<Bytes>>(chunk: T) -> BoxBody {
+ Full::new(chunk.into())
+ .map_err(|never| match never {})
+ .boxed()
+}
+
+type Func = fn(&rustweb::Request, &mut rustweb::Response) -> Result<(), cxx::Exception>;
+
+fn api_wrapper(handler: Func, request: &rustweb::Request, response: &mut rustweb::Response, headers: &mut header::HeaderMap)
+{
+ response.status = StatusCode::OK.as_u16(); // 200;
+ // security headers
+ headers.insert(header::ACCESS_CONTROL_ALLOW_ORIGIN, header::HeaderValue::from_static("*"));
+ headers.insert(header::X_CONTENT_TYPE_OPTIONS, header::HeaderValue::from_static("nosniff"));
+ headers.insert(header::X_FRAME_OPTIONS, header::HeaderValue::from_static("deny"));
+ headers.insert(header::HeaderName::from_static("x-permitted-cross-domain-policies"), header::HeaderValue::from_static("none"));
+ headers.insert(header::X_XSS_PROTECTION, header::HeaderValue::from_static("1; mode=block"));
+ headers.insert(header::CONTENT_SECURITY_POLICY, header::HeaderValue::from_static("default-src 'self'; style-src 'self' 'unsafe-inline'"));
+
+ println!("api_wrapper A0 Status {}", response.status);
+ match handler(request, response) {
+ Ok(_) => {
+ }
+ Err(_) => {
+ response.status = StatusCode::UNPROCESSABLE_ENTITY.as_u16(); // 422
+ }
+ }
+ println!("api_wrapper A Status {}", response.status);
+}
+
+async fn hello(rust_request: Request<IncomingBody>, urls: &Vec<String>) -> MyResult<Response<BoxBody>> {
+ let mut rust_response = Response::builder();
+ let mut vars: Vec<rustweb::KeyValue> = vec![];
+ if let Some(query) = rust_request.uri().query() {
+ for (k, v) in form_urlencoded::parse(query.as_bytes()) {
+ if k == "_" { // jQuery cache buster
+ continue;
+ }
+ let kv = rustweb::KeyValue{key: k.to_string(), value: v.to_string()};
+ vars.push(kv);
+ }
+ }
+ let mut request = rustweb::Request{body: vec!(), uri: rust_request.uri().to_string(), vars: vars};
+ let mut response = rustweb::Response{status: 0, body: vec![], headers: vec![]};
+ let headers = rust_response.headers_mut().expect("no headers?");
+ match (rust_request.method(), rust_request.uri().path()) {
+ (&Method::GET, "/metrics") => {
+ rustweb::prometheusMetrics(&request, &mut response).unwrap();
+ }
+ (&Method::PUT, "/api/v1/servers/localhost/cache/flush") => {
+ api_wrapper(rustweb::apiServerCacheFlush as Func, &request, &mut response, headers);
+ }
+ (&Method::GET, "/api/v1/servers/localhost/zones") => {
+ println!("hello Status {}", response.status);
+ api_wrapper(rustweb::apiServerZonesGET as Func, &request, &mut response, headers);
+ }
+ (&Method::POST, "/api/v1/servers/localhost/zones") => {
+ request.body = rust_request.collect().await?.to_bytes().to_vec();
+ api_wrapper(rustweb::apiServerZonesPOST as Func, &request, &mut response, headers);
+ }
+ _ => {
+ println!("{}", rust_request.uri().path());
+ println!("{}", urls.len());
+ let mut path = rust_request.uri().path();
+ if path == "/" {
+ path = "/index.html";
+ }
+ let pos = urls.iter().position(|x| {
+ String::from("/") + x == path
+ });
+ println!("Pos is {:?}", pos);
+ if let Err(_) = rustweb::serveStuff(&request, &mut response) {
+ // Return 404 not found response.
+ response.status = StatusCode::NOT_FOUND.as_u16();
+ response.body = NOTFOUND.to_vec();
+ }
+ }
+ }
+ println!("B Status {}", response.status);
+ let mut rust_response = rust_response
+ .status(StatusCode::from_u16(response.status).unwrap())
+ .body(full(response.body))?;
+ for kv in response.headers {
+ rust_response.headers_mut().insert(header::HeaderName::from_bytes(kv.key.as_bytes()).unwrap(), header::HeaderValue::from_str(kv.value.as_str()).unwrap());
+ }
+ Ok(rust_response)
+}
+
+async fn serveweb_async(listener: TcpListener, urls: &'static Vec<String>) -> MyResult<()> {
+
+ //let request_counter = Arc::new(AtomicUsize::new(0));
+ /*
+ let fut = http1::Builder::new()
+ .serve_connection(move || {
+ service_fn(move |req| hello(req))
+});
+ */
+ // We start a loop to continuously accept incoming connections
+ loop {
+ let (stream, _) = listener.accept().await?;
+
+ // Use an adapter to access something implementing `tokio::io` traits as if they implement
+ // `hyper::rt` IO traits.
+ let io = TokioIo::new(stream);
+ let fut = http1::Builder::new()
+ .serve_connection(io, service_fn(move |req| {
+ hello(req, urls)
+ }));
+
+ // Spawn a tokio task to serve multiple connections concurrently
+ tokio::task::spawn(async move {
+ // Finally, we bind the incoming connection to our `hello` service
+ if let Err(err) = /* http1::Builder::new()
+ // `service_fn` converts our function in a `Service`
+ .serve_connection(io, service_fn(|req| hello(req)))
+ */
+ fut.await
+ {
+ eprintln!("Error serving connection: {:?}", err);
+ }
+ });
+ }
+}
+
+pub fn serveweb(addresses: &Vec<String>, urls: &'static Vec<String>) -> Result<(), std::io::Error> {
+
+ let runtime = Builder::new_current_thread()
+ .worker_threads(1)
+ .thread_name("rec/web")
+ .enable_io()
+ .build()?;
+
+ let mut set = JoinSet::new();
+
+ for addr_str in addresses {
+
+ // Socket create and bind should happen here
+ //let addr = SocketAddr::from_str(addr_str);
+ let addr = match SocketAddr::from_str(addr_str) {
+ Ok(val) => val,
+ Err(err) => {
+ let msg = format!("`{}' is not a IP:port combination: {}", addr_str, err);
+ return Err(std::io::Error::new(ErrorKind::Other, msg));
+ }
+ };
+
+ let listener = runtime.block_on(async {
+ TcpListener::bind(addr).await
+ });
+
+ match listener {
+ Ok(val) => {
+ println!("Listening on {}", addr);
+ set.spawn_on(serveweb_async(val, urls), runtime.handle());
+ },
+ Err(err) => {
+ let msg = format!("Unable to bind web socket: {}", err);
+ return Err(std::io::Error::new(ErrorKind::Other, msg));
+ }
+ }
+ }
+ std::thread::Builder::new()
+ .name(String::from("rec/rustweb"))
+ .spawn(move || {
+ runtime.block_on(async {
+ while let Some(res) = set.join_next().await {
+ println!("{:?}", res);
+ }
+ });
+ })?;
+ Ok(())
+}
+
+#[cxx::bridge(namespace = "pdns::rust::web::rec")]
+/*
+ * Functions callable from C++
+ */
+mod rustweb {
+
+ extern "Rust" {
+ fn serveweb(addreses: &Vec<String>, urls: &'static Vec<String>) -> Result<()>;
+ }
+
+ struct KeyValue
+ {
+ key: String,
+ value: String,
+ }
+
+ struct Request
+ {
+ body: Vec<u8>,
+ uri: String,
+ vars: Vec<KeyValue>,
+ }
+
+ struct Response
+ {
+ status: u16,
+ body: Vec<u8>,
+ headers: Vec<KeyValue>,
+ }
+
+ unsafe extern "C++" {
+ include!("bridge.hh");
+ fn serveStuff(request: &Request, response: &mut Response) -> Result<()>;
+ fn prometheusMetrics(request: &Request, response: &mut Response) -> Result<()>;
+ fn apiServerCacheFlush(request: &Request, response: &mut Response) -> Result<()>;
+ fn apiServerZonesGET(request: &Request, response: &mut Response) -> Result<()>;
+ fn apiServerZonesPOST(requst: &Request, response: &mut Response) -> Result<()>;
+ }
+
+}
}
return LWResult::Result::Timeout;
}
+
+void pdns::rust::web::rec::serveStuff(const pdns::rust::web::rec::Request& /* unused */, pdns::rust::web::rec::Response& /* unused */)
+{
+}
+
+void pdns::rust::web::rec::prometheusMetrics(const pdns::rust::web::rec::Request& /* unused */, pdns::rust::web::rec::Response& /* unused */)
+{
+}
+
+void pdns::rust::web::rec::apiServerZonesGET(const pdns::rust::web::rec::Request& /* unused */, pdns::rust::web::rec::Response& /* unused */)
+{
+}
+
+void pdns::rust::web::rec::apiServerCacheFlush(const pdns::rust::web::rec::Request& /* unused */, pdns::rust::web::rec::Response& /* unused */)
+{
+}
+
+void pdns::rust::web::rec::apiServerZonesPOST(const pdns::rust::web::rec::Request& /* unused */, pdns::rust::web::rec::Response& /* unused */)
+{
+}
+
#include "ws-recursor.hh"
#include "json.hh"
+#include <algorithm>
#include <string>
#include "namespaces.hh"
#include <iostream>
#include "tcpiohandler.hh"
#include "rec-main.hh"
#include "settings/cxxsettings.hh" // IWYU pragma: keep, needed by included generated file
+#include "settings/rust/web.rs.h"
using json11::Json;
+static void fromCxxToRust(const HttpResponse& cxxresp, pdns::rust::web::rec::Response& rustResponse)
+{
+ if (cxxresp.status != 0) {
+ rustResponse.status = cxxresp.status;
+ }
+ rustResponse.body = ::rust::Vec<::rust::u8>();
+ rustResponse.body.reserve(cxxresp.body.size());
+ std::copy(cxxresp.body.cbegin(), cxxresp.body.cend(), std::back_inserter(rustResponse.body));
+ for (const auto& header : cxxresp.headers) {
+ rustResponse.headers.emplace_back(pdns::rust::web::rec::KeyValue{header.first, header.second});
+ }
+}
+
void productServerStatisticsFetch(map<string, string>& out)
{
auto stats = getAllStatsMap(StatComponent::API);
DNSName zonename = apiNameToDNSName(stringFromJson(document, "name"));
- const auto& iter = SyncRes::t_sstorage.domainmap->find(zonename);
- if (iter != SyncRes::t_sstorage.domainmap->cend()) {
+ const auto& iter = g_initialDomainMap->find(zonename);
+ if (iter != g_initialDomainMap->cend()) {
throw ApiException("Zone already exists");
}
resp->status = 201;
}
+void pdns::rust::web::rec::apiServerZonesPOST(const pdns::rust::web::rec::Request& rustRequest, pdns::rust::web::rec::Response& rustResponse)
+{
+ HttpRequest req;
+ HttpResponse resp;
+
+ req.body = std::string(reinterpret_cast<const char*>(rustRequest.body.data()), rustRequest.body.size());
+ apiServerZonesPOST(&req, &resp);
+ fromCxxToRust(resp, rustResponse);
+}
+
static void apiServerZonesGET(HttpRequest* /* req */, HttpResponse* resp)
{
Json::array doc;
- for (const auto& val : *SyncRes::t_sstorage.domainmap) {
+ for (const auto& val : *g_initialDomainMap) {
const SyncRes::AuthDomain& zone = val.second;
Json::array servers;
for (const auto& server : zone.d_servers) {
resp->setJsonBody(doc);
}
+void pdns::rust::web::rec::apiServerZonesGET(const pdns::rust::web::rec::Request& /* rustRequest */, pdns::rust::web::rec::Response& rustResponse)
+{
+ HttpResponse resp;
+ apiServerZonesGET(nullptr, &resp);
+ fromCxxToRust(resp, rustResponse);
+}
+
static inline DNSName findZoneById(HttpRequest* req)
{
auto zonename = apiZoneIdToName(req->parameters["id"]);
resp->setJsonBody(doc);
}
+
static void apiServerCacheFlush(HttpRequest* req, HttpResponse* resp)
{
DNSName canon = apiNameToDNSName(req->getvars["domain"]);
{"result", "Flushed cache."}});
}
+void pdns::rust::web::rec::apiServerCacheFlush(const pdns::rust::web::rec::Request& rustRequest, pdns::rust::web::rec::Response& rustResponse)
+{
+ HttpRequest request;
+ for (const auto& [key, value] : rustRequest.vars) {
+ cerr << key << ' ' << value << endl;
+ request.getvars[std::string(key)] = std::string(value);
+ }
+ HttpResponse response;
+ apiServerCacheFlush(&request, &response);
+ fromCxxToRust(response, rustResponse);
+}
+
static void apiServerRPZStats(HttpRequest* /* req */, HttpResponse* resp)
{
auto luaconf = g_luaconfs.getLocal();
resp->status = 200;
}
+void pdns::rust::web::rec::prometheusMetrics(const pdns::rust::web::rec::Request& /* rustRequest */, pdns::rust::web::rec::Response& rustReponse)
+{
+ HttpResponse resp;
+ prometheusMetrics(nullptr, &resp);
+ fromCxxToRust(resp, rustReponse);
+}
+
#include "htmlfiles.h"
static void serveStuff(HttpRequest* req, HttpResponse* resp)
}
}
+void pdns::rust::web::rec::serveStuff(const pdns::rust::web::rec::Request& rustRequest, pdns::rust::web::rec::Response& rustReponse)
+{
+ HttpRequest request;
+ HttpResponse response;
+ request.url = std::string(rustRequest.uri);
+ serveStuff(&request, &response);
+ fromCxxToRust(response, rustReponse);
+}
+
const std::map<std::string, MetricDefinition> MetricDefinitionStorage::d_metrics = {
#include "rec-prometheus-gen.h"
};
}
server->asyncWaitForConnections(d_fdm, [this](const std::shared_ptr<Socket>& socket) { serveConnection(socket); });
}
+
+void serveRustWeb()
+{
+ static ::rust::Vec<::rust::String> urls;
+ for (const auto& [url, _] : g_urlmap) {
+ urls.emplace_back(url);
+ }
+ pdns::rust::web::rec::serveweb({"127.0.0.1:3000", "[::1]:3000"}, urls);
+}