diff --git a/fusio/Cargo.toml b/fusio/Cargo.toml index eff8e96..89d0c5c 100644 --- a/fusio/Cargo.toml +++ b/fusio/Cargo.toml @@ -68,6 +68,7 @@ cfg-if = "1.0.0" chrono = { version = "0.4", optional = true, default-features = false, features = [ "now", "std", + "wasmbind" ] } futures-core = { version = "0.3" } futures-util = { version = "0.3" } diff --git a/fusio/src/impls/remotes/aws/credential.rs b/fusio/src/impls/remotes/aws/credential.rs index 90afe87..6afa3f6 100644 --- a/fusio/src/impls/remotes/aws/credential.rs +++ b/fusio/src/impls/remotes/aws/credential.rs @@ -15,12 +15,7 @@ // specific language governing permissions and limitations // under the License. -use std::{ - collections::BTreeMap, - io, - sync::Arc, - time::{Duration, Instant}, -}; +use std::{collections::BTreeMap, io, sync::Arc}; use bytes::{Buf, Bytes}; use chrono::{DateTime, Utc}; @@ -228,7 +223,7 @@ impl<'a> AwsAuthorizer<'a> { } #[allow(unused)] - pub(crate) fn sign(&self, method: Method, url: &mut Url, expires_in: Duration) { + pub(crate) fn sign(&self, method: Method, url: &mut Url, expires_in: u32) { let date = self.date.unwrap_or_else(Utc::now); let scope = self.scope(date); @@ -240,7 +235,7 @@ impl<'a> AwsAuthorizer<'a> { &format!("{}/{}", self.credential.key_id, scope), ) .append_pair("X-Amz-Date", &date.format("%Y%m%dT%H%M%SZ").to_string()) - .append_pair("X-Amz-Expires", &expires_in.as_secs().to_string()) + .append_pair("X-Amz-Expires", &expires_in.to_string()) .append_pair("X-Amz-SignedHeaders", "host"); // For S3, you must include the X-Amz-Security-Token query parameter in the URL if @@ -521,7 +516,6 @@ async fn instance_creds<'c, C: HttpClient>( let ttl = (creds.expiration - now).to_std().unwrap_or_default(); Ok(TemporaryToken { token: Arc::new(creds.into()), - expiry: Some(Instant::now() + ttl), }) } @@ -548,15 +542,10 @@ impl From for AwsCredential { pub(crate) struct TemporaryToken { /// The temporary credential pub(crate) token: T, - /// The instant at which this credential is no longer valid - /// None means the credential does not expire - #[allow(unused)] - pub(crate) expiry: Option, } #[cfg(test)] mod tests { - use std::time::Duration; #[allow(unused)] use bytes::Bytes; @@ -681,7 +670,7 @@ mod tests { }; let mut url = Url::parse("https://examplebucket.s3.amazonaws.com/test.txt").unwrap(); - authorizer.sign(Method::GET, &mut url, Duration::from_secs(86400)); + authorizer.sign(Method::GET, &mut url, 86400); assert_eq!( url, diff --git a/fusio/src/impls/remotes/http/wasm.rs b/fusio/src/impls/remotes/http/wasm.rs index 5fc260b..e0a9f68 100644 --- a/fusio/src/impls/remotes/http/wasm.rs +++ b/fusio/src/impls/remotes/http/wasm.rs @@ -39,12 +39,20 @@ impl HttpClient for WasmClient { Ok(body) => { let client = reqwest::Client::new(); - let mut builder = client.request(parts.method, url); + let mut builder = client.request(parts.method, url).headers(parts.headers); builder = builder.body(reqwest::Body::from(body.to_bytes())); let response = builder.send().await?; + + let mut resp_builder = Response::builder(); + let mut headers = resp_builder.headers_mut(); + for (name, value) in response.headers().iter() { + headers.as_mut().unwrap().append(name, value.clone()); + } let bytes = response.bytes().await?; - Ok(Response::new(http_body_util::Full::new(bytes))) + resp_builder + .body(http_body_util::Full::new(bytes)) + .map_err(HttpError::Http) } Err(err) => Err(HttpError::Other(err.into())), } @@ -74,6 +82,7 @@ mod tests { assert_eq!(response.status(), StatusCode::OK); } + #[ignore] #[cfg(all(feature = "wasm-http", feature = "aws"))] #[wasm_bindgen_test] async fn list_and_remove_wasm() { diff --git a/fusio/tests/wasm_http.rs b/fusio/tests/wasm_http.rs new file mode 100644 index 0000000..05e6377 --- /dev/null +++ b/fusio/tests/wasm_http.rs @@ -0,0 +1,53 @@ +#[cfg(all(feature = "wasm-http", target_arch = "wasm32", test))] +pub(crate) mod tests { + + wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + use wasm_bindgen_test::wasm_bindgen_test; + + #[ignore] + #[cfg(feature = "aws")] + #[wasm_bindgen_test] + async fn test_read_write_s3_wasm() { + use fusio::{ + fs::Fs, + remotes::aws::{fs::AmazonS3Builder, AwsCredential}, + Read, Write, + }; + + if option_env!("AWS_ACCESS_KEY_ID").is_none() { + return; + } + let key_id = option_env!("AWS_ACCESS_KEY_ID").unwrap().to_string(); + let secret_key = option_env!("AWS_SECRET_ACCESS_KEY").unwrap().to_string(); + + let s3 = AmazonS3Builder::new("wasm-data".into()) + .credential(AwsCredential { + key_id, + secret_key, + token: None, + }) + .region("ap-southeast-2".into()) + .sign_payload(true) + .build(); + + { + let mut s3_file = s3.open(&"read-write.txt".into()).await.unwrap(); + + let (result, _) = s3_file + .write_all(&b"The answer of life, universe and everthing"[..]) + .await; + + result.unwrap(); + + s3_file.close().await.unwrap(); + } + let mut s3_file = s3.open(&"read-write.txt".into()).await.unwrap(); + + let size = s3_file.size().await.unwrap(); + assert_eq!(size, 42); + let buf = Vec::new(); + let (result, buf) = s3_file.read_to_end_at(buf, 0).await; + result.unwrap(); + assert_eq!(buf, b"The answer of life, universe and everthing"); + } +}