This is an automated email from the ASF dual-hosted git repository.

xuanwo pushed a commit to branch http-send-reqwest-wasm
in repository https://gitbox.apache.org/repos/asf/opendal-reqsign.git

commit 327effe5379f92879c34480acb7c1c567a9c538f
Author: Xuanwo <[email protected]>
AuthorDate: Sun Oct 19 16:27:24 2025 +0800

    feat: Make http-send-reqwest available on wasm
    
    Signed-off-by: Xuanwo <[email protected]>
---
 context/http-send-reqwest/Cargo.toml |  4 ++
 context/http-send-reqwest/src/lib.rs | 79 ++++++++++++++++++++++++++++++------
 2 files changed, 71 insertions(+), 12 deletions(-)

diff --git a/context/http-send-reqwest/Cargo.toml 
b/context/http-send-reqwest/Cargo.toml
index f215dd6..c5a211a 100644
--- a/context/http-send-reqwest/Cargo.toml
+++ b/context/http-send-reqwest/Cargo.toml
@@ -40,3 +40,7 @@ reqwest = { workspace = true, default-features = false }
 [dev-dependencies]
 tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
 reqwest = { workspace = true, default-features = false, features = 
["default-tls"] }
+
+[target.'cfg(target_arch = "wasm32")'.dependencies]
+futures-channel = { version = "0.3" }
+wasm-bindgen-futures = { version = "0.4" }
diff --git a/context/http-send-reqwest/src/lib.rs 
b/context/http-send-reqwest/src/lib.rs
index eb81c84..dfbf029 100644
--- a/context/http-send-reqwest/src/lib.rs
+++ b/context/http-send-reqwest/src/lib.rs
@@ -95,9 +95,14 @@
 
 use async_trait::async_trait;
 use bytes::Bytes;
+#[cfg(target_arch = "wasm32")]
+use futures_channel::oneshot;
+#[cfg(not(target_arch = "wasm32"))]
 use http_body_util::BodyExt;
 use reqsign_core::{Error, HttpSend, Result};
 use reqwest::{Client, Request};
+#[cfg(target_arch = "wasm32")]
+use wasm_bindgen_futures::spawn_local;
 
 /// Reqwest-based implementation of the `HttpSend` trait.
 ///
@@ -137,18 +142,68 @@ impl HttpSend for ReqwestHttpSend {
     async fn http_send(&self, req: http::Request<Bytes>) -> 
Result<http::Response<Bytes>> {
         let req = Request::try_from(req)
             .map_err(|e| Error::unexpected("failed to convert 
request").with_source(e))?;
-        let resp: http::Response<_> = self
-            .client
-            .execute(req)
-            .await
-            .map_err(|e| Error::unexpected("failed to send HTTP 
request").with_source(e))?
-            .into();
 
-        let (parts, body) = resp.into_parts();
-        let bs = BodyExt::collect(body)
-            .await
-            .map(|buf| buf.to_bytes())
-            .map_err(|e| Error::unexpected("failed to collect response 
body").with_source(e))?;
-        Ok(http::Response::from_parts(parts, bs))
+        #[cfg(not(target_arch = "wasm32"))]
+        {
+            return http_send_native(&self.client, req).await;
+        }
+
+        #[cfg(target_arch = "wasm32")]
+        {
+            return http_send_wasm(&self.client, req).await;
+        }
     }
 }
+
+#[cfg(not(target_arch = "wasm32"))]
+async fn http_send_native(client: &Client, req: Request) -> 
Result<http::Response<Bytes>> {
+    let resp = client
+        .execute(req)
+        .await
+        .map_err(|e| Error::unexpected("failed to send HTTP 
request").with_source(e))?;
+
+    let resp: http::Response<_> = resp.into();
+    let (parts, body) = resp.into_parts();
+    let bs = BodyExt::collect(body)
+        .await
+        .map(|buf| buf.to_bytes())
+        .map_err(|e| Error::unexpected("failed to collect response 
body").with_source(e))?;
+    Ok(http::Response::from_parts(parts, bs))
+}
+
+#[cfg(target_arch = "wasm32")]
+async fn http_send_wasm(client: &Client, req: Request) -> 
Result<http::Response<Bytes>> {
+    let (tx, rx) = oneshot::channel();
+    let client = client.clone();
+
+    // reqwest's wasm client is !Send, so drive the request on the local 
executor
+    // and forward the result back through a channel to satisfy HttpSend's 
Send requirement.
+    spawn_local(async move {
+        let result = async move {
+            let resp = client
+                .execute(req)
+                .await
+                .map_err(|e| Error::unexpected("failed to send HTTP 
request").with_source(e))?;
+
+            let status = resp.status();
+            let headers = resp.headers().clone();
+            let body = resp
+                .bytes()
+                .await
+                .map_err(|e| Error::unexpected("failed to collect response 
body").with_source(e))?;
+
+            let mut response = http::Response::builder()
+                .status(status)
+                .body(body)
+                .map_err(|e| Error::unexpected("failed to build HTTP 
response").with_source(e))?;
+            *response.headers_mut() = headers;
+            Ok(response)
+        }
+        .await;
+
+        let _ = tx.send(result);
+    });
+
+    rx.await
+        .map_err(|_| Error::unexpected("failed to receive response from wasm 
task"))?
+}

Reply via email to