16f6a514bSRoman Volosatovs use futures::join;
2*1cc0bcffSBailey Hayes use test_programs::p3::wasi::http::client;
36f6a514bSRoman Volosatovs use test_programs::p3::wasi::http::types::{ErrorCode, Headers, Method, Request, Scheme, Trailers};
46f6a514bSRoman Volosatovs use test_programs::p3::{wit_future, wit_stream};
51047b511SAlex Crichton use wit_bindgen::{FutureReader, FutureWriter, StreamWriter};
66f6a514bSRoman Volosatovs 
76f6a514bSRoman Volosatovs struct Component;
86f6a514bSRoman Volosatovs 
96f6a514bSRoman Volosatovs test_programs::p3::export!(Component);
106f6a514bSRoman Volosatovs 
make_request() -> ( Request, StreamWriter<u8>, FutureWriter<Result<Option<Trailers>, ErrorCode>>, FutureReader<Result<(), ErrorCode>>, )116f6a514bSRoman Volosatovs fn make_request() -> (
126f6a514bSRoman Volosatovs     Request,
136f6a514bSRoman Volosatovs     StreamWriter<u8>,
146f6a514bSRoman Volosatovs     FutureWriter<Result<Option<Trailers>, ErrorCode>>,
156f6a514bSRoman Volosatovs     FutureReader<Result<(), ErrorCode>>,
166f6a514bSRoman Volosatovs ) {
176f6a514bSRoman Volosatovs     let (contents_tx, contents_rx) = wit_stream::new();
186f6a514bSRoman Volosatovs     let (trailers_tx, trailers_rx) = wit_future::new(|| todo!());
196f6a514bSRoman Volosatovs     let (request, transmit) = Request::new(
206f6a514bSRoman Volosatovs         Headers::from_list(&[("Content-Length".to_string(), b"11".to_vec())]).unwrap(),
216f6a514bSRoman Volosatovs         Some(contents_rx),
226f6a514bSRoman Volosatovs         trailers_rx,
236f6a514bSRoman Volosatovs         None,
246f6a514bSRoman Volosatovs     );
256f6a514bSRoman Volosatovs 
266f6a514bSRoman Volosatovs     request.set_method(&Method::Post).expect("setting method");
276f6a514bSRoman Volosatovs     request
286f6a514bSRoman Volosatovs         .set_scheme(Some(&Scheme::Http))
296f6a514bSRoman Volosatovs         .expect("setting scheme");
306f6a514bSRoman Volosatovs     let addr = test_programs::p3::wasi::cli::environment::get_environment()
316f6a514bSRoman Volosatovs         .into_iter()
326f6a514bSRoman Volosatovs         .find_map(|(k, v)| k.eq("HTTP_SERVER").then_some(v))
336f6a514bSRoman Volosatovs         .unwrap();
346f6a514bSRoman Volosatovs     request
356f6a514bSRoman Volosatovs         .set_authority(Some(&addr))
366f6a514bSRoman Volosatovs         .expect("setting authority");
376f6a514bSRoman Volosatovs     request
386f6a514bSRoman Volosatovs         .set_path_with_query(Some("/"))
396f6a514bSRoman Volosatovs         .expect("setting path with query");
406f6a514bSRoman Volosatovs 
416f6a514bSRoman Volosatovs     (request, contents_tx, trailers_tx, transmit)
426f6a514bSRoman Volosatovs }
436f6a514bSRoman Volosatovs 
446f6a514bSRoman Volosatovs impl test_programs::p3::exports::wasi::cli::run::Guest for Component {
run() -> Result<(), ()>456f6a514bSRoman Volosatovs     async fn run() -> Result<(), ()> {
465674e4b4SRoman Volosatovs         println!("writing enough");
476f6a514bSRoman Volosatovs         {
486f6a514bSRoman Volosatovs             let (request, mut contents_tx, trailers_tx, transmit) = make_request();
49f3d72564SRoman Volosatovs             let (handle, transmit, ()) = join!(
50*1cc0bcffSBailey Hayes                 async { client::send(request).await },
51f3d72564SRoman Volosatovs                 async { transmit.await },
525674e4b4SRoman Volosatovs                 async {
536f6a514bSRoman Volosatovs                     let remaining = contents_tx.write_all(b"long enough".to_vec()).await;
545a2860ceSRoman Volosatovs                     assert_eq!(String::from_utf8_lossy(&remaining), "");
555674e4b4SRoman Volosatovs                     trailers_tx.write(Ok(None)).await.unwrap();
566f6a514bSRoman Volosatovs                     drop(contents_tx);
575674e4b4SRoman Volosatovs                 },
585674e4b4SRoman Volosatovs             );
59f3d72564SRoman Volosatovs             let _res = handle.expect("failed to send request");
60f3d72564SRoman Volosatovs             transmit.expect("failed to transmit request");
616f6a514bSRoman Volosatovs         }
626f6a514bSRoman Volosatovs 
635674e4b4SRoman Volosatovs         println!("writing too little");
646f6a514bSRoman Volosatovs         {
656f6a514bSRoman Volosatovs             let (request, mut contents_tx, trailers_tx, transmit) = make_request();
665674e4b4SRoman Volosatovs             let (handle, transmit, ()) = join!(
67*1cc0bcffSBailey Hayes                 async { client::send(request).await },
685674e4b4SRoman Volosatovs                 async { transmit.await },
695674e4b4SRoman Volosatovs                 async {
706f6a514bSRoman Volosatovs                     let remaining = contents_tx.write_all(b"msg".to_vec()).await;
715a2860ceSRoman Volosatovs                     assert_eq!(String::from_utf8_lossy(&remaining), "");
725674e4b4SRoman Volosatovs                     trailers_tx.write(Ok(None)).await.unwrap();
735a2860ceSRoman Volosatovs                     drop(contents_tx);
745674e4b4SRoman Volosatovs                 },
755674e4b4SRoman Volosatovs             );
765a2860ceSRoman Volosatovs             // The request body will be polled before `handle` returns.
775a2860ceSRoman Volosatovs             // Due to the way implementation is structured, by the time it happens
785a2860ceSRoman Volosatovs             // the error will be already available in most cases and `handle` will fail,
795a2860ceSRoman Volosatovs             // but it is a race condition, since `handle` may also succeed if
805a2860ceSRoman Volosatovs             // polling body returns `Poll::Pending`
81f3d72564SRoman Volosatovs             assert!(
825a2860ceSRoman Volosatovs                 matches!(handle, Ok(..) | Err(ErrorCode::HttpProtocolError)),
835a2860ceSRoman Volosatovs                 "unexpected handle result: {handle:#?}"
84f3d72564SRoman Volosatovs             );
856f6a514bSRoman Volosatovs             let err = transmit.expect_err("request transmission should have failed");
866f6a514bSRoman Volosatovs             assert!(
876f6a514bSRoman Volosatovs                 matches!(err, ErrorCode::HttpRequestBodySize(Some(3))),
886f6a514bSRoman Volosatovs                 "unexpected error: {err:#?}"
896f6a514bSRoman Volosatovs             );
906f6a514bSRoman Volosatovs         }
916f6a514bSRoman Volosatovs 
925674e4b4SRoman Volosatovs         println!("writing too much");
936f6a514bSRoman Volosatovs         {
946f6a514bSRoman Volosatovs             let (request, mut contents_tx, trailers_tx, transmit) = make_request();
955674e4b4SRoman Volosatovs             let (handle, transmit, ()) = join!(
96*1cc0bcffSBailey Hayes                 async { client::send(request).await },
975674e4b4SRoman Volosatovs                 async { transmit.await },
985674e4b4SRoman Volosatovs                 async {
996f6a514bSRoman Volosatovs                     let remaining = contents_tx.write_all(b"more than 11 bytes".to_vec()).await;
1005a2860ceSRoman Volosatovs                     assert_eq!(String::from_utf8_lossy(&remaining), "more than 11 bytes");
1016f6a514bSRoman Volosatovs                     _ = trailers_tx.write(Ok(None)).await;
1025674e4b4SRoman Volosatovs                 },
1035674e4b4SRoman Volosatovs             );
1045a2860ceSRoman Volosatovs             // The request body will be polled before `handle` returns.
1055a2860ceSRoman Volosatovs             // Due to the way implementation is structured, by the time it happens
1065a2860ceSRoman Volosatovs             // the error will be already available in most cases and `handle` will fail,
1075a2860ceSRoman Volosatovs             // but it is a race condition, since `handle` may also succeed if
1085a2860ceSRoman Volosatovs             // polling body returns `Poll::Pending`
1095a2860ceSRoman Volosatovs             assert!(
1105a2860ceSRoman Volosatovs                 matches!(
1115a2860ceSRoman Volosatovs                     handle,
1125a2860ceSRoman Volosatovs                     Ok(..) | Err(ErrorCode::HttpRequestBodySize(Some(18)))
1135a2860ceSRoman Volosatovs                 ),
1145a2860ceSRoman Volosatovs                 "unexpected handle result: {handle:#?}"
1155a2860ceSRoman Volosatovs             );
1166f6a514bSRoman Volosatovs             let err = transmit.expect_err("request transmission should have failed");
1176f6a514bSRoman Volosatovs             assert!(
1186f6a514bSRoman Volosatovs                 matches!(err, ErrorCode::HttpRequestBodySize(Some(18))),
1196f6a514bSRoman Volosatovs                 "unexpected error: {err:#?}"
1206f6a514bSRoman Volosatovs             );
1216f6a514bSRoman Volosatovs         }
1226f6a514bSRoman Volosatovs         Ok(())
1236f6a514bSRoman Volosatovs     }
1246f6a514bSRoman Volosatovs }
1256f6a514bSRoman Volosatovs 
main()1266f6a514bSRoman Volosatovs fn main() {}
127