11use crate :: FieldMap ;
22use crate :: p3:: bindings:: http:: client:: { Host , HostWithStore } ;
33use crate :: p3:: bindings:: http:: types:: { Request , Response } ;
4- use crate :: p3:: body:: Body ;
4+ use crate :: p3:: body:: { Body , BodyExt as _ } ;
55use crate :: p3:: { HttpError , HttpResult } ;
66use crate :: { Error , WasiHttp , WasiHttpCtxView } ;
77use core:: task:: { Context , Poll , Waker } ;
8+ use http_body_util:: BodyExt as _;
9+ use std:: sync:: Arc ;
810use tokio:: sync:: oneshot;
911use tokio:: task:: { self , JoinHandle } ;
1012use tracing:: debug;
@@ -26,7 +28,7 @@ const DROPPED_FUTURE_ERROR: &str =
2628
2729async fn io_task_result (
2830 rx : oneshot:: Receiver < (
29- Option < AbortOnDropJoinHandle > ,
31+ Option < Arc < AbortOnDropJoinHandle > > ,
3032 oneshot:: Receiver < Result < ( ) , Error > > ,
3133 ) > ,
3234) -> Result < ( ) , Error > {
@@ -41,7 +43,7 @@ async fn io_task_result(
4143fn send_dummy_io (
4244 result : Result < ( ) , Error > ,
4345 io_result_tx : oneshot:: Sender < (
44- Option < AbortOnDropJoinHandle > ,
46+ Option < Arc < AbortOnDropJoinHandle > > ,
4547 oneshot:: Receiver < Result < ( ) , Error > > ,
4648 ) > ,
4749) {
@@ -54,7 +56,7 @@ fn send_dummy_io_err<T>(
5456 store : & Accessor < T , WasiHttp > ,
5557 e : Error ,
5658 io_result_tx : oneshot:: Sender < (
57- Option < AbortOnDropJoinHandle > ,
59+ Option < Arc < AbortOnDropJoinHandle > > ,
5860 oneshot:: Receiver < Result < ( ) , Error > > ,
5961 ) > ,
6062) -> HttpError {
@@ -68,6 +70,10 @@ impl<T> HostWithStore<T> for WasiHttp {
6870 store : & Accessor < T , Self > ,
6971 req : Resource < Request > ,
7072 ) -> HttpResult < Resource < Response > > {
73+ // A handle to the I/O task, if spawned, will be sent on this channel
74+ // and kept as part of request body state
75+ let ( io_task_tx, io_task_rx) = oneshot:: channel ( ) ;
76+
7177 // A handle to the I/O task, if spawned, will be sent on this channel
7278 // along with the result receiver
7379 let ( io_result_tx, io_result_rx) = oneshot:: channel ( ) ;
@@ -85,7 +91,9 @@ impl<T> HostWithStore<T> for WasiHttp {
8591 let ( req, options) =
8692 req. into_http_with_getter ( & mut store, io_task_result ( io_result_rx) , getter) ?;
8793 HttpResult :: Ok ( store. get ( ) . hooks . send_request (
88- req,
94+ // Attach a reference to the io task to the body so that it
95+ // isn't cancelled if the body is dropped.
96+ req. map ( |body| body. with_state ( io_task_rx) . boxed_unsync ( ) ) ,
8997 options. as_deref ( ) . copied ( ) ,
9098 Box :: new ( async {
9199 // Forward the response processing result to `WasiHttpCtx` implementation
@@ -134,13 +142,16 @@ impl<T> HostWithStore<T> for WasiHttp {
134142 Poll :: Pending => {
135143 // I/O driver still needs to be polled, spawn a task and send handles to it
136144 let ( tx, rx) = oneshot:: channel ( ) ;
137- let io = AbortOnDropJoinHandle ( task:: spawn ( async move {
145+ let io = Arc :: new ( AbortOnDropJoinHandle ( task:: spawn ( async move {
138146 let res = io. await ;
139147 debug ! ( ?res, "`send_request` I/O future finished" ) ;
140148 _ = tx. send ( res) ;
141- } ) ) ;
142- _ = io_result_tx. send ( ( Some ( io) , rx) ) ;
143- body
149+ } ) ) ) ;
150+ _ = io_result_tx. send ( ( Some ( Arc :: clone ( & io) ) , rx) ) ;
151+ _ = io_task_tx. send ( Arc :: clone ( & io) ) ;
152+ // Attach a reference to the io task to the body so that it
153+ // isn't cancelled if the body is dropped.
154+ body. with_state ( io) . boxed_unsync ( )
144155 }
145156 } ;
146157 store. with ( |mut store| {
0 commit comments