Skip to content

Commit 2ac71e4

Browse files
committed
Fix streaming request bodies
Signed-off-by: Ryan Levick <[email protected]>
1 parent 88d8bba commit 2ac71e4

File tree

4 files changed

+14
-8
lines changed

4 files changed

+14
-8
lines changed

examples/http-rust-outbound-http/outbound-http-to-same-app/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use spin_sdk::{
77
/// Send an HTTP request and return the response.
88
#[http_component]
99
async fn send_outbound(_req: Request) -> Result<impl IntoResponse> {
10-
let mut res: http::Response<()> = spin_sdk::http::send(
10+
let mut res: http::Response<String> = spin_sdk::http::send(
1111
http::Request::builder()
1212
.method("GET")
1313
.uri("/hello")

sdk/rust/readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ server, modifies the result, then returns it:
4141
```rust
4242
#[http_component]
4343
async fn hello_world(_req: Request) -> Result<Response> {
44-
let mut res: http::Response<()> = spin_sdk::http::send(
44+
let mut res: http::Response<String> = spin_sdk::http::send(
4545
http::Request::builder()
4646
.method("GET")
4747
.uri("https://fermyon.com")

sdk/rust/src/http.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,9 @@ impl ResponseOutparam {
535535
}
536536

537537
/// Send an outgoing request
538+
///
539+
/// If `request`` is an `OutgoingRequest` and you are streaming the body to the
540+
/// outgoing request body sink, you need to ensure it is dropped before awaiting this function.
538541
pub async fn send<I, O>(request: I) -> Result<O, SendError>
539542
where
540543
I: TryIntoOutgoingRequest,
@@ -544,18 +547,22 @@ where
544547
{
545548
let (request, body_buffer) = I::try_into_outgoing_request(request)
546549
.map_err(|e| SendError::RequestConversion(e.into()))?;
547-
if let Some(body_buffer) = body_buffer {
550+
let response = if let Some(body_buffer) = body_buffer {
548551
// It is part of the contract of the trait that implementors of `TryIntoOutgoingRequest`
549552
// do not call `OutgoingRequest::write`` if they return a buffered body.
550553
let mut body_sink = request.take_body();
554+
let response = executor::outgoing_request_send(request);
551555
body_sink
552556
.send(body_buffer)
553557
.await
554558
.map_err(|e| SendError::Http(Error::UnexpectedError(e.to_string())))?;
559+
// The body sink needs to be dropped before we await the response, otherwise we deadlock
560+
drop(body_sink);
561+
response.await
562+
} else {
563+
executor::outgoing_request_send(request).await
555564
}
556-
let response = executor::outgoing_request_send(request)
557-
.await
558-
.map_err(SendError::Http)?;
565+
.map_err(SendError::Http)?;
559566

560567
TryFromIncomingResponse::try_from_incoming_response(response)
561568
.await

sdk/rust/src/http/executor.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,8 @@ pub(crate) fn outgoing_body(body: OutgoingBody) -> impl Sink<Vec<u8>, Error = ty
143143
pub(crate) fn outgoing_request_send(
144144
request: OutgoingRequest,
145145
) -> impl Future<Output = Result<IncomingResponse, types::Error>> {
146+
let response = outgoing_handler::handle(request, None);
146147
future::poll_fn({
147-
let response = outgoing_handler::handle(request, None);
148-
149148
move |context| match &response {
150149
Ok(response) => {
151150
if let Some(response) = response.get() {

0 commit comments

Comments
 (0)