Skip to content

Commit

Permalink
Fix streaming request bodies
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Levick <ryan.levick@fermyon.com>
  • Loading branch information
rylev committed Oct 28, 2023
1 parent 88d8bba commit 2ac71e4
Show file tree
Hide file tree
Showing 4 changed files with 14 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use spin_sdk::{
/// Send an HTTP request and return the response.
#[http_component]
async fn send_outbound(_req: Request) -> Result<impl IntoResponse> {
let mut res: http::Response<()> = spin_sdk::http::send(
let mut res: http::Response<String> = spin_sdk::http::send(
http::Request::builder()
.method("GET")
.uri("/hello")
Expand Down
2 changes: 1 addition & 1 deletion sdk/rust/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ server, modifies the result, then returns it:
```rust
#[http_component]
async fn hello_world(_req: Request) -> Result<Response> {
let mut res: http::Response<()> = spin_sdk::http::send(
let mut res: http::Response<String> = spin_sdk::http::send(
http::Request::builder()
.method("GET")
.uri("https://fermyon.com")
Expand Down
15 changes: 11 additions & 4 deletions sdk/rust/src/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,9 @@ impl ResponseOutparam {
}

/// Send an outgoing request
///
/// If `request`` is an `OutgoingRequest` and you are streaming the body to the
/// outgoing request body sink, you need to ensure it is dropped before awaiting this function.
pub async fn send<I, O>(request: I) -> Result<O, SendError>
where
I: TryIntoOutgoingRequest,
Expand All @@ -544,18 +547,22 @@ where
{
let (request, body_buffer) = I::try_into_outgoing_request(request)
.map_err(|e| SendError::RequestConversion(e.into()))?;
if let Some(body_buffer) = body_buffer {
let response = if let Some(body_buffer) = body_buffer {
// It is part of the contract of the trait that implementors of `TryIntoOutgoingRequest`
// do not call `OutgoingRequest::write`` if they return a buffered body.
let mut body_sink = request.take_body();
let response = executor::outgoing_request_send(request);
body_sink
.send(body_buffer)
.await
.map_err(|e| SendError::Http(Error::UnexpectedError(e.to_string())))?;
// The body sink needs to be dropped before we await the response, otherwise we deadlock
drop(body_sink);
response.await
} else {
executor::outgoing_request_send(request).await
}
let response = executor::outgoing_request_send(request)
.await
.map_err(SendError::Http)?;
.map_err(SendError::Http)?;

TryFromIncomingResponse::try_from_incoming_response(response)
.await
Expand Down
3 changes: 1 addition & 2 deletions sdk/rust/src/http/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,8 @@ pub(crate) fn outgoing_body(body: OutgoingBody) -> impl Sink<Vec<u8>, Error = ty
pub(crate) fn outgoing_request_send(
request: OutgoingRequest,
) -> impl Future<Output = Result<IncomingResponse, types::Error>> {
let response = outgoing_handler::handle(request, None);
future::poll_fn({
let response = outgoing_handler::handle(request, None);

move |context| match &response {
Ok(response) => {
if let Some(response) = response.get() {
Expand Down

0 comments on commit 2ac71e4

Please # to comment.