[pbs-devel] [PATCH proxmox-backup v2 09/16] make get_index and ApiConfig property (callback)

Dietmar Maurer dietmar at proxmox.com
Tue Sep 21 07:58:47 CEST 2021


---
 proxmox-rest-server/src/api_config.rs | 18 +++++-
 src/bin/proxmox-backup-api.rs         | 21 +++++++
 src/bin/proxmox-backup-proxy.rs       | 81 ++++++++++++++++++++++++++-
 src/bin/proxmox-restore-daemon.rs     | 22 +++++++-
 src/server/rest.rs                    | 80 +-------------------------
 5 files changed, 142 insertions(+), 80 deletions(-)

diff --git a/proxmox-rest-server/src/api_config.rs b/proxmox-rest-server/src/api_config.rs
index a319e204..fee94e88 100644
--- a/proxmox-rest-server/src/api_config.rs
+++ b/proxmox-rest-server/src/api_config.rs
@@ -5,7 +5,9 @@ use std::fs::metadata;
 use std::sync::{Arc, Mutex, RwLock};
 
 use anyhow::{bail, Error, format_err};
-use hyper::Method;
+use hyper::{Method, Body, Response};
+use hyper::http::request::Parts;
+
 use handlebars::Handlebars;
 use serde::Serialize;
 
@@ -14,6 +16,8 @@ use proxmox::tools::fs::{create_path, CreateOptions};
 
 use crate::{ApiAuth, FileLogger, FileLogOptions, CommandoSocket};
 
