From 066a7a8a0c1f85c0b41c06de1b3b25a5bdf9b1c8 Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Tue, 11 Feb 2025 11:56:45 -0500 Subject: [PATCH] fix: Working remote manifest fetch. --- Makefile | 2 +- sdk/src/error.rs | 4 +-- sdk/src/store.rs | 61 +++++++++++++++++---------------- sdk/tests/integration.rs | 1 - sdk/tests/test_builder.rs | 2 +- sdk/tests/v2_api_integration.rs | 11 +++--- 6 files changed, 42 insertions(+), 39 deletions(-) diff --git a/Makefile b/Makefile index 85c41b35c..ff4b61ff8 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ test-wasm-web: # WASI testing requires the WASI SDK https://github.com/WebAssembly/wasi-sdk installed in /opt, # wasmtime, and the target wasm32-wasip2 on the nightly toolchain test-wasi: - CC=/opt/wasi-sdk/bin/clang CARGO_TARGET_WASM32_WASIP2_RUNNER="wasmtime -S common --dir ." cargo +nightly test --target wasm32-wasip2 -p c2pa -p c2pa-crypto + CC=/opt/wasi-sdk/bin/clang CARGO_TARGET_WASM32_WASIP2_RUNNER="wasmtime -S cli -S http --dir ." cargo +nightly test --target wasm32-wasip2 -p c2pa -p c2pa-crypto --all-features # Full local validation, build and test all features including wasm # Run this before pushing a PR to pre-validate diff --git a/sdk/src/error.rs b/sdk/src/error.rs index 6abedfc07..49d4892ff 100644 --- a/sdk/src/error.rs +++ b/sdk/src/error.rs @@ -191,10 +191,10 @@ pub enum Error { #[error("required JUMBF box not found")] JumbfBoxNotFound, - #[error("could not fetch the remote manifest")] + #[error("could not fetch the remote manifest {0}")] RemoteManifestFetch(String), - #[error("must fetch remote manifests from url")] + #[error("must fetch remote manifests from url {0}")] RemoteManifestUrl(String), #[error("stopped because of logged error")] diff --git a/sdk/src/store.rs b/sdk/src/store.rs index 01e3d8b5d..697885c89 100644 --- a/sdk/src/store.rs +++ b/sdk/src/store.rs @@ -3276,47 +3276,48 @@ impl Store { }; //const MANIFEST_CONTENT_TYPE: &str = "application/x-c2pa-manifest-store"; // todo verify once these are served - //const DEFAULT_MANIFEST_RESPONSE_SIZE: usize = 10 * 1024 * 1024; // 10 MB + const DEFAULT_MANIFEST_RESPONSE_SIZE: usize = 10 * 1024 * 1024; // 10 MB let parsed_url = Url::parse(url) .map_err(|e| Error::RemoteManifestFetch(format!("invalid URL: {}", e)))?; - let path_with_query = parsed_url[url::Position::BeforeHost..].to_string(); + let authority = parsed_url.authority(); + let path_with_query = parsed_url[url::Position::AfterPort..].to_string(); + let scheme = match parsed_url.scheme() { + "http" => Scheme::Http, + "https" => Scheme::Https, + _ => { + return Err(Error::RemoteManifestFetch( + "unsupported URL scheme".to_string(), + )) + } + }; let request = OutgoingRequest::new(Fields::new()); request.set_path_with_query(Some(&path_with_query)).unwrap(); - request.set_scheme(Some(&Scheme::Https)).unwrap(); + request.set_authority(Some(&authority)).unwrap(); + request.set_scheme(Some(&scheme)).unwrap(); match outgoing_handler::handle(request, None) { Ok(resp) => { resp.subscribe().block(); let response = resp .get() - .expect("HTTP request response missing") - .expect("HTTP request response requested more than once") - .expect("HTTP request failed"); + .ok_or(Error::RemoteManifestFetch( + "HTTP request response missing".to_string(), + ))? + .map_err(|_| { + Error::RemoteManifestFetch( + "HTTP request response requested more than once".to_string(), + ) + })? + .map_err(|_| Error::RemoteManifestFetch("HTTP request failed".to_string()))?; if response.status() == 200 { - let raw_header = response.headers().get("Content-Length"); - if raw_header.first().map(|val| val.is_empty()).unwrap_or(true) { - return Err(Error::RemoteManifestFetch( - "url returned no content length".to_string(), - )); - } - let str_parsed_header = match std::str::from_utf8(raw_header.first().unwrap()) { - Ok(s) => s, - Err(e) => { - return Err(Error::RemoteManifestFetch(format!( - "error parsing content length header: {}", - e - ))) - } - }; - let content_length: usize = match str_parsed_header.parse() { - Ok(s) => s, - Err(e) => { - return Err(Error::RemoteManifestFetch(format!( - "error parsing content length header: {}", - e - ))) - } - }; + let content_length: usize = response + .headers() + .get("Content-Length") + .first() + .and_then(|val| if val.is_empty() { None } else { Some(val) }) + .and_then(|val| std::str::from_utf8(val).ok()) + .and_then(|str_parsed_header| str_parsed_header.parse().ok()) + .unwrap_or(DEFAULT_MANIFEST_RESPONSE_SIZE); let body = { let mut buf = Vec::with_capacity(content_length); let response_body = response diff --git a/sdk/tests/integration.rs b/sdk/tests/integration.rs index 22577ae70..2746964fd 100644 --- a/sdk/tests/integration.rs +++ b/sdk/tests/integration.rs @@ -13,7 +13,6 @@ /// Complete functional integration test with parent and ingredients. // Isolate from wasm by wrapping in module. - #[cfg(feature = "file_io")] mod integration_1 { use std::{io, path::PathBuf}; diff --git a/sdk/tests/test_builder.rs b/sdk/tests/test_builder.rs index 3cbca48d2..4275ab240 100644 --- a/sdk/tests/test_builder.rs +++ b/sdk/tests/test_builder.rs @@ -21,7 +21,7 @@ mod common; use common::{compare_stream_to_known_good, fixtures_path, test_signer}; #[test] -#[ignore] // TODO: Test does not pass in WASI or native +#[cfg(all(feature = "add_thumbnails", feature = "file_io"))] fn test_builder_ca_jpg() -> Result<()> { let manifest_def = std::fs::read_to_string(fixtures_path("simple_manifest.json"))?; let mut builder = Builder::from_json(&manifest_def)?; diff --git a/sdk/tests/v2_api_integration.rs b/sdk/tests/v2_api_integration.rs index d26bcb195..1b0cbff49 100644 --- a/sdk/tests/v2_api_integration.rs +++ b/sdk/tests/v2_api_integration.rs @@ -147,10 +147,13 @@ mod integration_v2 { dest }; - // write dest to file for debugging - let debug_path = format!("{}/../target/v2_test.jpg", env!("CARGO_MANIFEST_DIR")); - std::fs::write(debug_path, dest.get_ref())?; - dest.rewind()?; + #[cfg(not(target_os = "wasi"))] + { + // write dest to file for debugging + let debug_path = format!("{}/../target/v2_test.jpg", env!("CARGO_MANIFEST_DIR")); + std::fs::write(debug_path, dest.get_ref())?; + dest.rewind()?; + } let reader = Reader::from_stream(format, &mut dest)?;