let sa = validate_socket_address(field, val);
if sa.is_err() && !isValidHostname(val) {
let parts: Vec<&str> = val.split(':').collect();
- if parts.len() != 2
- || !isValidHostname(parts[0])
- || !is_port_number(parts[1])
- {
+ if parts.len() != 2 || !isValidHostname(parts[0]) || !is_port_number(parts[1]) {
let msg = format!(
"{}: value `{}' is not an IP, IP:port, name or name:port combination",
field, val
Ok(())
}
-fn validate_address_family(addrfield: &str, localfield: &str, vec: &[String], local_address: &String) -> Result<(), ValidationError> {
+fn validate_address_family(
+ addrfield: &str,
+ localfield: &str,
+ vec: &[String],
+ local_address: &String,
+) -> Result<(), ValidationError> {
if vec.is_empty() {
let msg = format!("{}: cannot be empty", addrfield);
return Err(ValidationError { msg });
if local.is_ipv4() != ip.is_ipv4() || local.is_ipv6() != ip.is_ipv6() {
wrong = true;
}
- }
- else {
+ } else {
let sa = sa.unwrap();
if local.is_ipv4() != sa.is_ipv4() || local.is_ipv6() != sa.is_ipv6() {
wrong = true;
}
}
if wrong {
- let msg = format!("{}: value `{}' and `{}' differ in address family", localfield, local_address, addr_str);
+ let msg = format!(
+ "{}: value `{}' and `{}' differ in address family",
+ localfield, local_address, addr_str
+ );
return Err(ValidationError { msg });
}
}
}
self.tsig.validate(&(field.to_owned() + ".tsig"))?;
if !self.addresses.is_empty() {
- validate_address_family(&(field.to_owned() + ".addresses"), &(field.to_owned() + ".localAddress"), &self.addresses, &self.localAddress)?;
+ validate_address_family(
+ &(field.to_owned() + ".addresses"),
+ &(field.to_owned() + ".localAddress"),
+ &self.addresses,
+ &self.localAddress,
+ )?;
}
Ok(())
}
&self.sources,
validate_socket_address,
)?;
- validate_address_family(&(field.to_string() + ".sources"), &(field.to_string() + ".localAddress"), &self.sources, &self.localAddress)?;
+ validate_address_family(
+ &(field.to_string() + ".sources"),
+ &(field.to_string() + ".localAddress"),
+ &self.sources,
+ &self.localAddress,
+ )?;
}
self.tsig.validate(&(field.to_owned() + ".tsig"))?;
Ok(())
pub fn validate_snmp(_snmp: &recsettings::Snmp) -> Result<(), ValidationError> {
Ok(())
}
-
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::{body::Incoming as IncomingBody, header, Method, Request, Response, StatusCode};
use hyper_util::rt::TokioIo;
use tokio::net::TcpListener;
use tokio::runtime::Builder;
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)
-{
+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'"));
+ // 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(_) => {
+ 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>> {
+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
+ if k == "_" {
+ // jQuery cache buster
continue;
}
- let kv = rustweb::KeyValue{key: k.to_string(), value: v.to_string()};
+ 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 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);
+ 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);
+ 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);
+ 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();
+ let mut path = rust_request.uri().path();
if path == "/" {
path = "/index.html";
}
- let pos = urls.iter().position(|x| {
- String::from("/") + x == path
- });
+ 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.
.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());
+ 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))
-});
- */
+ 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)
- }));
+ 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)))
- */
+ // `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")
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) {
}
};
- let listener = runtime.block_on(async {
- TcpListener::bind(addr).await
- });
+ 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));
while let Some(res) = set.join_next().await {
println!("{:?}", res);
}
- });
- })?;
+ });
+ })?;
Ok(())
}
fn serveweb(addreses: &Vec<String>, urls: &'static Vec<String>) -> Result<()>;
}
- struct KeyValue
- {
+ struct KeyValue {
key: String,
value: String,
}
- struct Request
- {
+ struct Request {
body: Vec<u8>,
uri: String,
vars: Vec<KeyValue>,
}
- struct Response
- {
+ struct Response {
status: u16,
body: Vec<u8>,
headers: Vec<KeyValue>,
fn apiServerZonesGET(request: &Request, response: &mut Response) -> Result<()>;
fn apiServerZonesPOST(requst: &Request, response: &mut Response) -> Result<()>;
}
-
}