From 3d4587fadbb67a4becb417e4817b617ff35d87f2 Mon Sep 17 00:00:00 2001 From: Alon Gubkin Date: Tue, 8 Apr 2025 00:26:51 +0300 Subject: [PATCH 1/2] fix(wasm): handle null body in bytes_stream The previous implementation of `bytes_stream` in the WASM target would panic with "could not create wasm byte stream" if the underlying `web_sys::Response` had a null body (e.g., for certain redirects or responses with no content). This change introduces a check for `web_response.body()`. If the body is `Some`, it proceeds with creating the stream as before. If the body is `None`, it now returns an empty stream (`stream::empty()`), preventing the panic and correctly representing an empty response body. --- src/wasm/response.rs | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/wasm/response.rs b/src/wasm/response.rs index f879669ac..f94e03d31 100644 --- a/src/wasm/response.rs +++ b/src/wasm/response.rs @@ -135,24 +135,30 @@ impl Response { /// Convert the response into a `Stream` of `Bytes` from the body. #[cfg(feature = "stream")] pub fn bytes_stream(self) -> impl futures_core::Stream> { + use futures_core::Stream; + use std::pin::Pin; + let web_response = self.http.into_body(); let abort = self._abort; - let body = web_response - .body() - .expect("could not create wasm byte stream"); - let body = wasm_streams::ReadableStream::from_raw(body.unchecked_into()); - Box::pin(body.into_stream().map(move |buf_js| { - // Keep the abort guard alive as long as this stream is. - let _abort = &abort; - let buffer = Uint8Array::new( - &buf_js - .map_err(crate::error::wasm) - .map_err(crate::error::decode)?, - ); - let mut bytes = vec![0; buffer.length() as usize]; - buffer.copy_to(&mut bytes); - Ok(bytes.into()) - })) + + if let Some(body) = web_response.body() { + let body = wasm_streams::ReadableStream::from_raw(body.unchecked_into()); + Box::pin(body.into_stream().map(move |buf_js| { + // Keep the abort guard alive as long as this stream is. + let _abort = &abort; + let buffer = Uint8Array::new( + &buf_js + .map_err(crate::error::wasm) + .map_err(crate::error::decode)?, + ); + let mut bytes = vec![0; buffer.length() as usize]; + buffer.copy_to(&mut bytes); + Ok(bytes.into()) + })) as Pin>>> + } else { + // If there's no body, return an empty stream. + Box::pin(stream::empty()) as Pin>>> + } } // util methods From 5d733dd14d3d0f58fe2f12e3c1a31049355b4bb5 Mon Sep 17 00:00:00 2001 From: Alon Gubkin Date: Tue, 8 Apr 2025 00:29:05 +0300 Subject: [PATCH 2/2] Fix import --- src/wasm/response.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wasm/response.rs b/src/wasm/response.rs index f94e03d31..52fad04ee 100644 --- a/src/wasm/response.rs +++ b/src/wasm/response.rs @@ -11,7 +11,7 @@ use crate::wasm::AbortGuard; use wasm_bindgen::JsCast; #[cfg(feature = "stream")] -use futures_util::stream::StreamExt; +use futures_util::stream::{self, StreamExt}; #[cfg(feature = "json")] use serde::de::DeserializeOwned;