+pub type GetIndexFn = fn(Option<String>, Option<String>, &ApiConfig, Parts) -> Response<Body>;
+
 pub struct ApiConfig {
     basedir: PathBuf,
     router: &'static Router,
@@ -23,6 +27,7 @@ pub struct ApiConfig {
     template_files: RwLock<HashMap<String, (SystemTime, PathBuf)>>,
     request_log: Option<Arc<Mutex<FileLogger>>>,
     pub api_auth: Arc<dyn ApiAuth + Send + Sync>,
+    get_index_fn: GetIndexFn,
 }
 
 impl ApiConfig {
@@ -31,6 +36,7 @@ impl ApiConfig {
         router: &'static Router,
         env_type: RpcEnvironmentType,
         api_auth: Arc<dyn ApiAuth + Send + Sync>,
+        get_index_fn: GetIndexFn,
     ) -> Result<Self, Error> {
         Ok(Self {
             basedir: basedir.into(),
@@ -41,9 +47,19 @@ impl ApiConfig {
             template_files: RwLock::new(HashMap::new()),
             request_log: None,
             api_auth,
+            get_index_fn,
         })
     }
 
+    pub fn get_index(
+        &self,
+        auth_id: Option<String>,
+        language: Option<String>,
+        parts: Parts,
+    ) -> Response<Body> {
+        (self.get_index_fn)(auth_id, language, self, parts)
+    }
+
     pub fn find_method(
         &self,
         components: &[&str],
diff --git a/src/bin/proxmox-backup-api.rs b/src/bin/proxmox-backup-api.rs
index 17b6f184..3bc02639 100644
--- a/src/bin/proxmox-backup-api.rs
+++ b/src/bin/proxmox-backup-api.rs
@@ -1,5 +1,9 @@
 use anyhow::{bail, Error};
 use futures::*;
+use http::request::Parts;
+use http::Response;
+use hyper::{Body, StatusCode};
+use hyper::header;
 
 use proxmox::try_block;
 use proxmox::api::RpcEnvironmentType;
@@ -27,6 +31,22 @@ fn main() {
     }
 }
 
+fn get_index(
+    _auth_id: Option<String>,
+    _language: Option<String>,
+    _api: &ApiConfig,
+    _parts: Parts,
+) -> Response<Body> {
+
+    let index = "<center><h1>Proxmox Backup API Server</h1></center>";
+
+    Response::builder()
+        .status(StatusCode::OK)
+        .header(header::CONTENT_TYPE, "text/html")
+        .body(index.into())
+        .unwrap()
+}
+
 async fn run() -> Result<(), Error> {
     if let Err(err) = syslog::init(
         syslog::Facility::LOG_DAEMON,
@@ -65,6 +85,7 @@ async fn run() -> Result<(), Error> {
         &proxmox_backup::api2::ROUTER,
         RpcEnvironmentType::PRIVILEGED,
         default_api_auth(),
+        get_index,
     )?;
 
     let backup_user = pbs_config::backup_user()?;
diff --git a/src/bin/proxmox-backup-proxy.rs b/src/bin/proxmox-backup-proxy.rs
index d4ac2a85..6a4fddef 100644
--- a/src/bin/proxmox-backup-proxy.rs
+++ b/src/bin/proxmox-backup-proxy.rs
@@ -4,10 +4,15 @@ use std::os::unix::io::AsRawFd;
 
 use anyhow::{bail, format_err, Error};
 use futures::*;
+use http::request::Parts;
+use http::Response;
+use hyper::{Body, StatusCode};
+use hyper::header;
+use url::form_urlencoded;
 
 use openssl::ssl::{SslMethod, SslAcceptor, SslFiletype};
 use tokio_stream::wrappers::ReceiverStream;
-use serde_json::Value;
+use serde_json::{json, Value};
 
 use proxmox::try_block;
 use proxmox::api::RpcEnvironmentType;
@@ -73,6 +78,79 @@ fn main() -> Result<(), Error> {
     pbs_runtime::main(run())
 }
 
+fn get_index(
+    auth_id: Option<String>,
+    language: Option<String>,
+    api: &ApiConfig,
+    parts: Parts,
+) -> Response<Body> {
+
+    let (userid, csrf_token) = match auth_id {
+        Some(auth_id) => {
+            let auth_id = auth_id.parse::<Authid>();
+            match auth_id {
+                Ok(auth_id) if !auth_id.is_token() => {
+                    let userid = auth_id.user().clone();
+                    let new_csrf_token = assemble_csrf_prevention_token(csrf_secret(), &userid);
+                    (Some(userid), Some(new_csrf_token))
+                }
+                _ => (None, None)
+            }
+        }
+        None => (None, None),
+    };
+
+    let nodename = proxmox::tools::nodename();
+    let user = userid.as_ref().map(|u| u.as_str()).unwrap_or("");
+
+    let csrf_token = csrf_token.unwrap_or_else(|| String::from(""));
+
+    let mut debug = false;
+    let mut template_file = "index";
+
+    if let Some(query_str) = parts.uri.query() {
+        for (k, v) in form_urlencoded::parse(query_str.as_bytes()).into_owned() {
+            if k == "debug" && v != "0" && v != "false" {
+                debug = true;
+            } else if k == "console" {
+                template_file = "console";
+            }
+        }
+    }
+
+    let mut lang = String::from("");
+    if let Some(language) = language {
+        if Path::new(&format!("/usr/share/pbs-i18n/pbs-lang-{}.js", language)).exists() {
+            lang = language;
+        }
+    }
+
+    let data = json!({
+        "NodeName": nodename,
+        "UserName": user,
+        "CSRFPreventionToken": csrf_token,
+        "language": lang,
+        "debug": debug,
+    });
+
+    let (ct, index) = match api.render_template(template_file, &data) {
+        Ok(index) => ("text/html", index),
+        Err(err) => ("text/plain", format!("Error rendering template: {}", err)),
+    };
+
+    let mut resp = Response::builder()
+        .status(StatusCode::OK)
+        .header(header::CONTENT_TYPE, ct)
+        .body(index.into())
+        .unwrap();
+
+    if let Some(userid) = userid {
+        resp.extensions_mut().insert(Authid::from((userid, None)));
+    }
+
+    resp
+}
+
 async fn run() -> Result<(), Error> {
     if let Err(err) = syslog::init(
         syslog::Facility::LOG_DAEMON,
@@ -93,6 +171,7 @@ async fn run() -> Result<(), Error> {
         &proxmox_backup::api2::ROUTER,
         RpcEnvironmentType::PUBLIC,
         default_api_auth(),
+        get_index,
     )?;
 
     config.add_alias("novnc", "/usr/share/novnc-pve");
diff --git a/src/bin/proxmox-restore-daemon.rs b/src/bin/proxmox-restore-daemon.rs
index c5122cff..d9a8eff0 100644
--- a/src/bin/proxmox-restore-daemon.rs
+++ b/src/bin/proxmox-restore-daemon.rs
@@ -13,6 +13,10 @@ use lazy_static::lazy_static;
 use log::{error, info};
 use tokio::sync::mpsc;
 use tokio_stream::wrappers::ReceiverStream;
+use http::request::Parts;
+use http::Response;
+use hyper::{Body, StatusCode};
+use hyper::header;
 
 use proxmox::api::RpcEnvironmentType;
 
@@ -89,13 +93,29 @@ fn setup_system_env() -> Result<(), Error> {
     Ok(())
 }
 
+fn get_index(
+    _auth_id: Option<String>,
+    _language: Option<String>,
+    _api: &ApiConfig,
+    _parts: Parts,
+) -> Response<Body> {
+
+    let index = "<center><h1>Proxmox Backup Restore Daemon/h1></center>";
+
+    Response::builder()
+        .status(StatusCode::OK)
+        .header(header::CONTENT_TYPE, "text/html")
+        .body(index.into())
+        .unwrap()
+}
+
 async fn run() -> Result<(), Error> {
     watchdog_init();
 
     let auth_config = Arc::new(
         auth::ticket_auth().map_err(|err| format_err!("reading ticket file failed: {}", err))?,
     );
-    let config = ApiConfig::new("", &ROUTER, RpcEnvironmentType::PUBLIC, auth_config)?;
+    let config = ApiConfig::new("", &ROUTER, RpcEnvironmentType::PUBLIC, auth_config, get_index)?;
     let rest_server = RestServer::new(config);
 
     let vsock_fd = get_vsock_fd()?;
diff --git a/src/server/rest.rs b/src/server/rest.rs
index 3cc6bccb..9ed0eb32 100644
--- a/src/server/rest.rs
+++ b/src/server/rest.rs
@@ -15,7 +15,7 @@ use hyper::http::request::Parts;
 use hyper::{Body, Request, Response, StatusCode};
 use lazy_static::lazy_static;
 use regex::Regex;
-use serde_json::{json, Value};
+use serde_json::Value;
 use tokio::fs::File;
 use tokio::time::Instant;
 use url::form_urlencoded;
@@ -42,8 +42,6 @@ use proxmox_rest_server::formatter::*;
 
 use pbs_config::CachedUserInfo;
 
-use crate::auth_helpers::*;
-
 extern "C" {
     fn tzset();
 }
@@ -468,78 +466,6 @@ pub async fn handle_api_request<Env: RpcEnvironment, S: 'static + BuildHasher +
     Ok(resp)
 }
 
-fn get_index(
-    auth_id: Option<String>,
-    language: Option<String>,
-    api: &Arc<ApiConfig>,
-    parts: Parts,
-) -> Response<Body> {
-
-    let (userid, csrf_token) = match auth_id {
-        Some(auth_id) => {
-            let auth_id = auth_id.parse::<Authid>();
-            match auth_id {
-                Ok(auth_id) if !auth_id.is_token() => {
-                    let userid = auth_id.user().clone();
-                    let new_csrf_token = assemble_csrf_prevention_token(csrf_secret(), &userid);
-                    (Some(userid), Some(new_csrf_token))
-                }
-                _ => (None, None)
-            }
-        }
-        None => (None, None),
-    };
-
-    let nodename = proxmox::tools::nodename();
-    let user = userid.as_ref().map(|u| u.as_str()).unwrap_or("");
-
-    let csrf_token = csrf_token.unwrap_or_else(|| String::from(""));
-
-    let mut debug = false;
-    let mut template_file = "index";
-
-    if let Some(query_str) = parts.uri.query() {
-        for (k, v) in form_urlencoded::parse(query_str.as_bytes()).into_owned() {
-            if k == "debug" && v != "0" && v != "false" {
-                debug = true;
-            } else if k == "console" {
-                template_file = "console";
-            }
-        }
-    }
-
-    let mut lang = String::from("");
-    if let Some(language) = language {
-        if Path::new(&format!("/usr/share/pbs-i18n/pbs-lang-{}.js", language)).exists() {
-            lang = language;
-        }
-    }
-
-    let data = json!({
-        "NodeName": nodename,
-        "UserName": user,
-        "CSRFPreventionToken": csrf_token,
-        "language": lang,
-        "debug": debug,
-    });
-
-    let (ct, index) = match api.render_template(template_file, &data) {
-        Ok(index) => ("text/html", index),
-        Err(err) => ("text/plain", format!("Error rendering template: {}", err)),
-    };
-
-    let mut resp = Response::builder()
-        .status(StatusCode::OK)
-        .header(header::CONTENT_TYPE, ct)
-        .body(index.into())
-        .unwrap();
-
-    if let Some(userid) = userid {
-        resp.extensions_mut().insert(Authid::from((userid, None)));
-    }
-
-    resp
-}
 
 fn extension_to_content_type(filename: &Path) -> (&'static str, bool) {
     if let Some(ext) = filename.extension().and_then(|osstr| osstr.to_str()) {
@@ -802,14 +728,14 @@ async fn handle_request(
             let language = extract_lang_header(&parts.headers);
             match auth.check_auth(&parts.headers, &method) {
                 Ok(auth_id) => {
-                    return Ok(get_index(Some(auth_id), language, &api, parts));
+                    return Ok(api.get_index(Some(auth_id), language, parts));
                 }
                 Err(AuthError::Generic(_)) => {
                     tokio::time::sleep_until(Instant::from_std(delay_unauth_time)).await;
                 }
                 Err(AuthError::NoData) => {}
             }
-            return Ok(get_index(None, language, &api, parts));
+            return Ok(api.get_index(None, language, parts));
         } else {
             let filename = api.find_alias(&components);
             let compression = extract_compression_method(&parts.headers);
-- 
2.30.2






More information about the pbs-devel mailing list