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