1 use futures::join; 2 use test_programs::p3::wasi::http::handler; 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 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 { 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 { handler::handle(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 { handler::handle(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 { handler::handle(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 126 fn main() {} 127