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