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