commit 6487055e6ab65e0f329c801c33441c33b50e968c
parent 4ee1a714a0725e5b8b2c16d03281145cc8ee8937
Author: Dave Kozma <dkozma@adobe.com>
Date: Thu, 1 Jun 2023 10:59:05 -0400
Make remote manifest handling consistent across input types (#260)
* Remote manifest fix for non-file i/o functions
* Updated tests
* Update `load_cai_from_memory` function with stream logic
* Remove public from `load_cai_from_memory`
Diffstat:
2 files changed, 67 insertions(+), 53 deletions(-)
diff --git a/sdk/src/ingredient.rs b/sdk/src/ingredient.rs
@@ -918,8 +918,8 @@ impl Ingredient {
let thumbnail = ingredient_assertion.thumbnail.and_then(|hashed_uri| {
// This could be a relative or absolute thumbnail reference to another manifest
let target_label = match jumbf::labels::manifest_label_from_uri(&hashed_uri.url()) {
- Some(label) => label, // use the manifest from the thumbnail uri
- None => claim_label.to_owned(), // relative so use the whole url from the thumbnail assertion
+ Some(label) => label, // use the manifest from the thumbnail uri
+ None => claim_label.to_owned(), // relative so use the whole url from the thumbnail assertion
};
match store.get_assertion_from_uri_and_claim(&hashed_uri.url(), &target_label) {
Some(assertion) => Some(Self::thumbnail_from_assertion(assertion)),
@@ -1427,15 +1427,34 @@ mod tests {
);
}
- #[cfg_attr(not(target_arch = "wasm32"), actix::test)]
- #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ #[allow(dead_code)]
+ #[cfg_attr(not(any(target_arch = "wasm32", feature = "file_io")), actix::test)]
+ #[cfg(not(target_arch = "wasm32"))]
async fn test_jpg_cloud_from_memory() {
let image_bytes = include_bytes!("../tests/fixtures/cloud.jpg");
let format = "image/jpeg";
let ingredient = Ingredient::from_memory_async(format, image_bytes)
.await
.expect("from_memory_async");
- //println!("ingredient = {ingredient}");
+ // println!("ingredient = {ingredient}");
+ assert_eq!(&ingredient.title, "untitled");
+ assert_eq!(ingredient.format(), format);
+ assert!(ingredient.provenance().is_some());
+ assert!(ingredient.provenance().unwrap().starts_with("https:"));
+ assert!(ingredient.manifest_data().is_some());
+ assert!(ingredient.validation_status().is_none());
+ }
+
+ #[allow(dead_code)]
+ #[cfg_attr(not(any(target_arch = "wasm32", feature = "file_io")), actix::test)]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ async fn test_jpg_cloud_from_memory_no_file_io() {
+ let image_bytes = include_bytes!("../tests/fixtures/cloud.jpg");
+ let format = "image/jpeg";
+ let ingredient = Ingredient::from_memory_async(format, image_bytes)
+ .await
+ .expect("from_memory_async");
+ // println!("ingredient = {ingredient}");
assert!(ingredient.validation_status().is_some());
assert_eq!(
ingredient.validation_status().unwrap()[0].code(),
diff --git a/sdk/src/store.rs b/sdk/src/store.rs
@@ -42,8 +42,8 @@ use crate::{
labels::{ASSERTIONS, CREDENTIALS, DATABOXES, SIGNATURE},
},
jumbf_io::{
- get_assetio_handler, load_jumbf_from_memory, load_jumbf_from_stream,
- object_locations_from_stream, save_jumbf_to_memory, save_jumbf_to_stream,
+ get_assetio_handler, load_jumbf_from_stream, object_locations_from_stream,
+ save_jumbf_to_memory, save_jumbf_to_stream,
},
status_tracker::{log_item, OneShotStatusTracker, StatusTracker},
utils::{
@@ -2292,33 +2292,46 @@ impl Store {
}
}
+ /// Handles remote manifests when file_io/fetch_remote_manifests feature is enabled
+ #[cfg(feature = "file_io")]
+ fn handle_remote_manifest(ext_ref: &str) -> Result<Vec<u8>> {
+ // verify provenance path is remote url
+ let is_remote_url = Store::is_valid_remote_url(ext_ref);
+
+ if cfg!(feature = "fetch_remote_manifests") && is_remote_url {
+ Store::fetch_remote_manifest(ext_ref)
+ } else {
+ // return an error with the url that should be read
+ if is_remote_url {
+ Err(Error::RemoteManifestUrl(ext_ref.to_owned()))
+ } else {
+ Err(Error::JumbfNotFound)
+ }
+ }
+ }
+
+ /// Handles remote manifests for Wasm or when the file_io/fetch_remote_manifests feature is disabled
+ #[cfg(not(feature = "file_io"))]
+ fn handle_remote_manifest(ext_ref: &str) -> Result<Vec<u8>> {
+ // verify provenance path is remote url
+ let is_remote_url = Store::is_valid_remote_url(ext_ref);
+
+ if is_remote_url {
+ Err(Error::RemoteManifestUrl(ext_ref.to_owned()))
+ } else {
+ Err(Error::JumbfNotFound)
+ }
+ }
+
/// Return Store from in memory asset
- pub fn load_cai_from_memory(
+ fn load_cai_from_memory(
asset_type: &str,
data: &[u8],
validation_log: &mut impl StatusTracker,
) -> Result<Store> {
- match load_jumbf_from_memory(asset_type, data) {
- Ok(manifest_bytes) => {
- // load and validate with CAI toolkit and dump if desired
- Store::from_jumbf(&manifest_bytes, validation_log)
- }
- Err(Error::JumbfNotFound) => {
- let mut buf_reader = Cursor::new(data);
- if let Some(ext_ref) = crate::utils::xmp_inmemory_utils::XmpInfo::from_source(
- &mut buf_reader,
- asset_type,
- )
- .provenance
- {
- // return an error with the url that should be read
- Err(Error::RemoteManifestUrl(ext_ref))
- } else {
- Err(Error::JumbfNotFound)
- }
- }
- Err(e) => Err(e),
- }
+ let mut input_stream = Cursor::new(data);
+ Store::load_jumbf_from_stream(asset_type, &mut input_stream)
+ .map(|manifest_bytes| Store::from_jumbf(&manifest_bytes, validation_log))?
}
/// load jumbf given a stream
@@ -2336,8 +2349,7 @@ impl Store {
crate::utils::xmp_inmemory_utils::XmpInfo::from_source(stream, asset_type)
.provenance
{
- // return an error with the url that should be read
- Err(Error::RemoteManifestUrl(ext_ref))
+ Store::handle_remote_manifest(&ext_ref)
} else {
Err(Error::JumbfNotFound)
}
@@ -2379,24 +2391,7 @@ impl Store {
)
.provenance
{
- // verify provenance path is remote url
- let is_remote_url = Store::is_valid_remote_url(&ext_ref);
-
- if cfg!(feature = "fetch_remote_manifests") && is_remote_url {
- // not supported in wasm
- if cfg!(target_arch = "wasm32") {
- Err(Error::JumbfNotFound)
- } else {
- Store::fetch_remote_manifest(&ext_ref)
- }
- } else {
- // return an error with the url that should be read
- if is_remote_url {
- Err(Error::RemoteManifestUrl(ext_ref))
- } else {
- Err(Error::JumbfNotFound)
- }
- }
+ Store::handle_remote_manifest(&ext_ref)
} else {
Err(Error::JumbfNotFound)
}
@@ -4158,7 +4153,7 @@ pub mod tests {
let url_string: String = url.into();
// set claim for side car with remote manifest embedding generation
- claim.set_remote_manifest(url_string.clone()).unwrap();
+ claim.set_remote_manifest(url_string).unwrap();
store.commit_claim(claim).unwrap();
@@ -4183,12 +4178,12 @@ pub mod tests {
assert!(result.is_err());
- // verify that we got RemoteManifestUrl error with the expected url
+ // We should get a `JumbfNotFound` error since the external reference points to a file URL, not a remote URL
match result {
Ok(_store) => panic!("did not expect to have a store"),
Err(e) => match e {
- Error::RemoteManifestUrl(url) => assert_eq!(url, url_string),
- _ => panic!("unexepected error"),
+ Error::JumbfNotFound => {}
+ e => panic!("unexpected error: {}", e),
},
}
}