char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
f4a0f5b
main
1use std:: sync::{ 2Arc , 3 atomic::{ AtomicBool , Ordering }, 4}; 5 6use avril_http::{ Address , Engine }; 7use bytes:: Bytes ; 8use tokio:: io::{ AsyncReadExt , AsyncWriteExt }; 9 10# [ tokio :: test ] 11async fn engine_streams_without_a_js_runtime () { 12let engine =Arc :: new ( Engine :: new ( tokio:: runtime:: Handle :: current ())); 13let ( id, address) = engine 14. listen ( 15Address :: Tcp { 16hostname : "127.0.0.1" . into (), 17port : 0 , 18}, 19Arc :: new ( |_|Ok (())), 20) 21. unwrap (); 22let Address :: Tcp { hostname, port} = addresselse { 23panic! ( "expected TCP" ); 24}; 25let mut client = tokio:: net:: TcpStream :: connect (( hostname. as_str (), port)) 26. await 27. unwrap (); 28 client. write_all ( b"POST /stream HTTP/1.1\r\nHost: example.test\r\nContent-Length: 5\r\nConnection: close\r\n\r\nhello" ). await . unwrap (); 29let metadata = engine. next ( id). await . unwrap (). unwrap (); 30assert_eq! ( metadata. 1 , "POST" ); 31assert_eq! ( metadata. 2 , "http://example.test/stream" ); 32let request = metadata. 0 ; 33let completed = engine. wait ( request); 34let mut body =Vec :: new (); 35while let Some ( bytes) = engine. read ( request). await . unwrap () { 36 body. extend ( bytes); 37} 38assert_eq! ( body, b"hello" ); 39assert! ( engine. respond (( request, 200 , vec! [], None , true )). unwrap ()); 40assert! ( 41 engine 42. write ( request, Some ( Bytes :: from_static ( b"world" ))) 43. await 44. unwrap () 45); 46 engine. write ( request, None ). await . unwrap (); 47let mut response =String :: new (); 48 client. read_to_string ( & mut response). await . unwrap (); 49assert! ( response. starts_with ( "HTTP/1.1 200" )); 50assert! ( response. contains ( "world" )); 51assert! ( !completed. await . unwrap ()); 52 engine. stop ( id, false ); 53 engine. finished ( id). await . unwrap (); 54} 55 56# [ tokio :: test ] 57async fn native_file_ranges_preserve_keep_alive_framing () { 58use avril_http:: file::{ header_pairs, headers, serve_file}; 59 60let directory = tempfile:: tempdir (). unwrap (); 61let path = directory. path (). join ( "data.bin" ); 62let bytes: Vec < u8 > =( 0 ..200_000 ). map ( |i|( i %251 ) as u8 ). collect (); 63 std:: fs:: write ( & path, & bytes). unwrap (); 64let engine =Arc :: new ( Engine :: new ( tokio:: runtime:: Handle :: current ())); 65let ( id, address) = engine 66. listen ( 67Address :: Tcp { 68hostname : "127.0.0.1" . into (), 69port : 0 , 70}, 71Arc :: new ( |_|Ok (())), 72) 73. unwrap (); 74let Address :: Tcp { hostname, port} = addresselse { 75panic! ( "expected TCP" ); 76}; 77let mut client = tokio:: net:: TcpStream :: connect (( hostname. as_str (), port)) 78. await 79. unwrap (); 80 client. write_all ( b"GET /file HTTP/1.1\r\nHost: localhost\r\nRange: bytes=65530-131080\r\n\r\nGET /next HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n" ). await . unwrap (); 81let receive = tokio:: spawn ( async move { 82let mut bytes =Vec :: new (); 83 client. read_to_end ( & mut bytes). await . unwrap (); 84 bytes 85}); 86let request = engine. next ( id). await . unwrap (). unwrap (); 87let complete = engine. wait ( request. 0 ); 88let runtime = tokio:: runtime:: Handle :: current (); 89let response = tokio:: task:: spawn_blocking ( move ||{ 90serve_file ( 91 runtime, 92& request. 1 , 93headers ( request. 3 ). unwrap (), 94"data.bin" , 95headers ( vec! []). unwrap (), 96 ||Ok (( std:: fs:: File :: open ( & path) ?, Arc :: new ( ||Ok (())))), 97) 98}) 99. await 100. unwrap () 101. unwrap (); 102 engine 103. respond_file ( 104 request. 0 , 105 response. status (). as_u16 (), 106header_pairs ( response. headers ()), 107 response. into_body (). unwrap (), 108) 109. unwrap (); 110let next = engine. next ( id). await . unwrap (). unwrap (). 0 ; 111let next_complete = engine. wait ( next); 112 engine 113. respond (( next, 200 , vec! [], Some ( Bytes :: from_static ( b"next" )), false )) 114. unwrap (); 115let received = receive. await . unwrap (); 116let body_start = received 117. windows ( 4 ) 118. position ( |part| part ==b"\r\n\r\n" ) 119. unwrap () 120 +4 ; 121assert! ( received. starts_with ( b"HTTP/1.1 206" )); 122assert_eq! ( 123& received[ body_start..body_start +65551 ], 124& bytes[ 65530 ..=131080 ] 125); 126assert! ( received[ body_start +65551 ..]. starts_with ( b"HTTP/1.1 200" )); 127assert! ( received. ends_with ( b"next" )); 128assert! ( !complete. await . unwrap ()); 129assert! ( !next_complete. await . unwrap ()); 130 engine. stop ( id, false ); 131 engine. finished ( id). await . unwrap (); 132} 133 134# [ tokio :: test ] 135async fn authorization_denials_do_not_leak_pending_responses () { 136let engine =Arc :: new ( Engine :: new ( tokio:: runtime:: Handle :: current ())); 137let allowed =Arc :: new ( AtomicBool :: new ( true )); 138let flag = allowed. clone (); 139let authorize =Arc :: new ( move |_: & Address |{ 140if flag. load ( Ordering :: Relaxed ) { 141Ok (()) 142} else { 143Err ( "denied" . into ()) 144} 145}); 146let ( id, address) = engine 147. listen ( 148Address :: Tcp { 149hostname : "127.0.0.1" . into (), 150port : 0 , 151}, 152 authorize. clone (), 153) 154. unwrap (); 155let Address :: Tcp { hostname, port} = addresselse { 156panic! ( "expected TCP" ); 157}; 158let mut client = tokio:: net:: TcpStream :: connect (( hostname. as_str (), port)) 159. await 160. unwrap (); 161 client 162. write_all ( b"GET / HTTP/1.1\r\nHost: example.test\r\nConnection: close\r\n\r\n" ) 163. await 164. unwrap (); 165let request = engine. next ( id). await . unwrap (). unwrap (). 0 ; 166let completed = engine. wait ( request); 167 allowed. store ( false , Ordering :: Relaxed ); 168assert_eq! ( 169 engine 170. respond (( 171 request, 172200 , 173vec! [], 174Some ( Bytes :: from_static ( b"secret" )), 175false 176)) 177. unwrap_err () 178. to_string (), 179"denied" 180); 181assert! ( 182 engine 183. listen ( 184Address :: Tcp { 185hostname : "127.0.0.1" . into (), 186port : 0 187}, 188 authorize 189) 190. is_err () 191); 192 engine. cancel ( request); 193let mut response =Vec :: new (); 194 client. read_to_end ( & mut response). await . unwrap (); 195assert! ( response. is_empty ()); 196assert! ( completed. await . unwrap ()); 197 engine. stop ( id, false ); 198 engine. finished ( id). await . unwrap (); 199} 200 201# [ test ] 202# [ cfg ( unix )] 203fn failed_listener_setup_leaves_no_socket_entry () { 204let directory = tempfile:: tempdir (). unwrap (); 205let path = directory. path (). join ( "failed.sock" ); 206let runtime = tokio:: runtime:: Builder :: new_current_thread () 207. enable_all () 208. build () 209. unwrap (); 210let handle = runtime. handle (). clone (); 211drop ( runtime); 212let engine =Arc :: new ( Engine :: new ( handle)); 213assert! ( 214 engine 215. listen ( 216Address :: Unix { 217path : Some ( path. to_str (). unwrap (). into ()) 218}, 219Arc :: new ( |_|Ok (())) 220) 221. is_err () 222); 223assert! ( !path. exists ()); 224} 225 226# [ tokio :: test ] 227# [ cfg ( target_os = "linux" )] 228async fn unix_cleanup_follows_the_pinned_directory_after_rename () { 229let directory = tempfile:: tempdir (). unwrap (); 230let original = directory. path (). join ( "original" ); 231let moved = directory. path (). join ( "moved" ); 232 std:: fs:: create_dir ( & original). unwrap (); 233let path = original. join ( "server.sock" ); 234let engine =Arc :: new ( Engine :: new ( tokio:: runtime:: Handle :: current ())); 235let ( id, _) = engine 236. listen ( 237Address :: Unix { 238path : Some ( path. to_str (). unwrap (). into ()), 239}, 240Arc :: new ( |_|Ok (())), 241) 242. unwrap (); 243 std:: fs:: rename ( & original, & moved). unwrap (); 244 std:: fs:: create_dir ( & original). unwrap (); 245 std:: fs:: write ( & path, "replacement" ). unwrap (); 246 engine. stop ( id, false ); 247 engine. finished ( id). await . unwrap (); 248assert! ( !moved. join ( "server.sock" ). exists ()); 249assert_eq! ( std:: fs:: read_to_string ( path). unwrap (), "replacement" ); 250}