1 use futures::join;
2 use test_programs::p3::wasi::http::client;
3 use test_programs::p3::wasi::http::types::{ErrorCode, Headers, Method, Request, Scheme, Trailers};
4 use test_programs::p3::{wit_future, wit_stream};
5 use wit_bindgen::{FutureReader, FutureWriter, StreamWriter};
6
7 struct Component;
8
9 test_programs::p3::export!(Component);
10
make_request() -> ( Request, StreamWriter<u8>, FutureWriter<Result<Option<Trailers>, ErrorCode>>, FutureReader<Result<(), ErrorCode>>, )11 fn make_request() -> (
12 Request,
13 StreamWriter<u8>,
14 FutureWriter<Result<Option<Trailers>, ErrorCode>>,
15 FutureReader<Result<(), ErrorCode>>,
16 ) {
17 let (contents_tx, contents_rx) = wit_stream::new();
18 let (trailers_tx, trailers_rx) = wit_future::new(|| todo!());
19 let (request, transmit) = Request::new(
20 Headers::from_list(&[("Content-Length".to_string(), b"11".to_vec())]).unwrap(),
21 Some(contents_rx),
22 trailers_rx,
23 None,
24 );
25
26 request.set_method(&Method::Post).expect("setting method");
27 request
28 .set_scheme(Some(&Scheme::Http))
29 .expect("setting scheme");
30 let addr = test_programs::p3::wasi::cli::environment::get_environment()
31 .into_iter()
32 .find_map(|(k, v)| k.eq("HTTP_SERVER").then_some(v))
33 .unwrap();
34 request
35 .set_authority(Some(&addr))
36 .expect("setting authority");
37 request
38 .set_path_with_query(Some("/"))
39 .expect("setting path with query");
40
41 (request, contents_tx, trailers_tx, transmit)
42 }
43
44 impl test_programs::p3::exports::wasi::cli::run::Guest for Component {
run() -> Result<(), ()>45 async fn run() -> Result<(), ()> {
46 println!("writing enough");
47 {
48 let (request, mut contents_tx, trailers_tx, transmit) = make_request();
49 let (handle, transmit, ()) = join!(
50 async { client::send(request).await },
51 async { transmit.await },
52 async {
53 let remaining = contents_tx.write_all(b"long enough".to_vec()).await;
54 assert_eq!(String::from_utf8_lossy(&remaining), "");
55 trailers_tx.write(Ok(None)).await.unwrap();
56 drop(contents_tx);
57 },
58 );
59 let _res = handle.expect("failed to send request");
60 transmit.expect("failed to transmit request");
61 }
62
63 println!("writing too little");
64 {
65 let (request, mut contents_tx, trailers_tx, transmit) = make_request();
66 let (handle, transmit, ()) = join!(
67 async { client::send(request).await },
68 async { transmit.await },
69 async {
70 let remaining = contents_tx.write_all(b"msg".to_vec()).await;
71 assert_eq!(String::from_utf8_lossy(&remaining), "");
72 trailers_tx.write(Ok(None)).await.unwrap();
73 drop(contents_tx);
74 },
75 );
76 // The request body will be polled before `handle` returns.
77 // Due to the way implementation is structured, by the time it happens
78 // the error will be already available in most cases and `handle` will fail,
79 // but it is a race condition, since `handle` may also succeed if
80 // polling body returns `Poll::Pending`
81 assert!(
82 matches!(handle, Ok(..) | Err(ErrorCode::HttpProtocolError)),
83 "unexpected handle result: {handle:#?}"
84 );
85 let err = transmit.expect_err("request transmission should have failed");
86 assert!(
87 matches!(err, ErrorCode::HttpRequestBodySize(Some(3))),
88 "unexpected error: {err:#?}"
89 );
90 }
91
92 println!("writing too much");
93 {
94 let (request, mut contents_tx, trailers_tx, transmit) = make_request();
95 let (handle, transmit, ()) = join!(
96 async { client::send(request).await },
97 async { transmit.await },
98 async {
99 let remaining = contents_tx.write_all(b"more than 11 bytes".to_vec()).await;
100 assert_eq!(String::from_utf8_lossy(&remaining), "more than 11 bytes");
101 _ = trailers_tx.write(Ok(None)).await;
102 },
103 );
104 // The request body will be polled before `handle` returns.
105 // Due to the way implementation is structured, by the time it happens
106 // the error will be already available in most cases and `handle` will fail,
107 // but it is a race condition, since `handle` may also succeed if
108 // polling body returns `Poll::Pending`
109 assert!(
110 matches!(
111 handle,
112 Ok(..) | Err(ErrorCode::HttpRequestBodySize(Some(18)))
113 ),
114 "unexpected handle result: {handle:#?}"
115 );
116 let err = transmit.expect_err("request transmission should have failed");
117 assert!(
118 matches!(err, ErrorCode::HttpRequestBodySize(Some(18))),
119 "unexpected error: {err:#?}"
120 );
121 }
122 Ok(())
123 }
124 }
125
main()126 fn main() {}
127