11use core:: future:: Future ;
22
33use bytes:: Bytes ;
4+ use http_body:: Body ;
5+ use http_body_util:: { BodyExt as _, Collected , Empty } ;
46use wasmtime:: component:: { Component , Linker , ResourceTable } ;
57use wasmtime:: Store ;
68use wasmtime_wasi:: p3:: cli:: { WasiCliCtx , WasiCliView } ;
@@ -11,13 +13,14 @@ use wasmtime_wasi::p3::sockets::{WasiSocketsCtx, WasiSocketsView};
1113use wasmtime_wasi:: p3:: ResourceView ;
1214use wasmtime_wasi:: { IoView , WasiCtx , WasiCtxBuilder , WasiView } ;
1315use wasmtime_wasi_http:: p3:: bindings:: http:: types:: ErrorCode ;
16+ use wasmtime_wasi_http:: p3:: bindings:: Proxy ;
1417use wasmtime_wasi_http:: p3:: {
1518 default_send_request, Client , RequestOptions , WasiHttpCtx , WasiHttpView ,
1619} ;
1720
1821use crate :: http_server:: Server ;
1922
20- mod tests ;
23+ mod outgoing ;
2124
2225struct Ctx < C : Client = TestClient > {
2326 cli : WasiCliCtx ,
@@ -103,7 +106,7 @@ impl<C: Client> WasiHttpView for Ctx<C> {
103106 & self . http
104107 }
105108
106- fn is_forbidden_header ( & mut self , name : & hyper :: header:: HeaderName ) -> bool {
109+ fn is_forbidden_header ( & mut self , name : & http :: header:: HeaderName ) -> bool {
107110 name. as_str ( ) == "custom-forbidden-header"
108111 }
109112}
@@ -148,104 +151,75 @@ impl Client for TestClient {
148151 }
149152}
150153
151- // TODO: Port below
154+ async fn run_wasi_http < E : Into < ErrorCode > + ' static > (
155+ component_filename : & str ,
156+ req : http:: Request < impl Body < Data = Bytes , Error = E > + Send + Sync + ' static > ,
157+ client : TestClient ,
158+ ) -> anyhow:: Result < Result < hyper:: Response < Collected < Bytes > > , ErrorCode > > {
159+ let engine = test_programs_artifacts:: engine ( |config| {
160+ config. wasm_backtrace_details ( wasmtime:: WasmBacktraceDetails :: Enable ) ;
161+ config. async_support ( true ) ;
162+ config. wasm_component_model_async ( true ) ;
163+ } ) ;
164+ let component = Component :: from_file ( & engine, component_filename) ?;
152165
153- //async fn run_wasi_http(
154- // component_filename: &str,
155- // req: hyper::Request<BoxBody<Bytes, hyper::Error>>,
156- // send_request: Option<RequestSender>,
157- // rejected_authority: Option<String>,
158- //) -> anyhow::Result<Result<hyper::Response<Collected<Bytes>>, ErrorCode>> {
159- // let stdout = MemoryOutputPipe::new(4096);
160- // let stderr = MemoryOutputPipe::new(4096);
161- // let table = ResourceTable::new();
162- //
163- // let mut config = Config::new();
164- // config.wasm_backtrace_details(wasmtime::WasmBacktraceDetails::Enable);
165- // config.wasm_component_model(true);
166- // config.async_support(true);
167- // let engine = Engine::new(&config)?;
168- // let component = Component::from_file(&engine, component_filename)?;
169- //
170- // // Create our wasi context.
171- // let mut builder = WasiCtxBuilder::new();
172- // builder.stdout(stdout.clone());
173- // builder.stderr(stderr.clone());
174- // let wasi = builder.build();
175- // let http = WasiHttpCtx::new();
176- // let ctx = Ctx {
177- // table,
178- // wasi,
179- // http,
180- // stderr,
181- // stdout,
182- // send_request,
183- // rejected_authority,
184- // };
185- // let mut store = Store::new(&engine, ctx);
186- //
187- // let mut linker = Linker::new(&engine);
188- // wasmtime_wasi_http::add_to_linker_async(&mut linker)?;
189- // let proxy =
190- // wasmtime_wasi_http::bindings::Proxy::instantiate_async(&mut store, &component, &linker)
191- // .await?;
192- //
193- // let req = store.data_mut().new_incoming_request(Scheme::Http, req)?;
194- //
195- // let (sender, receiver) = tokio::sync::oneshot::channel();
196- // let out = store.data_mut().new_response_outparam(sender)?;
197- //
198- // let handle = wasmtime_wasi::runtime::spawn(async move {
199- // proxy
200- // .wasi_http_incoming_handler()
201- // .call_handle(&mut store, req, out)
202- // .await?;
203- //
204- // Ok::<_, anyhow::Error>(())
205- // });
206- //
207- // let resp = match receiver.await {
208- // Ok(Ok(resp)) => {
209- // let (parts, body) = resp.into_parts();
210- // let collected = BodyExt::collect(body).await?;
211- // Some(Ok(hyper::Response::from_parts(parts, collected)))
212- // }
213- // Ok(Err(e)) => Some(Err(e)),
214- //
215- // // Fall through below to the `resp.expect(...)` which will hopefully
216- // // return a more specific error from `handle.await`.
217- // Err(_) => None,
218- // };
219- //
220- // // Now that the response has been processed, we can wait on the wasm to
221- // // finish without deadlocking.
222- // handle.await.context("Component execution")?;
223- //
224- // Ok(resp.expect("wasm never called set-response-outparam"))
225- //}
226- //
227- //#[test_log::test(tokio::test)]
228- //async fn wasi_http_proxy_tests() -> anyhow::Result<()> {
229- // let req = hyper::Request::builder()
230- // .header("custom-forbidden-header", "yes")
231- // .uri("http://example.com:8080/test-path")
232- // .method(http::Method::GET);
233- //
234- // let resp = run_wasi_http(
235- // test_programs_artifacts::API_PROXY_COMPONENT,
236- // req.body(body::empty())?,
237- // None,
238- // None,
239- // )
240- // .await?;
241- //
242- // match resp {
243- // Ok(resp) => println!("response: {resp:?}"),
244- // Err(e) => panic!("Error given in response: {e:?}"),
245- // };
246- //
247- // Ok(())
248- //}
166+ let mut store = Store :: new (
167+ & engine,
168+ Ctx {
169+ cli : WasiCliCtx {
170+ ..WasiCliCtx :: default ( )
171+ } ,
172+ http : WasiHttpCtx { client } ,
173+ ..Ctx :: default ( )
174+ } ,
175+ ) ;
176+
177+ let mut linker = Linker :: new ( & engine) ;
178+ wasmtime_wasi:: add_to_linker_async ( & mut linker) ?;
179+ wasmtime_wasi_http:: p3:: add_to_linker ( & mut linker) ?;
180+ let proxy = Proxy :: instantiate_async ( & mut store, & component, & linker) . await ?;
181+ match proxy. handle ( store, req) . await ? {
182+ Ok ( ( resp, fut) ) => {
183+ let ( parts, body) = resp. into_parts ( ) ;
184+ let body = body
185+ . collect ( )
186+ . await
187+ . map_err ( |err| err. expect ( "trailer future dropped" ) ) ?;
188+ if let Some ( fut) = fut {
189+ let _fut = fut. write ( Ok ( ( ) ) ) ;
190+ // TODO: Should we await the future, if so, how do we do that after having moved
191+ // the store?
192+ }
193+ Ok ( Ok ( http:: Response :: from_parts ( parts, body) ) )
194+ }
195+ Err ( err) => Ok ( Err ( err) ) ,
196+ }
197+ }
198+
199+ #[ test_log:: test( tokio:: test) ]
200+ async fn wasi_http_proxy_tests ( ) -> anyhow:: Result < ( ) > {
201+ let req = hyper:: Request :: builder ( )
202+ // TODO: remove forbidden headers?
203+ //.header("custom-forbidden-header", "yes")
204+ . uri ( "http://example.com:8080/test-path" )
205+ . method ( http:: Method :: GET ) ;
206+
207+ let resp = run_wasi_http (
208+ test_programs_artifacts:: API_0_3_PROXY_COMPONENT ,
209+ req. body ( Empty :: new ( ) ) ?,
210+ TestClient :: default ( ) ,
211+ )
212+ . await ?;
213+
214+ match resp {
215+ Ok ( resp) => println ! ( "response: {resp:?}" ) ,
216+ Err ( e) => panic ! ( "Error given in response: {e:?}" ) ,
217+ } ;
218+
219+ Ok ( ( ) )
220+ }
221+
222+ // TODO: Port below
249223//
250224//#[test_log::test(tokio::test)]
251225//async fn wasi_http_hash_all() -> Result<()> {
0 commit comments