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