]> git.proxmox.com Git - proxmox-backup.git/blobdiff - src/api2/reader.rs
extract create_download_response API helper
[proxmox-backup.git] / src / api2 / reader.rs
index f8fc5a19a2acc875627342ac8ea048a578784382..4c14c97ca56de3bf56927305f56113a84f028a0d 100644 (file)
@@ -1,5 +1,5 @@
 //use chrono::{Local, TimeZone};
-use failure::*;
+use anyhow::{bail, format_err, Error};
 use futures::*;
 use hyper::header::{self, HeaderValue, UPGRADE};
 use hyper::http::request::Parts;
@@ -15,7 +15,9 @@ use crate::api2::types::*;
 use crate::backup::*;
 use crate::server::{WorkerTask, H2Service};
 use crate::tools;
-use crate::config::acl::PRIV_DATASTORE_ALLOCATE_SPACE;
+use crate::config::acl::PRIV_DATASTORE_READ;
+use crate::config::cached_user_info::CachedUserInfo;
+use crate::api2::helpers;
 
 mod environment;
 use environment::*;
@@ -30,19 +32,17 @@ pub const API_METHOD_UPGRADE_BACKUP: ApiMethod = ApiMethod::new(
         concat!("Upgraded to backup protocol ('", PROXMOX_BACKUP_READER_PROTOCOL_ID_V1!(), "')."),
         &sorted!([
             ("store", false, &DATASTORE_SCHEMA),
-            ("backup-type", false, &StringSchema::new("Backup type.")
-             .format(&ApiStringFormat::Enum(&["vm", "ct", "host"]))
-             .schema()
-            ),
-            ("backup-id", false, &StringSchema::new("Backup ID.").schema()),
-            ("backup-time", false, &IntegerSchema::new("Backup time (Unix epoch.)")
-             .minimum(1_547_797_308)
-             .schema()
-            ),
+            ("backup-type", false, &BACKUP_TYPE_SCHEMA),
+            ("backup-id", false, &BACKUP_ID_SCHEMA),
+            ("backup-time", false, &BACKUP_TIME_SCHEMA),
             ("debug", true, &BooleanSchema::new("Enable verbose debug logging.").schema()),
         ]),
     )
-).access(None, &Permission::Privilege(&["datastore", "{store}"], PRIV_DATASTORE_ALLOCATE_SPACE, false));
+).access(
+    // Note: parameter 'store' is no uri parameter, so we need to test inside function body
+    Some("The user needs Datastore.Read privilege on /datastore/{store}."),
+    &Permission::Anybody
+);
 
 fn upgrade_to_backup_reader_protocol(
     parts: Parts,
@@ -55,7 +55,12 @@ fn upgrade_to_backup_reader_protocol(
     async move {
         let debug = param["debug"].as_bool().unwrap_or(false);
 
+        let username = rpcenv.get_user().unwrap();
         let store = tools::required_string_param(&param, "store")?.to_owned();
+
+        let user_info = CachedUserInfo::new()?;
+        user_info.check_privs(&username, &["datastore", &store], PRIV_DATASTORE_READ, false)?;
+
         let datastore = DataStore::lookup_datastore(&store)?;
 
         let backup_type = tools::required_string_param(&param, "backup-type")?;
@@ -76,7 +81,6 @@ fn upgrade_to_backup_reader_protocol(
             bail!("unexpected http version '{:?}' (expected version < 2)", parts.version);
         }
 
-        let username = rpcenv.get_user().unwrap();
         let env_type = rpcenv.env_type();
 
         let backup_dir = BackupDir::new(backup_type, backup_id, backup_time);
@@ -128,7 +132,7 @@ fn upgrade_to_backup_reader_protocol(
                     Either::Right((Ok(res), _)) => Ok(res),
                     Either::Right((Err(err), _)) => Err(err),
                 })
-                .map_ok(move |_| env.log("reader finished sucessfully"))
+                .map_ok(move |_| env.log("reader finished successfully"))
         })?;
 
         let response = Response::builder()
@@ -184,26 +188,9 @@ fn download_file(
         path.push(env.backup_dir.relative_path());
         path.push(&file_name);
 
-        let path2 = path.clone();
-        let path3 = path.clone();
-
-        let file = tokio::fs::File::open(path)
-            .map_err(move |err| http_err!(BAD_REQUEST, format!("open file {:?} failed: {}", path2, err)))
-            .await?;
-
-        env.log(format!("download {:?}", path3));
+        env.log(format!("download {:?}", path.clone()));
 
-        let payload = tokio_util::codec::FramedRead::new(file, tokio_util::codec::BytesCodec::new())
-            .map_ok(|bytes| hyper::body::Bytes::from(bytes.freeze()));
-
-        let body = Body::wrap_stream(payload);
-
-        // fixme: set other headers ?
-        Ok(Response::builder()
-           .status(StatusCode::OK)
-           .header(header::CONTENT_TYPE, "application/octet-stream")
-           .body(body)
-           .unwrap())
+        helpers::create_download_response(path).await
     }.boxed()
 }